本文共 3434 字,大约阅读时间需要 11 分钟。
由于需要返回的是一个后缀表达式,是一个字符串,因此YYSTYPE需要声明为char*, 而词法分析函数中不仅需要分析运算符,多位十进制整数,空白字符,还需要识别标识符ID。而对于多位十进制整数,不再需要得到整数值,而是需要得到整数对应的字符串。对于多位十进制整数,当读到一个字符为整数字符时,连续读接下来的数字字符直至读到不为数字字符的字符,调用ungetc 函数将读出的非数字字符放回缓冲区,将读到的若干数字字符存为一个字符串, 最后需要在字符串的最后添加结束符\0, 将这个字符串的地址赋给yylval。
NUMBER 的翻译模式执行动作就修改为将yylval的值拷贝给NUMBER, 这里需要注意的是,这里翻译模式的代码中并未出现yylval,却依然完成了赋值操作,这是因为yacc 与lex 默认将yylval 的值赋给了识别出的标识符。
ID 与NUMBER 思路类似,声明一个名为ID的token 和一个全局的字符串变量yylval, 用于赋给ID 值,由于标识符是有数字、字母和下划线组成的,而第一个字符不可以为数字,因此思路为当读到一个字符为字母或下划线时,连续读接下来的字符,直到出现一个不是数字或字母或下划线的字符停止,调用ungetc 函数将读出的非数字非字母非下划线字符放回缓冲区,将读到的若干字符存为一个字符串,将这个字符串的地址赋给yylval。ID 的翻译模式执行动作就修改为将$1 的值赋给ID。对于加减乘除、括号、负号、空白字符的词法分析部分不需修改,但语法分析部分需要将计算值修改成字符串的拷贝和连接。
实现代码如下:
postexpr.y文件,编译方法见我上一篇文章末尾%{ #include#include #include #include #define YYSTYPE char*char idstr[50];char numstr[50];int yylex();extern int yyparse();FILE* yyin;void yyerror(const char*s);%}%token NUMBER%token ID%token ADD SUB MUL DIV LKO RKO%left LKO%left ADD SUB%left MUL DIV%right UMINUS%right RKO%%lines : lines expr '\n'{ printf("%s\n",$2);} | lines '\n' | ;expr : expr ADD expr { $$=(char*)malloc(50*sizeof(char)); strcpy($$,$1); strcat($$,$3);strcat($$,"+"); } | expr SUB expr { $$=(char*)malloc(50*sizeof(char)); strcpy($$,$1); strcat($$,$3);strcat($$,"-"); } | expr MUL expr { $$=(char*)malloc(50*sizeof(char)); strcpy($$,$1); strcat($$,$3);strcat($$,"*"); } | expr DIV expr { $$=(char*)malloc(50*sizeof(char)); strcpy($$,$1); strcat($$,$3);strcat($$,"/"); } | LKO expr RKO { $$=(char*)malloc(50*sizeof(char));strcpy($$,$2);} | NUMBER { $$ = (char*)malloc(50*sizeof(char)); strcpy($$,$1); strcat($$," ");} | ID { $$=(char*)malloc(50*sizeof(char)); strcpy($$,$1);strcat($$," ");}%%int yylex(){ int t; while(1){ t=getchar(); if(t==' '||t=='\t'); else if((t>='0'&& t<='9')){ int ti=0; while((t>='0'&& t<='9')){ numstr[ti]=t; t=getchar(); ti++; } numstr[ti]='\0'; yylval=numstr; ungetc(t,stdin); return NUMBER; } else if((t>='a'&&t<='z')||(t>='A'&&t<='Z')||(t=='_')){ int ti=0; while((t>='a'&&t<='z')||(t>='A'&&t<='Z') ||(t=='_')||(t>='0'&& t<='9')){ idstr[ti]=t; ti++; t=getchar(); } idstr[ti]='\0'; yylval=idstr; ungetc(t,stdin); return ID; } else { switch(t) { case '+': return ADD; case '-': return SUB; case '*': return MUL; case '/': return DIV; case'(': return LKO; case')': return RKO; default: return t; } } return t; }}int main(void){ yyin = stdin; do{ yyparse(); }while(!feof(yyin)); return 0;}void yyerror(const char* s){ fprintf(stderr,"Parse error:%s\n",s); exit(1);}
转载地址:http://ybmf.baihongyu.com/