/* -*-c-*- -------------- mix_scanner.l : * Lexical scanner used by mix_parser_t * ------------------------------------------------------------------ * Copyright (C) 2000 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ %{ #include #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) \ do { \ mix_parser_add_raw (parser, value, lineno); \ 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() \ do { \ wexpr_val = MIX_WORD_ZERO; \ wexpr_val_tmp = MIX_WORD_ZERO; \ is_fp = FALSE; \ yyless (0); \ 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 pointer %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; yyin = mix_file_to_FILE (parser->in_file); %} <*><> { mix_parser_log_error (parser, MIX_PERR_UNEX_EOF, lineno, NULL, FALSE); return MIX_PERR_UNEX_EOF; } { ^\*.* /* eat comments */ . { if ( end ) return parser->status; yyless (0); BEGIN (LOC); } \n { ++lineno; if ( end ) return parser->status; } } { {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 */ } { {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}{5,}\"{ws}+.*\n | ALF{ws}+\"{mixchar}{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); 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); } [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); } { {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); } } { {number}{ws}*\n | {number}{ws}+.*\n { mix_word_t value = mix_word_new (atol (yytext)); ADD_RAW (value); } } { {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); } } { {number}{ws}*\n | {number}{ws}+.*\n { parser->start = mix_short_new (atol (yytext)); end = TRUE; if ( parser->status == MIX_PERR_NOCOMP ) parser->status = MIX_PERR_OK; return parser->status; } } { {wexpr} ENTER_WEVAL (); . RETURN_ERROR (MIX_PERR_INV_OP, yytext); } {locsymbol} RETURN_ERROR (MIX_PERR_UNEX_LOC, yytext);
{ =/[+-]?{number}= lsf = TRUE; =/{expr}= lsf = TRUE; [+-]?{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))); ADD_INS (); } [+-]?{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); } { {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); } { {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); ADD_INS (); } } {expr}/")" { ENTER_EVAL (); } . RETURN_ERROR (MIX_PERR_INV_FSPEC, yytext); } { {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); } { {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); }