%{ #define _XOPEN_SOURCE 700 #include #include #include #include #include #include typedef struct { int type; union { intmax_t i; char *s; } u; } expr_yystype; #define YYSTYPE expr_yystype #include "y.tab.h" static int yylex(void); extern int yyerror(const char *s); static void expr_only_integers(YYSTYPE *y1, YYSTYPE *y2) { if (y1->type == STRING) { fprintf(stderr, "expr: %s is not an integer\n", y1->u.s); exit(1); } if (y2->type == STRING) { fprintf(stderr, "expr: %s is not an integer\n", y2->u.s); exit(1); } } static int expr_compare(YYSTYPE *y1, YYSTYPE *y2) { if (y1->type == INTEGER && y2->type == INTEGER) { return y1->u.i - y2->u.i; } char buf[64]; char *s1 = y1->u.s; char *s2 = y2->u.s; if (y1->type == INTEGER) { snprintf(buf, sizeof(buf), "%d", y1->u.i); s1 = buf; } else if (y2->type == INTEGER) { snprintf(buf, sizeof(buf), "%d", y2->u.i); s2 = buf; } return strcmp(s1, s2); } %} %token INTEGER %token STRING %token '(' ')' %left ':' %left '*' '/' '%' %left '+' '-' %left '=' '<' '>' LE GE NE %left '&' %left '|' %start expr %% expr : STRING { } | INTEGER { } | '(' expr ')' { } | expr ':' expr { printf("match\n"); } | expr '*' expr { expr_only_integers(&$1, &$3); $$.u.i = $1.u.i * $3.u.i; printf("%d\n", $$.u.i); } | expr '/' expr { expr_only_integers(&$1, &$3); $$.u.i = $1.u.i / $3.u.i; printf("%d\n", $$.u.i); } | expr '%' expr { expr_only_integers(&$1, &$3); $$.u.i = $1.u.i % $3.u.i; printf("%d\n", $$.u.i); } | expr '+' expr { expr_only_integers(&$1, &$3); $$.u.i = $1.u.i + $3.u.i; printf("%d\n", $$.u.i); } | expr '-' expr { expr_only_integers(&$1, &$3); $$.u.i = $1.u.i - $3.u.i; printf("%d\n", $$.u.i); } | expr '=' expr { int r = expr_compare(&$1, &$3) == 0; printf("%d\n", r); } | expr NE expr { int r = expr_compare(&$1, &$3) != 0; printf("%d\n", r); } | expr '<' expr { int r = expr_compare(&$1, &$3) < 0; printf("%d\n", r); } | expr LE expr { int r = expr_compare(&$1, &$3) <= 0; printf("%d\n", r); } | expr '>' expr { int r = expr_compare(&$1, &$3) > 0; printf("%d\n", r); } | expr GE expr { int r = expr_compare(&$1, &$3) >= 0; printf("%d\n", r); } | expr '&' expr { printf("and\n"); } | expr '|' expr { printf("or\n"); } ; %% /* "|" return '|'; "&" return '&'; "=" return '='; ">" return '>'; ">=" return GE; "<" return '<'; "<=" return LE; "!=" return NE; "+" return '+'; "-" return '-'; "*" return '*'; "/" return '/'; "%" return '%'; "(" return '('; ")" return ')'; ":" return ':'; {DIGIT}+ { yylval.u.i = atoi(yytext); return yylval.type = INTEGER; } -{DIGIT}+ { yylval.u.i = atoi(yytext); return yylval.type = INTEGER; } .+ { yylval.u.s = strdup(yytext); return yylval.type = STRING; } \n ; */ static char **expr_args; static int yylex(void) { if (expr_args[optind] == NULL) { return YYEOF; } char *s = expr_args[optind]; if (strlen(s) == 1) { char c = s[0]; if (strchr("|&=+-*/%():", c)) { optind++; return c; } } if (strlen(s) == 2) { if (!strcmp(s, ">=")) { optind++; return GE; } if (!strcmp(s, "<=")) { optind++; return LE; } if (!strcmp(s, "!=")) { optind++; return NE; } } char *end = NULL; yylval.type = INTEGER; yylval.u.i = strtoimax(s, &end, 10); if (end && *end != '\0') { yylval.type = STRING; yylval.u.s = s; } optind++; return yylval.type; } int main(int argc, char *argv[]) { setlocale(LC_ALL, ""); int c; while ((c = getopt(argc, argv, "")) != -1) { switch (c) { default: return -1; } } if (optind >= argc) { fprintf(stderr, "expr: missing operands\n"); return 1; } expr_args = argv; return yyparse(); }