/* $Id: algebra.y,v 1.6 2004/07/11 08:45:56 bhepple Exp $ */ %{ #include #include #include #include #include "config.h" #include "dcalc.h" extern char *parserPointer; extern void msg(char*); struct funcName_s { char *fname; int (*func)(); }; double yy_tempf; #ifdef DEBUG # define TRACE(x) x #else # define TRACE(x) #endif static int exec_x(); static int exec_y(); static int exec_z(); static int exec_t(); static int exec_u(); static int exec_l(); extern struct funcName_s *getsym(char *sym_name, int *len); extern int yyerror(char *); extern int yylex(void); extern int yyparse(void); %} %union { long ival; double val; /* For returning numbers. */ struct funcName_s *fptr; /* For returning symbol-table pointers */ } %token INUM /* integer */ %token NUM /* Simple number */ %token FNCT /* Function */ %token IFNCT /* Function */ %type exp %type iexp %type dummy %left OR %left AND %left XOR %left LEFT RIGHT %left '-' '+' yPx yCx DAYS TODAY RECTPOLAR POLARRECT %left '*' '/' MOD %left NEG /* Negation--unary minus */ %left POS /* unary plus */ %left NOT %left '%' PCH %right '!' %right '^' /* Exponentiation */ %left ',' /* Grammar follows */ %% dummy: exp | iexp { $$ = (long) $1; }; exp: NUM { TRACE(printf("yyparse: num\n")); $$ = $1; pushf($1);} | FNCT { TRACE(printf("yyparse: func\n")); $$ = (*($1->func))(); } | FNCT '(' exp ')' { TRACE(printf("yyparse: func\n")); $$ = (*($1->func))(); } | exp '+' exp { TRACE(printf("yyparse: +\n")); exec_plus(); $$ = xfReg; } | exp '-' exp { TRACE(printf("yyparse: -\n")); exec_minus(); $$ = xfReg; } | exp '*' exp { TRACE(printf("yyparse: *\n")); exec_mult(); $$ = xfReg; } /* | exp exp %prec '*' { TRACE(printf("yyparse: (implicit) *\n")); pushf($1); pushf($2); exec_mult(); $$ = xfReg; } /* gives reduce/reduce errors with unary +- */ | exp '/' exp { TRACE(printf("yyparse: /\n")); exec_divide(); $$ = xfReg; } | exp '+' exp '%' { TRACE(printf("yyparse: +%%\n")); pushf(1.0 + popf() / 100.0); exec_mult(); $$ = xfReg; } | exp '-' exp '%' { TRACE(printf("yyparse: -%%\n")); pushf(1.0 - popf() / 100.0); exec_mult(); $$ = xfReg; } | exp '*' exp '%' { TRACE(printf("yyparse: *%%\n")); pushf(popf() / 100.0); exec_mult(); $$ = xfReg; } /* these two cause reduce/reduce errors: better leave them out 3% ... a bit meaningless anyway 3 4% ... use 3 x 4% | exp exp '%' { TRACE(printf("yyparse: *%%\n")); pushf(popf() / 100.0); exec_mult(); $$ = xfReg; } | exp '%' { TRACE(printf("yyparse: %%\n")); pushf(popf() / 100.0); $$ = xfReg; } */ | exp '/' exp '%' { TRACE(printf("yyparse: /%%\n")); pushf(popf() / 100.0); exec_divide(); $$ = xfReg; } | '-' exp %prec NEG { TRACE(printf("yyparse: unary -\n")); exec_chs(); $$ = xfReg; } | '+' exp %prec POS { TRACE(printf("yyparse: unary +\n")); $$ = xfReg; } | exp yPx exp { TRACE(printf("yyparse: PERM\n")); exec_perm(); $$ = xfReg; } | exp yCx exp { TRACE(printf("yyparse: COMB\n")); exec_comb(); $$ = xfReg; } | exp DAYS exp { TRACE(printf("yyparse: DAYS\n")); exec_dys(); $$ = xfReg; } | exp RECTPOLAR exp { TRACE(printf("yyparse: RECTPOLAR\n")); exec_rtop(); $$ = xfReg; } | exp POLARRECT exp { TRACE(printf("yyparse: POLARRECT\n")); exec_ptor(); $$ = xfReg; } | TODAY { TRACE(printf("yyparse: TODAY\n")); exec_tdy(); $$ = xfReg; } | exp '!' { TRACE(printf("yyparse: factorial\n")); exec_fact(); $$ = xfReg; } | '(' exp ')' { TRACE(printf("yyparse: brackets\n")); $$ = $2; } | exp '^' exp { TRACE(printf("yyparse: ^\n")); exec_ytox(); $$ = xfReg; } | exp PCH exp { TRACE(printf("yyparse: PERCENTCH\n")); exec_percentch(); $$ = xfReg; } ; iexp: INUM { TRACE(printf("yyparse: inum\n")); $$ = $1; push($1); } | IFNCT { TRACE(printf("yyparse: func\n")); $$ = (*($1->func))(); } | IFNCT '(' iexp ')' { TRACE(printf("yyparse: func\n")); $$ = (*($1->func))(); } | NOT iexp { TRACE(printf("yyparse: NOT\n")); exec_not(); $$ = xiReg; } | iexp AND iexp { TRACE(printf("yyparse: AND\n")); exec_and(); $$ = xiReg; } | iexp MOD iexp { TRACE(printf("yyparse: AND\n")); exec_modulus(); $$ = xiReg; } | iexp OR iexp { TRACE(printf("yyparse: OR\n")); exec_or(); $$ = xiReg; } | iexp XOR iexp { TRACE(printf("yyparse: XOR\n")); exec_xor(); $$ = xiReg; } | iexp LEFT iexp { TRACE(printf("yyparse: LEFT\n")); exec_shiftyl(); $$ = xiReg; } | iexp RIGHT iexp { TRACE(printf("yyparse: RIGHT\n")); exec_shiftyr(); $$ = xiReg; } | iexp '+' iexp { TRACE(printf("yyparse: +\n")); exec_plus(); $$ = xiReg; } | iexp '-' iexp { TRACE(printf("yyparse: -\n")); exec_minus(); $$ = xiReg; } | iexp '*' iexp { TRACE(printf("yyparse: *\n")); exec_mult(); $$ = xiReg; } /* | iexp iexp { TRACE(printf("yyparse: *\n")); push($1); push($2); exec_mult(); $$ = xReg; } /* gives reduce/reduce errors with unary +- */ | iexp '/' iexp { TRACE(printf("yyparse: /\n")); exec_divide(); $$ = xiReg; } | '-' iexp %prec NEG { TRACE(printf("yyparse: unary -\n")); exec_chs(); $$ = xiReg; } | '+' iexp %prec POS { TRACE(printf("yyparse: unary +\n")); $$ = xiReg; } | '(' iexp ')' { TRACE(printf("yyparse: brackets\n")); $$ = $2; } | iexp '^' iexp { TRACE(printf("yyparse: ^\n")); exec_ytox(); $$ = xiReg; } ; /* End of grammar */ %% static int exec_x() { (mode == PROG)? push(xSave): pushf(xfSave); return 0; } static int exec_y() { (mode == PROG)? push(ySave): pushf(yfSave); return 0; } static int exec_z() { (mode == PROG)? push(zSave): pushf(zfSave); return 0; } static int exec_t() { (mode == PROG)? push(tSave): pushf(tfSave); return 0; } static int exec_u() { (mode == PROG)? push(uSave): pushf(ufSave); return 0; } static int exec_l() { (mode == PROG)? push(lSave): pushf(lfSave); return 0; } struct funcName_s fncts[] ={ { "%", exec_percent }, { "<<", exec_shiftyl }, { ">>", exec_shiftyr }, { "acos", exec_acos }, { "acosh", exec_acosh }, { "alog10", exec_10tox }, { "aloge", exec_etox }, { "and", exec_and }, { "ans", exec_y }, { "asin", exec_asin }, { "asinh", exec_asinh }, { "atan", exec_atan }, { "atanh", exec_atanh }, { "cos", exec_cos }, { "cosh", exec_cosh }, { "croot", exec_croot }, { "cube", exec_cube }, { "ch%", exec_percentch }, { "dtor", exec_dtor }, { "dys", exec_dys }, { "e", exec_e }, /* Note 'e' is a valid hex number */ { "etox", exec_etox }, { "fact", exec_fact }, { "fclr", exec_fclr }, { "frc", exec_frc }, { "fval", exec_fval }, { "fx", exec_calcy }, { "hms", exec_hms }, { "int", exec_int }, { "intst", exec_intst }, { "l", exec_l }, { "lastx", exec_lastx }, { "log10", exec_log10 }, { "loge", exec_loge }, { "lr", exec_lr }, { "mean", exec_mean }, { "means", exec_means }, { "meany", exec_meany }, { "mod", exec_modulus }, { "nfin", exec_nfin }, { "not", exec_not }, { "nstat", exec_nstat }, { "or", exec_or }, { "pf", exec_primef }, { "pi", exec_pi }, { "plus", exec_plus }, { "pmt", exec_pmt }, { "ptor", exec_ptor }, { "pval", exec_pval }, { "rcl", exec_rcl }, { "rolldown", exec_rolldown }, { "rtod", exec_rtod }, { "rtop", exec_rtop }, { "s_dev", exec_s_dev }, { "sin", exec_sin }, { "sinh", exec_sinh }, { "sqrt", exec_root }, { "sum", exec_sum }, { "sum0", exec_sum0 }, { "sumr", exec_sumr }, { "t", exec_t }, { "tan", exec_tan }, { "tanh", exec_tanh }, { "tdy", exec_tdy }, { "u", exec_u }, { "x", exec_x }, { "xnl", exec_xnl }, { "xnt", exec_xnt }, { "xny", exec_xny }, { "xnz", exec_xnz }, { "xor", exec_xor }, { "y", exec_y }, { "ycx", exec_comb }, { "ypx", exec_perm }, { "z", exec_z }, { 0, 0 } }; struct funcName_s * getsym (char *sym_name, int *len) { struct funcName_s *ptr; int i; static char *symbuf = 0; char c; static int length = 0; /* Initially make the buffer long enough for a 40-character symbol name. */ if (length == 0) { length = 40; symbuf = (char *)malloc (length + 1); } i = 0; c = tolower(sym_name[0]); do { /* If buffer is full, make it bigger. */ if (i == length) { length *= 2; symbuf = (char *)realloc (symbuf, length + 1); } /* Add this character to the buffer. */ symbuf[i++] = c; /* Get another character. */ c = tolower(*++sym_name); } while (c != 0 && (isalnum (c) || (i == 1 && c == symbuf[0]))); symbuf[i] = '\0'; TRACE(printf("getsym: searching for <%s>\n", symbuf);) *len = strlen(symbuf); for (ptr = fncts; ptr->fname != (char *) 0; ptr++) if (strcmp(ptr->fname, symbuf) == 0) return ptr; return 0; } int yylex (void) { char *endptr; int c; /* Ignore whitespace, get first nonwhite character. */ while ((c = *parserPointer) != 0 && (c == ' ' || c == '\t')) parserPointer++; if (c == 0) return 0; /* These seem to be alpha to isalpha() and to be affected by * tolower(), at least on the bookman. Unix seems ok tho'!: */ if (c == '×' || c == '÷') { TRACE(printf("yylex: TOKEN <%c>\n", c)); parserPointer++; return c=='×'? '*': '/'; } c = tolower(*parserPointer); if (mode == PROG) { switch (intmode) { case BIN: if (c == '0' || c == '1') { yylval.ival = strtol(parserPointer, &endptr, 2); parserPointer = endptr; TRACE(printf("yylex: INUM %ld\n", yylval.ival)); return INUM; } break; case OCT: if (c >= '0' && c <= '7') { yylval.ival = strtol(parserPointer, &endptr, 8); parserPointer = endptr; TRACE(printf("yylex: INUM 0%lo\n", yylval.ival)); return INUM; } break; case DEC: if (c >= '0' && c <= '9') { yylval.ival = strtol(parserPointer, &endptr, 10); parserPointer = endptr; TRACE(printf("yylex: INUM %ld\n", yylval.ival)); return INUM; } break; case HEX: if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f')) { int len; struct funcName_s *s; /* extra care here as functions starting with a-f * could get here */ if (isalpha(c) && (s = getsym(parserPointer, &len)) != NULL) if (s->func != exec_e) /* E by itself */ break; yylval.ival = strtol(parserPointer, &endptr, 16); parserPointer = endptr; TRACE(printf("yylex: INUM 0x%lx\n", yylval.ival)); return INUM; } break; case IP: /* look for 4 decimal numbers from 0-255 separated by . */ do { int i, num[4], count = 0; for (i = 0; i < 4; i++) { TRACE(printf("parserPointer = <%s>\n", parserPointer);) num[i] = 0; if (!*parserPointer || (*parserPointer < '0' || *parserPointer > '9')) break; count++; num[i] = strtol(parserPointer, &endptr, 10); TRACE(printf("num[%d]=%d\n", i, num[i]);) parserPointer = endptr; if (*parserPointer == '.') parserPointer++; } TRACE(printf("count=%d\n", count);) yylval.ival = 0; for (i = 0; count--; i++) { yylval.ival = (yylval.ival << 8) | num[i]; TRACE(printf("%d: yylval.ival = %ld\n", i, yylval.ival);) } TRACE(printf("final yylval.ival = %ld\n", yylval.ival);) } while (0); return INUM; break; } } else { if (c == '.' || isdigit (c)) { yylval.val = strtod(parserPointer, &endptr); /* check for HUGE_NUM & errno? */ TRACE(printf("yylex: NUM %g\n", yylval.val)); parserPointer = endptr; return NUM; } } if (c == '%' && tolower(*(parserPointer+1)) == 'c' && tolower(*(parserPointer+2)) == 'h') { parserPointer += 3; return PCH; } if (c == '<') { if (*(parserPointer+1) == '<') { parserPointer += 2; return LEFT; } parserPointer++; return LEFT; } if (c == '>') { if (*(parserPointer+1) == '>') { parserPointer += 2; return RIGHT; } parserPointer++; return RIGHT; } /* Char starts an identifier => read the name. */ if (isalpha (c)) { struct funcName_s *s; int len; s = getsym(parserPointer, &len); parserPointer += len; if (s == 0) { TRACE(printf("yylex: not found\n")); return 0; } if (s->func == exec_and) { TRACE(printf("yylex: AND\n")); return AND; } if (s->func == exec_or) { TRACE(printf("yylex: OR\n")); return OR; } if (s->func == exec_xor) { TRACE(printf("yylex: XOR \n")); return XOR; } if (s->func == exec_not) { TRACE(printf("yylex: NOT \n")); return NOT; } if (s->func == exec_shiftyl) { TRACE(printf("yylex: SHIFTYL \n")); return LEFT; } if (s->func == exec_shiftyr) { TRACE(printf("yylex: SHIFTYR \n")); return RIGHT; } if (s->func == exec_modulus) { TRACE(printf("yylex: MOD \n")); return MOD; } if (s->func == exec_comb) { TRACE(printf("yylex: COMB \n")); return yCx; } if (s->func == exec_perm) { TRACE(printf("yylex: PERM \n")); return yPx; } if (s->func == exec_dys) { TRACE(printf("yylex: DAYS \n")); return DAYS; } if (s->func == exec_tdy) { TRACE(printf("yylex: TODAY \n")); return TODAY; } if (s->func == exec_rtop) { TRACE(printf("yylex: RECTPOLAR \n")); return RECTPOLAR; } if (s->func == exec_ptor) { TRACE(printf("yylex: POLARRECT \n")); return POLARRECT; } yylval.fptr = s; if (mode == PROG) { TRACE(printf("yylex: IFNCT %s\n", s->fname)); return IFNCT; } else { TRACE(printf("yylex: FNCT %s\n", s->fname)); return FNCT; } } /* Any other character is a token by itself. */ TRACE(printf("yylex: TOKEN <%c>\n", c)); parserPointer++; return c; } int yyerror (char *s) { /* Called by yyparse on error */ msg(s); lift_needed = 1; return 0; }