%{
#include <iostream>
#include <string>
#include <cmath>
#define YYDEBUG 1 <-- set debug on
typedef struct symrec
{
char *name;
int type;
union {
double var;
double (*fnctptr)(double);
} value;
struct symrec *next;
} symrec;
%}
%union { <-- yystype
double val;
symrec *tptr;
}
%token <val> NUM
%token <tptr> VAR FNCT
%type <val> exp
%right '='
%left '-' '+'
%left '*' '/'
%left NEG
%right '^'
%name-prefix="Mfcalc" <-- classname prefix (MfcalcPushParser)
%%
input: |
| input line |
; |
|
line: |
'\n' |
| exp '\n' { printf ("\t%.10g\n", $1); } |
| error '\n' { yyerrok(); } |
; |
|
exp: NUM { $$ = $1; } |
| VAR { $$ = $1->value.var; } | pull grammar == push grammar
| VAR '=' exp { $$ = $3; $1->value.var = $3; } |
| FNCT '(' exp ')' { $$ = (*($1->value.fnctptr))($3); } |
| exp '+' exp { $$ = $1 + $3; } |
| exp '-' exp { $$ = $1 - $3; } |
| exp '*' exp { $$ = $1 * $3; } |
| exp '/' exp { $$ = $1 / $3; } |
| '-' exp %prec NEG { $$ = -$2; } |
| exp '^' exp { $$ = pow ($1, $3); } |
| '(' exp ')' { $$ = $2; } |
; |
%%
class MyMfcalcPushParser:public MfcalcPushParser <-- implement debugPrint(...) and yyerror(...)
{
private:
virtual void debugPrint(int aInt) const
{
std::cout << aInt;
}
virtual void debugPrint(std::string s) const
{
std::cout << s;
}
public:
MyMfcalcPushParser() {}
virtual void yyerror(const char* s) const
{
std::cout << s << std::endl;
}
virtual void accept() <-- called if parser state == accept
{
std::cout << "\taccept!" << std::endl;
}
virtual void error() <-- called if parser state == error || parser state == abort
{
std::cout << "\terror!" << std::endl;
}
};
<-- Lexer
symrec *sym_table;
struct init
{
char *fname;
double (*fnct)(double);
};
symrec *putsym(char *sym_name,int sym_type)
{
symrec *ptr;
ptr = (symrec *) malloc (sizeof (symrec));
ptr->name = (char *) malloc (strlen (sym_name) + 1);
strcpy (ptr->name,sym_name);
ptr->type = sym_type;
ptr->value.var = 0;
ptr->next = (struct symrec *)sym_table;
sym_table = ptr;
return ptr;
}
symrec *getsym(char *sym_name)
{
symrec *ptr;
for (ptr=sym_table;ptr!=NULL;ptr=(symrec *)ptr->next) {
if (strcmp (ptr->name,sym_name) == 0) {
return ptr;
}
}
return 0;
}
void init_sym_table ()
{
int i;
symrec *ptr;
struct init arith_fncts[] = {
"sin" ,sin,
"cos" ,cos,
"atan",atan,
"ln" ,log,
"exp" ,exp,
"sqrt",sqrt,
0 ,0
};
for (i=0;arith_fncts[i].fname!=0;i++) {
ptr=putsym(arith_fncts[i].fname,FNCT);
ptr->value.fnctptr=arith_fncts[i].fnct;
}
}
int lex(MyMfcalcPushParser *parser)
{
int c;
MyMfcalcPushParser::SemanticType yylval;
while(1) {
while ((c=getchar())==' ' || c=='\t');
if (c==EOF) {
yylval.val=EOF;
parser->parseToken(0,yylval); <-- parse EOF
return 0;
}
if (c == '.' || isdigit(c)) {
ungetc(c,stdin);
scanf("%lf",&yylval.val);
parser->parseToken(NUM,yylval); <-- instead of return(...) parseToken(...)
} else if(isalpha(c)) {
symrec *s;
static char *symbuf=0;
static int length=0;
int i;
if (length==0) {
length=40,symbuf=(char *)malloc(length+1);
}
i=0;
do {
if (i == length) {
length *= 2;
symbuf=(char *)realloc(symbuf,length+1);
}
symbuf[i++] = c;
c=getchar();
}
while (c!=EOF && isalnum(c));
ungetc (c,stdin);
symbuf[i]='\0';
s=getsym(symbuf);
if(s==0) {
s = putsym (symbuf, VAR);
yylval.tptr = s;
parser->parseToken(VAR,yylval);
}
yylval.tptr = s;
parser->parseToken(FNCT,yylval);
} else {
parser->parseToken(c,yylval);
}
}
}
int main ()
{
MyMfcalcPushParser *parser=new MyMfcalcPushParser();
parser->setDebug(1);
init_sym_table();
lex(parser);
delete parser;
return 0;
}