/* Copyright (C) 1998 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */ %{ #include #include #include #ifndef TEST #include "ed.h" #include #endif #define YYSTYPE long int valid_addr(word32 addr, int len); #ifdef TEST unsigned long syms_name2val (char *); int main (int, char **); int undefined_symbol = 0; #define valid_addr(x,y) 0 #define read_child (void) #endif int evaluate (char *, long *, char **); static int yylex (); static void yyerror (char *); static long result; static char *input; static char *error; %} %token NUM %left OP_LOR '|' '^' %left OP_LAND '&' %nonassoc OP_EQ '<' '>' OP_NE OP_LE OP_GE %left OP_SHL OP_SHR %left '+' '-' %left '*' '/' '%' %left ':' %left OP_NEG OP_LNOT OP_NOT %start main %% main : expr { result = $1; } expr : NUM { $$ = $1; } | expr OP_LOR expr { $$ = $1 || $3; } | expr OP_LAND expr { $$ = $1 && $3; } | expr '|' expr { $$ = $1 | $3; } | expr '&' expr { $$ = $1 & $3; } | expr '^' expr { $$ = $1 ^ $3; } | expr OP_EQ expr { $$ = $1 == $3; } | expr '>' expr { $$ = $1 > $3; } | expr '<' expr { $$ = $1 < $3; } | expr OP_GE expr { $$ = $1 >= $3; } | expr OP_LE expr { $$ = $1 <= $3; } | expr OP_NE expr { $$ = $1 != $3; } | expr OP_SHL expr { $$ = (unsigned)$1 << $3; } | expr OP_SHR expr { $$ = (unsigned)$1 >> $3; } | expr '+' expr { $$ = $1 + $3; } | expr '-' expr { $$ = $1 - $3; } | expr '*' expr { $$ = $1 * $3; } | expr '/' expr { if ($3) $$ = $1 / $3; else yyerror ("Division by zero"); } | expr '%' expr { if ($3) $$ = $1 % $3; else yyerror ("Division by zero"); } | '-' expr %prec OP_NEG { $$ = -$2; } | '!' expr %prec OP_LNOT { $$ = !$2; } | '~' expr %prec OP_NOT { $$ = ~$2; } | '(' expr ')' { $$ = $2; } | '[' expr ']' { if (valid_addr ($2, 4)) { long l; read_child ($2, &l, 4); $$ = l; } else yyerror ("Error reading child"); } | expr ':' NUM { switch ($3) { case 1: $$ = ($1 & 0xff); break; case 2: $$ = ($1 & 0xffff); break; case 4: $$ = ($1 & 0xffffffff); break; default: yyerror ("Invalid resizing"); }} ; %% static int yylex () { char *p, save; int i; static struct { char c1, c2; int token; } twochars[] = { { '=', '=', OP_EQ }, { '>', '=', OP_GE }, { '<', '=', OP_LE }, { '!', '=', OP_NE }, { '&', '&', OP_LAND}, { '|', '|', OP_LOR }, { '<', '<', OP_SHL}, { '>', '>', OP_SHR}}; while (isspace (*input)) input++; switch (*input) { case '0' ... '9': case 'a' ... 'z': case 'A' ... 'Z': case '%': case '_': case '#': case '.': p = input++; while (isalnum (*input) || *input == '_' || *input == '#' || *input == '.') input++; save = *input; *input = 0; yylval = (long) syms_name2val (p); if (undefined_symbol) { static char buf[80]; sprintf (buf, "Undefined symbol `%s'", p); yyerror (buf); } *input = save; return NUM; case '\'': if (input[1] == '\\' && input[2] && input[3] == '\'') { static char escaped[] = "e\et\tb\bn\nr\r\\\\''"; for (i = 0; escaped[i]; i += 2) if (input[2] == escaped[i]) { input += 4; yylval = escaped[i + 1]; return NUM; } yyerror ("Unrecognized escaped character"); } else if (input[1] && input[2] == '\'') { yylval = input[1]; input += 3; } else yyerror ("Unterminated character constant"); return NUM; case 0: return 0; default: for (i = 0; i < sizeof (twochars) / sizeof (twochars[0]); i++) if (*input == twochars[i].c1 && input[1] == twochars[i].c2) { input += 2; return twochars[i].token; } return *input++; } } int evaluate (char *exp, long *res, char **errtxt) { int err; input = exp; error = 0; err = yyparse (); *res = result; *errtxt = error; undefined_symbol = 0; return err || error; } static void yyerror (char *s) { if (!error) error = s; } #ifdef TEST unsigned long syms_name2val (char *p) { return strtoul(p, 0, 0); } int main (int argc, char **argv) { long res; int i, err; char *errtxt; for (i = 1; i < argc; i++) { err = evaluate (argv[i], &res, &errtxt); if (err) printf ("`%s' -> %s\n", argv[i], errtxt); else printf ("`%s' -> %ld\n", argv[i], res); } return 0; } #endif