/* -*-c-*- ------------------ mix_eval_scanner.l :
* scanner used by mix_eval_t
* ------------------------------------------------------------------
* $Id: mix_eval_scanner.l,v 1.4 2005/09/20 19:43:13 jao Exp $
* ------------------------------------------------------------------
* Copyright (C) 2000, 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 <string.h>
#include "mix.h"
#include "xmix_eval.h"
#define YY_DECL \
mix_eval_result_t mix_eval_expr (mix_eval_data_ *data)
/* keep track of current position in buffer */
#define YY_USER_ACTION yypos += yyleng;
#define RETURN_STATE(err) \
do { \
done = TRUE; \
state = err; \
BEGIN (INITIAL); \
} while (FALSE)
#define CLEAN_UP() \
do { \
yy_delete_buffer (buffer); \
g_free (expr_cp); \
} while (FALSE)
static mix_word_t eval_binop_ (const gchar *op, mix_word_t x, mix_word_t y);
static int unput_word_ (mix_word_t word);
/* { */
/* gchar *value; */
/* gint k, result; */
/* value = g_strdup_printf ("%s%ld", */
/* mix_word_is_negative (word)? "-":"+", */
/* mix_word_magnitude (word)); */
/* result = strlen (value); */
/* for (k = result - 1; k >= 0; --k) */
/* unput (value[k]); */
/* g_free (value); */
/* return result; */
/* } */
%}
%option nomain
%option caseless
%option array
%option stack
%option noyywrap
%option noyy_top_state
%option noreject
%option outfile="lex.yy.c"
%s EVAL
%s WEVAL
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]*
binops "+"|"-"|"/"|"//"|":"
binop {binops}|"*"
atexpr {digit}+|{symbol}|\*
expr [+-]?{atexpr}({binop}{1}{atexpr})*
fpart \({expr}\)
wexpr {expr}({fpart})?(,{expr}({fpart})?)*
%%
%{
YY_BUFFER_STATE buffer;
mix_word_t expr_val = MIX_WORD_ZERO, wexpr_val = MIX_WORD_ZERO;
mix_word_t wexpr_val_tmp = MIX_WORD_ZERO;
mix_eval_result_t state = MIX_EVAL_OK;
gchar *expr_cp;
gint yypos = -22; /* to account for padding */
gboolean is_fp = FALSE, done = FALSE;
g_assert (data != NULL && data->expr != NULL);
/* make room enough to unput computed values */
expr_cp = g_strdup_printf ("%-20s%s"," ", data->expr);
buffer = yy_scan_string (expr_cp);
data->errpos = -1;
%}
<*><<EOF>> {
CLEAN_UP ();
return MIX_EVAL_INTERN;
}
<INITIAL>{
{ws} /* eat whitespace */
. {
if (!done && state == MIX_EVAL_OK) {
yypos -= yyleng; yyless (0);
yy_push_state (WEVAL);
} else {
CLEAN_UP ();
if (state == MIX_EVAL_OK) return (MIX_EVAL_SYNTAX);
data->errpos = yypos;
return state;
}
}
"\n" {
CLEAN_UP();
if (state == MIX_EVAL_OK)
data->value = wexpr_val;
else
data->errpos = yypos;
return state;
}
}
<WEVAL>{
{number}"(" {
is_fp = TRUE;
wexpr_val_tmp = mix_word_new (atol (yytext));
}
{number}")" {
glong val = atol (yytext);
if ( !is_fp ) {
RETURN_STATE (MIX_EVAL_MIS_PAREN);
} else if ( val < 0 || val > MIX_BYTE_MAX
|| !mix_fspec_is_valid (mix_byte_new (val)) ) {
RETURN_STATE (MIX_EVAL_INV_FSPEC);
} else {
is_fp = FALSE;
wexpr_val = mix_word_store_field (mix_byte_new (val),
wexpr_val_tmp,
wexpr_val);
}
}
{number}/({ws}*\n)|[,()] {
wexpr_val = mix_word_new (atol (yytext));
}
{expr}/({ws}*\n)|[,()] {
if (yytext[0] != '*')
{
yypos -= yyleng;
yyless (0);
}
else
{
yypos -= yyleng - 1;
expr_val = mix_short_to_word_fast (data->loc);
yyless (1);
}
yy_push_state (EVAL);
}
,/{expr} /* eat comma if followed by expression */
[\t\n ] { /* ok if not inside an f-part */
if ( is_fp ) {
RETURN_STATE (MIX_EVAL_MIS_PAREN);
}
unput (yytext[yyleng-1]); --yypos;
done = TRUE;
yy_pop_state ();
}
. RETURN_STATE (MIX_EVAL_SYNTAX);
}
<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 (data->table, s) ) {
RETURN_STATE (MIX_EVAL_UNDEF_SYM);
}
expr_val = eval_binop_ (yytext, expr_val,
mix_symbol_table_value (data->table, s));
}
{binop}"*" {
expr_val = eval_binop_ (yytext, expr_val,
mix_short_to_word_fast (data->loc));
}
"*" yypos -= unput_word_ (mix_short_to_word_fast (data->loc));
{number} expr_val = mix_word_new (atol (yytext));
{symbol} {
if ( !mix_symbol_table_is_defined (data->table, yytext) ) {
RETURN_STATE (MIX_EVAL_UNDEF_SYM);
}
expr_val = mix_symbol_table_value (data->table, yytext);
}
[,)(\n\t ] {
unput (yytext[0]); --yypos;
yypos -= unput_word_ (expr_val);
yy_pop_state ();
}
. RETURN_STATE (MIX_EVAL_SYNTAX);
}
%%
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 int
unput_word_ (mix_word_t word)
{
gchar *value;
gint k, result;
value = g_strdup_printf ("%s%ld",
mix_word_is_negative (word)? "-":"+",
mix_word_magnitude (word));
result = strlen (value);
for (k = result - 1; k >= 0; --k)
unput (value[k]);
g_free (value);
return result;
}
syntax highlighted by Code2HTML, v. 0.9.1