/* -*-c-*- -------------- mix_scanner.l :
* Lexical scanner used by mix_parser_t
* ------------------------------------------------------------------
* Copyright (C) 2000, 2003, 2004 Free Software Foundation, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
%{
#include <ctype.h>
#include <string.h>
#include "mix.h"
#include "xmix_parser.h"
#define YY_DECL mix_parser_err_t mix_flex_scan (mix_parser_t *parser)
#define RESET() \
do { \
mix_ins_fill_from_id (ins, mix_NOP); \
ins.address = 0; \
ins.index = 0; \
nof = FALSE; \
lsf = FALSE; \
if (symbol != NULL ) \
{ \
g_free (symbol); \
symbol = NULL; \
} \
if (lsymbol != NULL) \
{ \
g_free (lsymbol); \
lsymbol = NULL; \
} \
} while (FALSE)
#define NEXT() \
do { \
if (lsymbol != NULL) \
mix_parser_manage_local_symbol (parser,lsymbol, \
loc); \
parser->loc_count++; \
RESET (); \
++lineno; \
BEGIN (INITIAL); \
} while (FALSE)
#define ADD_INS() \
do { \
mix_parser_add_ins (parser, &ins, lineno); \
NEXT (); \
} while (FALSE)
#define ADD_RAW(value,is_con) \
do { \
mix_parser_add_raw (parser, value, lineno, is_con); \
NEXT (); \
} while (FALSE)
#define ENTER_EVAL() \
do { \
if (yytext[0] != '*') \
{ \
expr_val = MIX_WORD_ZERO; \
yyless (0); \
} \
else \
{ \
expr_val = mix_short_to_word_fast (parser->loc_count); \
yyless (1); \
} \
yy_push_state (EVAL); \
} while (FALSE)
#define ENTER_WEVAL(s) \
do { \
wexpr_val = MIX_WORD_ZERO; \
wexpr_val_tmp = MIX_WORD_ZERO; \
is_fp = FALSE; \
yyless (s); \
yy_push_state (WEVAL); \
} while (FALSE)
#define RETURN_ERROR(error, comment) \
do { \
char c; \
mix_parser_log_error (parser,error,lineno,comment,FALSE); \
while ( (c = input ()) != '\n' && c != EOF ) ; \
if ( c == EOF ) return error; else ++lineno; \
RESET (); \
BEGIN (INITIAL); \
} while (FALSE)
static mix_word_t eval_binop_ (const gchar *op, mix_word_t x, mix_word_t y);
static void unput_word_ (mix_word_t word);
%}
%option nomain
%option caseless
%option array
%option stack
%option noyywrap
%option noyy_top_state
%option noreject
%option outfile="lex.yy.c"
%s LOC
%s OP
%s ADDRESS
%s INDEX
%s FSPEC
%s EVAL
%s WEVAL
%s ORIG
%s CON
%s EQU
%s END
ws [ \t]
digit [0-9]
letter [A-Z]
number [+-]?{digit}+
mixchar [0-9A-Z .,'')(+*/=$<>@;:\-]
locsymbol {digit}H
flocsymbol {digit}F
blocsymbol {digit}B
symbol {digit}*{letter}+[A-Z0-9]*
binop "+"|"-"|"*"|"/"|"//"|":"
atexpr {digit}+|{symbol}|\*
expr [+-]?{atexpr}({binop}{1}{atexpr})*
fpart \({expr}\)
wexpr {expr}({fpart})?(,{expr}({fpart})?)*
%%
%{
mix_ins_t ins;
gboolean nof = FALSE, is_fp = FALSE, end = FALSE, lsf = FALSE;
mix_word_t expr_val = MIX_WORD_ZERO, wexpr_val = MIX_WORD_ZERO,
wexpr_val_tmp = MIX_WORD_ZERO;
gchar *symbol = NULL, *lsymbol = NULL;
mix_address_t loc = MIX_SHORT_ZERO;
guint lineno = 1;
mix_ins_fill_from_id (ins, mix_NOP);
ins.address = 0;
ins.index = 0;
parser->err_line = 0;
#ifdef FLEX_DEBUG
yy_flex_debug = getenv("FLEX_DEBUG");
#endif
yyin = mix_file_to_FILE (parser->in_file);
%}
<*><<EOF>> {
mix_parser_log_error (parser, MIX_PERR_UNEX_EOF, lineno, NULL, FALSE);
return MIX_PERR_UNEX_EOF;
}
<INITIAL>{
^\*.* /* eat comments */
. {
if ( end ) return parser->status;
yyless (0);
BEGIN (LOC);
}
\n {
++lineno;
if ( end ) return parser->status;
}
}
<LOC>{
{ws}+ BEGIN (OP); /* LOC field is empty */
{locsymbol} { /* manage local symbol */
loc = get_ploc_ (parser);
lsymbol = g_strdup (yytext);
if ( lsymbol == NULL ) {
mix_parser_log_error (parser, MIX_PERR_INTERNAL, lineno, NULL, FALSE);
return MIX_PERR_INTERNAL;
}
BEGIN (OP);
}
{locsymbol}/({ws}+EQU) {/* local symbol with value */
loc = get_ploc_ (parser);
symbol = g_strdup (yytext);
lsymbol = g_strdup (yytext);
if ( symbol == NULL || lsymbol == NULL) {
mix_parser_log_error (parser, MIX_PERR_INTERNAL, lineno, NULL, FALSE);
return MIX_PERR_INTERNAL;
}
symbol[1] = 'B'; /* this will be referred as nB afterwards */
BEGIN (OP);
}
{flocsymbol}|{blocsymbol} RETURN_ERROR (MIX_PERR_UNEX_LOC, yytext);
{symbol}/({ws}+EQU) { /* store symbol name for future definition */
symbol = g_strdup (yytext);
if ( symbol == NULL ) {
mix_parser_log_error (parser, MIX_PERR_INTERNAL, lineno, NULL, FALSE);
return MIX_PERR_INTERNAL;
}
BEGIN (OP);
}
{symbol} { /* define a new symbol */
mix_parser_err_t err;
if ( mix_get_id_from_string (yytext) != mix_INVALID_INS )
mix_parser_log_error (parser, MIX_PERR_SYM_INS, lineno, yytext, TRUE);
if ( (err = mix_parser_define_symbol_here (parser,yytext)) != MIX_PERR_OK )
mix_parser_log_error (parser, err, lineno, yytext, FALSE);
BEGIN (OP);
}
. RETURN_ERROR (MIX_PERR_INV_LOC, yytext);
\n ++lineno; /* empty line */
}
<OP>{
{ws}+ /* eat leading whitespace */
\n RETURN_ERROR (MIX_PERR_NOOP, NULL);
ORIG{ws}+ BEGIN (ORIG);
CON{ws}+ BEGIN (CON);
EQU{ws}+ BEGIN (EQU);
END{ws}+ BEGIN (END);
ALF{ws}+\"{mixchar}{0,5}\"{ws}+.*\n |
ALF{ws}+\"{mixchar}{0,5}\"{ws}*\n {
mix_byte_t bytes[5];
mix_word_t value;
guint k, j = 4;
while ( yytext[j++] != '\"' ) ;
for ( k = j; k < 5+j && yytext[k] != '\"'; ++k )
bytes[k-j] = mix_ascii_to_char (yytext[k]);
if ( k-j < 5 )
{
mix_parser_log_error (parser, MIX_PERR_SHORT_ALF, lineno, NULL, TRUE);
/* Fill with spaces */
for (; k < 5+j; k++)
bytes[k-j] = mix_ascii_to_char (' ');
}
else if ( yytext[k] != '\"' )
mix_parser_log_error (parser, MIX_PERR_LONG_ALF, lineno, NULL, TRUE);
value = mix_bytes_to_word (bytes, 5);
ADD_RAW (value, FALSE);
}
ALF{ws}*\n {
mix_byte_t bytes[5];
memset (bytes, mix_ascii_to_char (' '), 5);
mix_word_t value = mix_bytes_to_word (bytes, 5);
ADD_RAW (value, FALSE);
}
ALF{ws}+({mixchar}{1,5}) {
mix_byte_t bytes[5];
mix_word_t value;
int i, n;
for (n = 3; n < yyleng; n++)
if (!isspace (yytext[n]))
break;
for (i = 0; i < 5 && n < yyleng; i++, n++)
bytes[i] = mix_ascii_to_char (yytext[n]);
for (; i < 5; i++)
bytes[i] = mix_ascii_to_char (' ');
value = mix_bytes_to_word (bytes, 5);
ADD_RAW (value, FALSE);
}
/* ALF " " */
[A-Z0-9]+{ws}*/\n |
[A-Z0-9]+{ws}+ {
mix_ins_id_t id = mix_get_id_from_string (g_strchomp (yytext));
if ( id == mix_INVALID_INS )
mix_parser_log_error (parser, MIX_PERR_INV_OP, lineno, yytext, FALSE);
else {
mix_ins_fill_from_id (ins, id);
nof = mix_ins_id_is_extended (id);
}
BEGIN (ADDRESS);
}
{expr} RETURN_ERROR (MIX_PERR_INV_OP, yytext);
. RETURN_ERROR (MIX_PERR_INV_OP, yytext);
}
<ORIG>{
{number}{ws}*\n |
{number}{ws}+.*\n {
mix_word_t value = mix_word_new (atol (yytext));
parser->loc_count = mix_word_to_short_fast (value);
++lineno;
BEGIN (INITIAL);
}
}
<CON>{
{number}{ws}*\n |
{number}{ws}+.*\n {
mix_word_t value = mix_word_new (atol (yytext));
ADD_RAW (value, TRUE);
}
}
<EQU>{
{number}{ws}*\n |
{number}{ws}+.*\n {
mix_word_t value;
gint def;
if ( symbol == NULL ) RETURN_ERROR (MIX_PERR_MIS_SYM, NULL);
value = mix_word_new (atol (yytext));
def = mix_parser_define_symbol_value (parser, symbol, value);
if ( def == MIX_SYM_DUP ) RETURN_ERROR (MIX_PERR_DUP_SYMBOL, symbol);
if ( def == MIX_SYM_LONG ) RETURN_ERROR (MIX_PERR_LONG_SYMBOL, symbol);
++lineno;
BEGIN (INITIAL);
}
}
<END>{
{number}{ws}*\n |
{number}{ws}+.*\n {
parser->start = mix_short_new (atol (yytext));
parser->end = parser->loc_count;
end = TRUE;
if ( parser->status == MIX_PERR_NOCOMP ) parser->status = MIX_PERR_OK;
return parser->status;
}
}
<ORIG,CON,EQU,END>{
{wexpr} ENTER_WEVAL (0);
. RETURN_ERROR (MIX_PERR_INV_OP, yytext);
}
<ADDRESS,INDEX,FSPEC>{locsymbol} RETURN_ERROR (MIX_PERR_UNEX_LOC, yytext);
<ADDRESS>{
=/[+-]?{number}= lsf = TRUE;
=/{expr}= lsf = TRUE;
={wexpr}= { lsf = TRUE; ENTER_WEVAL (1); }
[+-]?{number}={ws}*\n |
[+-]?{number}={ws}+.*\n {
if (!lsf) RETURN_ERROR (MIX_PERR_INV_ADDRESS, yytext);
mix_parser_define_ls (parser, mix_word_new (atol (yytext)));
lsf = FALSE;
ADD_INS ();
}
[+-]?{number}=[(,] {
int pos = yyleng - 3;
if (!lsf) RETURN_ERROR (MIX_PERR_INV_ADDRESS, yytext);
unput (yytext[yyleng - 1]);
while (pos >= 0) {
unput (yytext[pos]);
--pos;
}
}
[+-]?{number}{ws}+.*\n |
[+-]?{number}[(,\n] {
ins.address = mix_short_new (atol (yytext));
switch ( yytext[yyleng-1] ) {
case '(' : BEGIN (FSPEC); break;
case ',' : BEGIN (INDEX); break;
case '\n' : ADD_INS (); break;
default: g_assert_not_reached ();
}
}
([+-]?{symbol})/[(,\n\t ] {
gboolean neg = (yytext[0] == '-');
const gchar *s = (neg || yytext[0] == '+')? yytext+1 : yytext;
if ( !mix_symbol_table_is_defined (parser->symbol_table, s) )
{
mix_parser_set_future_ref (parser, s);
if (neg)
mix_parser_log_error (parser, MIX_PERR_UNDEF_SYM, lineno, s, TRUE);
unput (neg? '1':'0');
}
else
{
mix_word_t v = mix_symbol_table_value (parser->symbol_table, s);
if ( neg ) mix_word_reverse_sign (v);
unput_word_ (v);
}
}
{expr}/[(,=\n\t ] ENTER_EVAL ();
\n ADD_INS ();
. RETURN_ERROR (MIX_PERR_INV_ADDRESS, yytext);
}
<INDEX>{
{number}[\n(\t ] {
int end = yytext[yyleng-1];
ins.index = mix_byte_new (atol (yytext));
if ( end == '\n' )
ADD_INS ();
else if ( end == '(' )
BEGIN (FSPEC);
else
{ /* eat rest of line (comment) */
while ( (end = input()) != '\n' && end != EOF ) ;
if ( end == '\n' ) ADD_INS ();
else RETURN_ERROR (MIX_PERR_UNEX_EOF, NULL);
}
}
{expr}/[\n(\t ] ENTER_EVAL ();
\n {
mix_parser_log_error (parser, MIX_PERR_INV_IDX, lineno++, NULL, FALSE);
RESET ();
BEGIN (INITIAL);
}
. RETURN_ERROR (MIX_PERR_INV_IDX, yytext);
}
<FSPEC>{
{number}")"(({ws}+.*\n)|\n) {
glong val = atol (yytext);
if ( val < 0 || val > MIX_BYTE_MAX )
RETURN_ERROR (MIX_PERR_INV_FSPEC, NULL);
if ( ins.opcode != mix_opMOVE
&& ( ins.opcode < mix_opJBUS || ins.opcode > mix_opJXx )
&& !mix_fspec_is_valid (mix_byte_new (val)) )
RETURN_ERROR (MIX_PERR_INV_FSPEC, NULL);
if ( nof )
mix_parser_log_error (parser, MIX_PERR_INV_FSPEC,
lineno, _("ignored"), TRUE);
else
{
ins.fspec = mix_byte_new (val);
if (lsf)
{
mix_parser_define_ls (parser,
mix_short_to_word_fast (ins.address));
ins.address = MIX_WORD_ZERO;
lsf = FALSE;
}
ADD_INS ();
}
}
{expr}/")" {
ENTER_EVAL ();
}
. RETURN_ERROR (MIX_PERR_INV_FSPEC, yytext);
}
<EVAL>{
{binop}{digit}+ {
const gchar *s = ( yytext[1] == '/' ) ? yytext+2 : yytext+1;
mix_word_t value = mix_word_new (atol (s));
expr_val = eval_binop_ (yytext, expr_val, value);
}
{binop}{symbol} {
const gchar *s = ( yytext[1] == '/' ) ? yytext+2 : yytext+1;
if ( !mix_symbol_table_is_defined (parser->symbol_table, s) ) {
mix_parser_log_error (parser, MIX_PERR_UNDEF_SYM, lineno, s, FALSE);
yy_pop_state ();
}
expr_val = eval_binop_ (yytext, expr_val,
mix_symbol_table_value (parser->symbol_table, s));
}
{binop}"*" {
expr_val = eval_binop_ (yytext, expr_val,
mix_short_to_word_fast (parser->loc_count));
}
"*" unput_word_ (mix_short_to_word_fast (parser->loc_count));
{number} expr_val = mix_word_new (atol (yytext));
{symbol} {
if ( !mix_symbol_table_is_defined (parser->symbol_table, yytext) ) {
mix_parser_log_error (parser, MIX_PERR_UNDEF_SYM, lineno, yytext, FALSE);
yy_pop_state ();
}
expr_val = mix_symbol_table_value (parser->symbol_table, yytext);
}
[,)(=\n\t ] unput (yytext[0]); unput_word_ (expr_val); yy_pop_state ();
. RETURN_ERROR (MIX_PERR_INV_EXPR, yytext);
}
<WEVAL>{
{number}"(" {
is_fp = TRUE;
wexpr_val_tmp = mix_word_new (atol (yytext));
}
{number}")" {
glong val = atol (yytext);
if ( !is_fp ) {
mix_parser_log_error (parser, MIX_PERR_MIS_PAREN, lineno, NULL, FALSE);
yy_pop_state ();
}
if ( val < 0 || val > MIX_BYTE_MAX
|| !mix_fspec_is_valid (mix_byte_new (val)) ) {
mix_parser_log_error (parser, MIX_PERR_INV_FSPEC, lineno, NULL, FALSE);
yy_pop_state ();
}
is_fp = FALSE;
wexpr_val = mix_word_store_field (mix_byte_new (val), wexpr_val_tmp,
wexpr_val);
}
{number}/[,()\n\t ] wexpr_val = mix_word_new (atol (yytext));
{expr}/[,()\n\t ] ENTER_EVAL ();
,/{expr} /* eat comma if followed by expression */
[=\n\t ] { /* ok if not inside an f-part */
if ( is_fp ) {
mix_parser_log_error (parser, MIX_PERR_MIS_PAREN, lineno, NULL, FALSE);
yy_pop_state ();
}
unput (yytext[yyleng-1]);
unput_word_ (wexpr_val);
yy_pop_state ();
}
. RETURN_ERROR (MIX_PERR_INV_EXPR, NULL);
}
%%
static mix_word_t
eval_binop_ (const gchar *op, mix_word_t x, mix_word_t y)
{
mix_word_t result = MIX_WORD_ZERO;
switch (op[0])
{
case '+':
result = mix_word_add (x,y);
break;
case '-':
result = mix_word_sub (x,y);
break;
case '*':
mix_word_mul (x, y, NULL, &result);
break;
case ':':
{
mix_word_t a;
mix_word_mul (x, 8, NULL, &a);
result = mix_word_add (a, y);
break;
}
case '/':
if ( strlen (op) > 1 && op[1] == '/' ) {
mix_word_div (x,MIX_WORD_ZERO,y, &result, NULL);
} else {
mix_word_div (MIX_WORD_ZERO, x, y, &result, NULL);
}
break;
default:
g_assert_not_reached ();
}
return result;
}
static void
unput_word_ (mix_word_t word)
{
gchar *value;
gint k;
value = g_strdup_printf ("%s%ld",
mix_word_is_negative (word)? "-":"+",
mix_word_magnitude (word));
for (k = strlen (value) - 1; k >= 0; --k)
unput (value[k]);
g_free (value);
}
syntax highlighted by Code2HTML, v. 0.9.1