1 /* -*-c-*- ------------------ mix_eval_scanner.l : 2 * scanner used by mix_eval_t 3 * ------------------------------------------------------------------ 4 * Copyright (C) 2000, 2004, 2006, 2007, 2008, 2019 Free Software Foundation, Inc. 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 3 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 * 20 */ 21 22 %{ 23 #include <string.h> 24 #include "mix.h" 25 #include "xmix_eval.h" 26 27 #define YY_DECL \ 28 mix_eval_result_t mix_eval_expr (mix_eval_data_ *data) 29 30 /* keep track of current position in buffer */ 31 #define YY_USER_ACTION yypos += yyleng; 32 33 #define RETURN_STATE(err) \ 34 do { \ 35 done = TRUE; \ 36 state = err; \ 37 BEGIN (INITIAL); \ 38 } while (FALSE) 39 40 #define CLEAN_UP() \ 41 do { \ 42 yy_delete_buffer (buffer); \ 43 g_free (expr_cp); \ 44 } while (FALSE) 45 46 static mix_word_t eval_binop_ (const gchar *op, mix_word_t x, mix_word_t y); 47 static int unput_word_ (mix_word_t word); 48 49 %} 50 51 %option nomain 52 %option caseless 53 %option array 54 %option stack 55 %option noinput 56 %option noyywrap 57 %option noyy_top_state 58 %option outfile="lex.yy.c" 59 60 %s EVAL 61 %s WEVAL 62 63 ws [ \t]+ 64 digit [0-9] 65 letter [A-Z] 66 number [+-]?{digit}+ 67 mixchar [0-9A-Z .,'')(+*/=$<>@;:\-] 68 locsymbol {digit}H 69 flocsymbol {digit}F 70 blocsymbol {digit}B 71 symbol {digit}*{letter}+[A-Z0-9]* 72 binops "+"|"-"|"/"|"//"|":" 73 binop {binops}|"*" 74 atexpr {digit}+|{symbol}|\* 75 expr [+-]?{atexpr}({binop}{1}{atexpr})* 76 fpart \({expr}\) 77 wexpr {expr}({fpart})?(,{expr}({fpart})?)* 78 79 80 %% 81 82 %{ 83 YY_BUFFER_STATE buffer; 84 mix_word_t expr_val = MIX_WORD_ZERO, wexpr_val = MIX_WORD_ZERO; 85 mix_word_t wexpr_val_tmp = MIX_WORD_ZERO; 86 mix_eval_result_t state = MIX_EVAL_OK; 87 gchar *expr_cp; 88 gint yypos = -22; /* to account for padding */ 89 gboolean is_fp = FALSE, done = FALSE; 90 g_assert (data != NULL && data->expr != NULL); 91 /* make room enough to unput computed values */ 92 expr_cp = g_strdup_printf ("%-20s%s"," ", data->expr); 93 buffer = yy_scan_string (expr_cp); 94 data->errpos = -1; 95 %} 96 97 98 <*><<EOF>> { 99 CLEAN_UP (); 100 return MIX_EVAL_INTERN; 101 } 102 103 <INITIAL>{ 104 {ws} /* eat whitespace */ 105 . { 106 if (!done && state == MIX_EVAL_OK) { 107 yypos -= yyleng; yyless (0); 108 yy_push_state (WEVAL); 109 } else { 110 CLEAN_UP (); 111 if (state == MIX_EVAL_OK) return (MIX_EVAL_SYNTAX); 112 data->errpos = yypos; 113 return state; 114 } 115 } 116 "\n" { 117 CLEAN_UP(); 118 if (state == MIX_EVAL_OK) 119 data->value = wexpr_val; 120 else 121 data->errpos = yypos; 122 return state; 123 } 124 } 125 126 <WEVAL>{ 127 {number}"(" { 128 is_fp = TRUE; 129 wexpr_val_tmp = mix_word_new (atol (yytext)); 130 } 131 {number}")" { 132 glong val = atol (yytext); 133 if ( !is_fp ) { 134 RETURN_STATE (MIX_EVAL_MIS_PAREN); 135 } else if ( val < 0 || val > MIX_BYTE_MAX 136 || !mix_fspec_is_valid (mix_byte_new (val)) ) { 137 RETURN_STATE (MIX_EVAL_INV_FSPEC); 138 } else { 139 is_fp = FALSE; 140 wexpr_val = mix_word_store_field (mix_byte_new (val), 141 wexpr_val_tmp, 142 wexpr_val); 143 } 144 } 145 {number}/({ws}*\n)|[,()] { 146 wexpr_val = mix_word_new (atol (yytext)); 147 } 148 {expr}/({ws}*\n)|[,()] { 149 if (yytext[0] != '*') 150 { 151 yypos -= yyleng; 152 yyless (0); 153 } 154 else 155 { 156 yypos -= yyleng - 1; 157 expr_val = mix_short_to_word_fast (data->loc); 158 yyless (1); 159 } 160 yy_push_state (EVAL); 161 } 162 ,/{expr} /* eat comma if followed by expression */ 163 [\t\n ] { /* ok if not inside an f-part */ 164 if ( is_fp ) { 165 RETURN_STATE (MIX_EVAL_MIS_PAREN); 166 } 167 unput (yytext[yyleng-1]); --yypos; 168 done = TRUE; 169 yy_pop_state (); 170 } 171 . RETURN_STATE (MIX_EVAL_SYNTAX); 172 } 173 174 <EVAL>{ 175 {binop}{digit}+ { 176 const gchar *s = ( yytext[1] == '/' ) ? yytext+2 : yytext+1; 177 mix_word_t value = mix_word_new (atol (s)); 178 expr_val = eval_binop_ (yytext, expr_val, value); 179 } 180 {binop}{symbol} { 181 const gchar *s = ( yytext[1] == '/' ) ? yytext+2 : yytext+1; 182 if ( !mix_symbol_table_is_defined (data->table, s) ) { 183 RETURN_STATE (MIX_EVAL_UNDEF_SYM); 184 } 185 expr_val = eval_binop_ (yytext, expr_val, 186 mix_symbol_table_value (data->table, s)); 187 } 188 {binop}"*" { 189 expr_val = eval_binop_ (yytext, expr_val, 190 mix_short_to_word_fast (data->loc)); 191 } 192 "*" yypos -= unput_word_ (mix_short_to_word_fast (data->loc)); 193 {number} expr_val = mix_word_new (atol (yytext)); 194 {symbol} { 195 if ( !mix_symbol_table_is_defined (data->table, yytext) ) { 196 RETURN_STATE (MIX_EVAL_UNDEF_SYM); 197 } 198 expr_val = mix_symbol_table_value (data->table, yytext); 199 } 200 [,)(\n\t ] { 201 unput (yytext[0]); --yypos; 202 yypos -= unput_word_ (expr_val); 203 yy_pop_state (); 204 } 205 206 . RETURN_STATE (MIX_EVAL_SYNTAX); 207 } 208 209 210 %% 211 212 static mix_word_t 213 eval_binop_ (const gchar *op, mix_word_t x, mix_word_t y) 214 { 215 mix_word_t result = MIX_WORD_ZERO; 216 switch (op[0]) 217 { 218 case '+': 219 result = mix_word_add (x,y); 220 break; 221 case '-': 222 result = mix_word_sub (x,y); 223 break; 224 case '*': 225 mix_word_mul (x, y, NULL, &result); 226 break; 227 case ':': 228 { 229 mix_word_t a; 230 mix_word_mul (x, 8, NULL, &a); 231 result = mix_word_add (a, y); 232 break; 233 } 234 case '/': 235 if ( strlen (op) > 1 && op[1] == '/' ) { 236 mix_word_div (x,MIX_WORD_ZERO,y, &result, NULL); 237 } else { 238 mix_word_div (MIX_WORD_ZERO, x, y, &result, NULL); 239 } 240 break; 241 default: 242 g_assert_not_reached (); 243 } 244 return result; 245 } 246 247 static int 248 unput_word_ (mix_word_t word) 249 { 250 gchar *value; 251 gint k, result; 252 value = g_strdup_printf ("%s%ld", 253 mix_word_is_negative (word)? "-":"+", 254 mix_word_magnitude (word)); 255 result = strlen (value); 256 for (k = result - 1; k >= 0; --k) 257 unput (value[k]); 258 g_free (value); 259 return result; 260 } 261