%{ #include #include #include #include #include #include "mapcalc.h" #define YYDEBUG 1 #define YYERROR_VERBOSE 1 static int syntax_error_occurred; %} %union { int ival; double fval; char *sval; expression *exp; expr_list *list; } %token VARNAME %token NAME %token VARSTRING %token STRING %token INTEGER %token FLOAT %token DOUBLE %token GT GE LT LE EQ NE LOGAND LOGOR LOGAND2 LOGOR2 BITAND BITOR LSH RSH RSHU %type exp %type exp_atom %type exp_pre %type exp_pow %type exp_mul %type exp_add %type exp_sh %type exp_cmp %type exp_eq %type exp_bitand %type exp_bitor %type exp_logand %type exp_logor %type exp_cond %type exp_let %type atom_var %type atom_map %type atom_func %type def %type mapmod %type index %type name %type map %type expr_list %type defs %type program %{ static expr_list *result; extern int yylex(void); int yyparse(void); void yyerror(char *s); %} %% program : defs { $$ = result = $1; } ; defs : def { $$ = list($1,NULL); } | def ';' { $$ = list($1,NULL); } | def ';' defs { $$ = list($1,$3); } | error ';' defs { $$ = $3; } ; def : STRING '=' exp { $$ = binding($1,$3); define_variable($$); } | NAME '=' exp { $$ = binding($1,$3); define_variable($$); } ; map : STRING | NAME | name '@' name { $$ = composite($1,$3); } ; mapmod : '@' { $$ = '@'; } | 'r' { $$ = 'r'; } | 'g' { $$ = 'g'; } | 'b' { $$ = 'b'; } | '#' { $$ = '#'; } | 'y' { $$ = 'y'; } | 'i' { $$ = 'i'; } ; index : INTEGER | '-' INTEGER { $$ = -$2; } ; expr_list : exp { $$ = singleton($1); } | exp ',' expr_list { $$ = list($1, $3); } ; atom_var : VARSTRING { $$ = variable($1); } | VARNAME { $$ = variable($1); } ; atom_map : map '[' index ']' { $$ = mapname($1,'M',$3,0,0); } | map '[' index ',' index ']' { $$ = mapname($1,'M',$3,$5,0); } | map '[' index ',' index ',' index ']' { $$ = mapname($1,'M',$3,$5,$7);} | map { $$ = mapname($1,'M',0,0,0); } | mapmod map '[' index ']' { $$ = mapname($2,$1,$4,0,0); } | mapmod map '[' index ',' index ']' { $$ = mapname($2,$1,$4,$6,0); } | mapmod map '[' index ',' index ',' index ']' { $$ = mapname($2,$1,$4,$6,$8); } | mapmod map { $$ = mapname($2,$1,0,0,0); } ; atom_func : name '(' ')' { $$ = function($1, NULL); } | name '(' expr_list ')' { $$ = function($1, $3); } ; exp_atom : '(' exp ')' { $$ = $2; } | atom_var | atom_map | atom_func | INTEGER { $$ = constant_int($1); } | FLOAT { $$ = constant_float($1); } | DOUBLE { $$ = constant_double($1); } ; exp_pre : exp_atom | '-' exp_atom { $$ = operator("neg","-",1,singleton($2)); } | '~' exp_atom { $$ = operator("bitnot","~",1,singleton($2)); } | '!' exp_atom { $$ = operator("not","!",1,singleton($2)); } ; exp_pow : exp_pre | exp_pre '^' exp_pow { $$ = operator("pow","^",2,pair($1,$3)); } ; exp_mul : exp_pow | exp_mul '*' exp_pow { $$ = operator("mul","*",3,pair($1,$3)); } | exp_mul '/' exp_pow { $$ = operator("div","/",3,pair($1,$3)); } | exp_mul '%' exp_pow { $$ = operator("mod","%",3,pair($1,$3)); } ; exp_add : exp_mul | exp_add '+' exp_mul { $$ = operator("add","+",4,pair($1,$3)); } | exp_add '-' exp_mul { $$ = operator("sub","-",4,pair($1,$3)); } ; exp_sh : exp_add | exp_sh LSH exp_add { $$ = operator("shiftl","<<",5,pair($1,$3)); } | exp_sh RSH exp_add { $$ = operator("shiftr",">>",5,pair($1,$3)); } | exp_sh RSHU exp_add { $$ = operator("shiftru",">>>",5,pair($1,$3)); } ; exp_cmp : exp_sh | exp_cmp GT exp_sh { $$ = operator("gt",">", 6,pair($1,$3)); } | exp_cmp GE exp_sh { $$ = operator("ge",">=",6,pair($1,$3)); } | exp_cmp LT exp_sh { $$ = operator("lt","<", 6,pair($1,$3)); } | exp_cmp LE exp_sh { $$ = operator("le","<=",6,pair($1,$3)); } exp_eq : exp_cmp | exp_eq EQ exp_cmp { $$ = operator("eq","==",7,pair($1,$3)); } | exp_eq NE exp_cmp { $$ = operator("ne","!=",7,pair($1,$3)); } ; exp_bitand : exp_eq | exp_bitand BITAND exp_eq { $$ = operator("bitand","&",8,pair($1,$3)); } ; exp_bitor : exp_bitand | exp_bitor BITOR exp_bitand { $$ = operator("bitor", "|",9,pair($1,$3)); } ; exp_logand : exp_bitor | exp_logand LOGAND exp_bitor { $$ = operator("and","&&",10,pair($1,$3)); } | exp_logand LOGAND2 exp_bitor { $$ = operator("and2","&&&",10,pair($1,$3)); } ; exp_logor : exp_logand | exp_logor LOGOR exp_logand { $$ = operator("or", "||",11,pair($1,$3)); } | exp_logor LOGOR2 exp_logand { $$ = operator("or2", "|||",11,pair($1,$3)); } ; exp_cond : exp_logor | exp_logor '?' exp_cond ':' exp_cond { $$ = operator("if","?:",12,triple($1,$3,$5)); } ; exp_let : exp_cond | name '=' exp_let { $$ = binding($1,$3); define_variable($$); } ; exp : exp_let { if (syntax_error_occurred) {syntax_error_occurred = 0; YYERROR; } else $$ = $1; } ; name : NAME | VARNAME ; %% void syntax_error(const char *fmt, ...) { va_list va; va_start(va, fmt); vfprintf(stderr, fmt, va); va_end(va); fprintf(stderr, "\n"); syntax_error_occurred = 1; } void yyerror(char *s) { fprintf(stderr, "%s\n", s); syntax_error_occurred = 0; } static expr_list *parse(void) { #if 0 yydebug = 1; #endif syntax_error_occurred = 0; if (yyparse() != 0) { fprintf(stderr, "Parse error\n"); return NULL; } if (syntax_error_occurred) { fprintf(stderr, "Syntax error\n"); return NULL; } return result; } expr_list *parse_string(const char *s) { initialize_scanner_string(s); return parse(); } expr_list *parse_stream(FILE *fp) { expr_list *e; initialize_scanner_stream(fp); if (isatty(fileno(fp))) fputs("Enter expressions, \"end\" when done.\n", stderr); e = parse(); if (isatty(fileno(fp))) fputs("\n", stderr); return e; }