Yacc实现中缀表达式转后缀
由于需要返回的是一个后缀表达式,是一个字符串,因此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文件,编译方法见我上一篇文章末尾编译原理学习(一)——Yacc实现计算器
%{
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<ctype.h>
#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);
}
博客围绕后缀表达式的实现展开,在C++环境下,YYSTYPE声明为char*,词法分析需识别运算符、多位十进制整数、空白字符和标识符ID。对于多位十进制整数和标识符,将读到的字符存为字符串并赋给yylval。语法分析部分需将计算值修改成字符串的拷贝和连接,还给出了实现代码文件。
——Yacc实现中缀表达式转后缀&spm=1001.2101.3001.5002&articleId=109456809&d=1&t=3&u=efd8e45e0f7945ca98b637a288caaeec)
3142

被折叠的 条评论
为什么被折叠?



