/* Einheiten-basierter Rechner */ %{ #define YYSTYPE UnitMeasure #include #include #include #include typedef struct _unitmeasure UnitMeasure; struct _unitmeasure { double val; int unit; }; double unit_factors[] = { 0.0, 1.0, 100, 10, 39.37, 3.281,}; char *unit_names[] = { "n/a", "m", "cm", "dm", "in", "ft",}; UnitMeasure unitsum (UnitMeasure arg1, UnitMeasure arg2); UnitMeasure unitnegate (UnitMeasure arg1); UnitMeasure unitmul (UnitMeasure arg1, UnitMeasure arg2); UnitMeasure unitdiv (UnitMeasure arg1, UnitMeasure arg2); %} %token NUM %token UNIT %token ERR %% /* Grammar rules and actions follow */ input: /* empty */ | input line ; line: '\n' | term '\n' { printf ("Ergebnis: %f\n", $1.val); } | uterm '\n' { printf ("Ergebnis: %f %s\n", $1.val, unit_names [$1.unit]); } ; term: expr { $$ = $1 ; } | expr '+' term { $$ = unitsum ($1, $3); } | expr '-' term { $$ = unitsum ($1, unitnegate ($3)); } ; expr: factor { $$ = $1 ; } | factor '*' expr { $$ = unitmul ($1, $3); } | factor '/' expr { $$ = unitdiv ($1, $3); } | ufactor '/' uexpr { $$ = unitdiv ($1, $3); } ; factor: NUM { $$.val = $1.val; $$.unit = 0 ; } | '-' NUM { $$ = unitnegate ($1); $$.unit = 0; } | '(' term ')' { $$ = $2 ; } ; uterm: uexpr { $$ = $1 ; } | uexpr '+' term { $$ = unitsum ($1, $3); } | uexpr '-' term { $$ = unitsum ($1, unitnegate ($3)); } | expr '+' uterm { $$ = unitsum ($1, $3); } | expr '-' uterm { $$ = unitsum ($1, unitnegate ($3)); } | uexpr '+' uterm { $$ = unitsum ($1, $3); } | uexpr '-' uterm { $$ = unitsum ($1, unitnegate ($3)); } ; uexpr: ufactor { $$ = $1 ; } | factor '*' uexpr { $$ = unitmul ($1, $3); } | ufactor '*' expr { $$ = unitmul ($1, $3); } | ufactor '/' expr { $$ = unitdiv ($1, $3); } | factor '/' uexpr { $$ = unitdiv ($1, $3); } ; ufactor: NUM UNIT { $$.val = $1.val; $$.unit = $2.unit; } | '-' NUM UNIT { $$ = unitnegate ($1); $$.unit = $3.unit; } | '(' uterm ')' { $$ = $2 ; } ; %% UnitMeasure unitsum (UnitMeasure arg1, UnitMeasure arg2) { UnitMeasure ret; if (arg1.unit == 0 || arg2.unit == 0) { ret.unit = arg1.unit + arg2.unit; ret.val = arg1.val + arg2.val; } else { ret.unit = arg1.unit; ret.val = arg1.val + arg2.val / unit_factors[arg2.unit] * unit_factors[arg1.unit]; } return ret; } UnitMeasure unitnegate (UnitMeasure arg1) { UnitMeasure ret; ret.unit = arg1.unit; ret.val = - arg1.val; return ret; } UnitMeasure unitmul (UnitMeasure arg1, UnitMeasure arg2) { UnitMeasure ret; if (arg1.unit == 0 || arg2.unit == 0) { ret.unit = arg1.unit + arg2.unit; ret.val = arg1.val * arg2.val; } else { ret = arg1; fprintf (stderr, "\nmeeep\n"); } return ret; } UnitMeasure unitdiv (UnitMeasure arg1, UnitMeasure arg2) { UnitMeasure ret; if (arg1.unit == 0 && arg2.unit != 0) { ret.unit = arg2.unit; ret.val = arg1.val / arg2.val; } else { if (arg2.unit == 0) { ret.unit = arg1.unit; ret.val = arg1.val / arg2.val; } else { ret.unit = 0; ret.val = arg1.val / unit_factors[arg1.unit] / arg2.val * unit_factors[arg2.unit]; } } return ret; } /* Lexical analyzer returns a double floating point number on the stack * and the token NUM, or the ASCII character read if not a number. Skips * all blanks and tabs, returns 0 for EOF. */ int yylex (void) { int i, c; char unitname[10]; while ((c = getchar ()) == ' ' || c == '\t'); /* skip white space */ if (c == '.' || isdigit (c)) { /* process numbers */ ungetc (c, stdin); scanf ("%lf", &yylval.val); return NUM; } if (isalpha (c)) { i = 0; do { unitname[i] = c; i++; c = getchar (); } while (i < 9 && isalpha (c)); unitname[i] = '\0'; ungetc (c, stdin); for (i = 1; i < 6; i++) { if (!strcmp (unitname, unit_names[i])) { yylval.unit = i; return UNIT; } } return ERR; } if (c == EOF) return 0; /* return end-of-file */ return c; /* return single chars */ } int main(int argc, char *argv[]) { yyparse(); return 0; } int yyerror(char *s) /* Called by yyparse on error */ { printf("%s\n", s); return 1; }