Bison 带yacc的多字符算子
我一直在尝试向给定的前缀/中缀/后缀计算器添加位运算符,但由于某些原因,我无法使用yacc识别运算符“**”。我到处找过一些有类似问题的人,特别是这个问题,但没有找到有效的解决方案 我的莱克斯档案Bison 带yacc的多字符算子,bison,yacc,lex,flex-lexer,Bison,Yacc,Lex,Flex Lexer,我一直在尝试向给定的前缀/中缀/后缀计算器添加位运算符,但由于某些原因,我无法使用yacc识别运算符“**”。我到处找过一些有类似问题的人,特别是这个问题,但没有找到有效的解决方案 我的莱克斯档案 %{ #include "zcalc.h" #include <math.h> int ch; int flag = 0; #define NAME 257 #define SEMISYM 268 #define COMMASYM 269 #define L
%{
#include "zcalc.h"
#include <math.h>
int ch;
int flag = 0;
#define NAME 257
#define SEMISYM 268
#define COMMASYM 269
#define LPARSYM 270
#define RPARSYM 271
#define EQSYM 272
#define PLUSSYM 273
#define MULTSYM 274
#define ASGNSYM 275
#define MINUSSYM 276
#define NUMBER 277
#define TILDE 278
/*New stuff I added*/
#define BITAND 279
#define BITOR 280
#define BITXOR 281
/*#define BITNOT 282*/
#define LSHIFT 283
#define RSHIFT 284
#define POWER 285
void yyerror( char *mesg ); /* yacc error checker */
/* definitions for lex analyzer */
letter [A-Za-z]
digit [0-9]+
ident {letter}({letter}|{digit})*
ws [ \t\n]+
other .
%%
{ws} ; /*---- Tokens and Actions---- */
/*New Stuff*/
"&" return BITAND;
"|" return BITOR;
"^" return BITXOR;
"<<" return LSHIFT;
">>" return RSHIFT;
"**" return POWER;
"//".* ;
";" return SEMISYM;
"," return COMMASYM;
"(" return LPARSYM;
")" return RPARSYM;
"==" return EQSYM;
"+" return PLUSSYM;
"*" return MULTSYM;
"=" return ASGNSYM;
"-" return MINUSSYM;
"~" return TILDE;
/*New Stuff
"&" return BITAND;
"|" return BITOR;
"^" return BITXOR;
"<<" return LSHIFT;
">>" return RSHIFT;
"**" return POWER;*/
{ident} {
return NAME;
}
{digit} {
return NUMBER;
}
"$" { return 0; }
{other} ; /* ignore other stuff */
%%
void yyerror( char *mesg ); /* yacc error checker */
/* yacc error function */
void yyerror( char *mesg ) {
flag = 1;
printf("%s \n" , mesg);
}
int main() {
printf("Lex \t\tToken\t\t\n"); /* header on columns */
printf("----------------------------\n");
do
{
ch = yylex();
if (ch == SEMISYM)
printf("%s\t\tSEMICOLON ", yytext);
else if (ch == COMMASYM)
printf("%s\t\tCOMMA ", yytext);
else if (ch == LPARSYM)
printf("%s\t\tL_PARENTHESIS ", yytext);
else if (ch == RPARSYM)
printf("%s\t\tR_PARENTHESIS ", yytext);
else if (ch == EQSYM)
printf("%s\t\tEQ_OP ", yytext);
else if (ch == PLUSSYM)
printf("%s\t\tPLUS_OP ", yytext);
else if (ch == MULTSYM)
printf("%s\t\tMULT_OP ", yytext);
else if (ch == ASGNSYM)
printf("%s\t\tASSIGNMENT_STMT ", yytext);
else if (ch == MINUSSYM)
printf("%s\t\tMINUS_OP ", yytext);
else if (ch == NUMBER)
printf("%s\t\tNUMBER ", yytext);
else if (ch == NAME)
printf("%s\t\tNAME\t\t", yytext);
else if (ch == TILDE)
printf("%s\t\tTILDE\t\t", yytext);
else
printf("%c ",ch);
printf("\n"); /* end check token read */
}
while(ch != 0); /* read until end of file */
return 0;
}
int yywrap() {
return 1;
}
%}
%{
#包括“zcalc.h”
#包括
int-ch;
int标志=0;
#定义名称257
#定义SEMISYM 268
#定义COMMASYM 269
#定义LPARSYM 270
#定义RPARSYM 271
#定义等式SYM 272
#定义PLUSSYM 273
#定义MULTSYM 274
#定义ASGNSYM 275
#定义最小SYM 276
#定义数字277
#定义TILDE 278
/*我加的新东西*/
#定义比特和279
#定义比特数280
#定义位异或281
/*#定义BITNOT 282*/
#定义LSHIFT 283
#定义重新换档284
#定义电源285
无效yyerror(char*mesg);/*yacc错误检查器*/
/*lex分析器的定义*/
字母[A-Za-z]
数字[0-9]+
ident{letter}({letter}{digit})*
ws[\t\n]+
其他的。
%%
{ws};/*----令牌和操作--*/
/*新东西*/
“&”返回位和;
“|”返回位;
“^”返回位异或;
“”返回重新换档;
“**”返回功率;
"//".* ;
“;”返回半符号;
“,”返回通信系统;
“(“返回LPARSYM;
“)返回RPARSYM;
“==”返回等式SYM;
“+”返回PLUSSYM;
“*”返回MULTSYM;
“=”返回ASGNSYM;
“-”返回MINUSSYM;
“~”返回TILDE;
/*新东西
“&”返回位和;
“|”返回位;
“^”返回位异或;
“”返回重新换档;
“**”返回功率*/
{ident}{
返回名称;
}
{数字}{
返回号码;
}
“$”{返回0;}
{other};/*忽略其他内容*/
%%
无效yyerror(char*mesg);/*yacc错误检查器*/
/*yacc误差函数*/
无效错误(字符*mesg){
flag=1;
printf(“%s\n”,mesg);
}
int main(){
printf(“Lex\t\tToken\t\t\n”);/*列标题*/
printf(“-----------------------------\n”);
做
{
ch=yylex();
if(ch==SEMISYM)
printf(“%s\t\tSEMICOLON”,yytext);
else if(ch==COMMASYM)
printf(“%s\t\t命令”,yytext);
else if(ch==LPARSYM)
printf(“%s\t\tL_括号”,yytext);
else if(ch==RPARSYM)
printf(“%s\t\tR_括号”,yytext);
else if(ch==EQSYM)
printf(“%s\t\tEQ_OP”,yytext);
else if(ch==PLUSSYM)
printf(“%s\t\tPLUS_OP”,yytext);
else if(ch==MULTSYM)
printf(“%s\t\t结果”,yytext);
else if(ch==ASGNSYM)
printf(“%s\t\t签名”,yytext);
else if(ch==MINUSSYM)
printf(“%s\t\tMINUS_OP”,yytext);
else if(ch==编号)
printf(“%s\t\t编号”,yytext);
else if(ch==名称)
printf(“%s\t\t名称\t\t”,yytext);
else if(ch==TILDE)
printf(“%s\t\tTILDE\t\t”,yytext);
其他的
printf(“%c”,ch);
printf(“\n”);/*结束检查令牌读取*/
}
while(ch!=0);/*一直读到文件结尾*/
返回0;
}
int yywrap(){
返回1;
}
%}
还有我的yacc文件
%{
#include "zcalc.h"
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
int flag = 0;
void yyerror( char *mesg ); /* yacc error checker */
%}
%union {
double dval;
struct symtab *symp;
}
%token <symp> NAME
%token <dval> NUMBER
// %token LSHIFT
// %token RSHIFT
%token POWER
%left '-' '+'
//%left "**"
%left '*' '/'
//%left LSHIFT RSHIFT
//%left POWER
%type <dval> expression
%%
statement_list: statement '\n'
| statement_list statement '\n'
statement: NAME '=' expression { $1->value = $3; }
| expression { printf("= %g\n", $1); }
expression: '+' expression expression { $$ = $2 + $3; }
| '-' expression expression { $$ = $2 - $3; }
| POWER expression expression { $$ = $3; }
| '*' expression expression { $$ = $2 * $3; }
| '/' expression expression { $$ = $2 / $3; }
| '&' expression expression { $$ = (int)$2 & (int)$3; }
| '|' expression expression { $$ = (int)$2 | (int)$3; }
| '^' expression expression { $$ = (int)$2 ^ (int)$3; }
| '<' '<' expression expression { $$ = (int)$3 << (int)$4; }
| '>' '>' expression expression { $$ = (int)$3 >> (int)$4; }
//| "**" expression expression { $$ = pow($2, $3); }
| '~' expression { $$ = ~ (int)$2; }
| '(' expression ')' { $$ = $2; }
| NUMBER
| NAME { $$ = $1->value; }
%%
struct symtab * symlook( char *s ) {
char *p;
struct symtab *sp;
for(sp = symtab; sp < &symtab[NSYMS]; sp++) {
/* is it already here? */
if (sp->name && !strcmp(sp->name, s))
return sp;
/* is it free */
if (!sp->name) {
sp->name = strdup(s);
return sp;
}
/* otherwise continue to the next */
}
yyerror("Too many symbols...\n");
exit(1);
}
void addfunc( char *name, double (*func)() ) {
struct symtab *sp = symlook(name);
sp->funcptr = func;
}
/* yacc error function */
void yyerror( char *mesg ) {
flag = 1;
printf("%s \n" , mesg);
}
int main() {
yyparse();
return 0;
}
%{
#包括“zcalc.h”
#包括
#包括
#包括
#包括
int标志=0;
无效yyerror(char*mesg);/*yacc错误检查器*/
%}
%联合{
双dval;
结构符号表*符号;
}
%令牌名
%令牌号
//%LSHIFT令牌
//%r标记移位
%代币权
%左''''+'
//%左“**”
%左'*''/'
//%左L档重新换档
//%左幂
%类型表达式
%%
语句列表:语句'\n'
|语句\u列表语句'\n'
语句:名称“=”表达式{$1->value=$3;}
|表达式{printf(=%g\n“,$1);}
表达式:“+”表达式{$$=$2+$3;}
|“-”表达式{$$=$2-$3;}
|幂表达式{$$=$3;}
|“*”表达式{$$=$2*$3;}
|“/”表达式{$$=$2/$3;}
|“&”表达式{$$=(int)$2&(int)$3;}
|“|”表达式{$$=(int)$2 |(int)$3;}
|“^”表达式{$$=(int)$2^(int)$3;}
|“”表达式{$$=(int)$3>>(int)$4;}
//|“**”表达式{$$=pow($2,$3);}
|“~”表达式{$$=~(int)$2;}
|“(“表达式”)”{$$=$2;}
|数
|名称{$$=$1->value;}
%%
结构symtab*symlook(字符*s){
char*p;
结构符号表*sp;
对于(sp=symtab;sp<&symtab[NSYMS];sp++){
/*已经到了吗*/
如果(sp->name&&!strcmp(sp->name,s))
返回sp;
/*是免费的吗*/
如果(!sp->name){
sp->name=strdup;
返回sp;
}
/*否则继续下一步*/
}
yyerror(“符号太多…\n”);
出口(1);
}
void addfunc(字符*名称,双(*func)(){
结构symtab*sp=symlook(名称);
sp->funcptr=func;
}
/*yacc误差函数*/
无效错误(字符*mesg){
flag=1;
printf(“%s\n”,mesg);
}
int main(){
yyparse();
返回0;
}
我在标题中摆弄了定义和规则的位置,但这似乎不起作用。我可以使用“使“”工作。问题是,尽管您可以在bison中定义和使用类似于“
”>“
的令牌,但此类令牌没有扩展到.tab.h文件中定义的值的宏,因此没有(简单的)方法在lexer中生成令牌。为了使用它们,您需要找出bison分配给它们的令牌值(一个整数)(可以在.output文件中看到)并返回该整数。但是对.y文件的任何更改(添加的任何新标记,甚至只是重新排序的东西)都可能会改变这一点,因此几乎不可能进行维护
相反,定义bison将为其生成ma的名称标记(如LSHIFT
和RSHIFT
)更有意义
else
printf("%d\t\tUNKNOWN (%s)",ch, yytext);
Lex Token
----------------------------
()+*=-~ &|^>>**<<;,()===
( L_PARENTHESIS
) R_PARENTHESIS
+ PLUS_OP
* MULT_OP
= ASSIGNMENT_STMT
- MINUS_OP
~ TILDE
279 UNKNOWN (&)
280 UNKNOWN (|)
281 UNKNOWN (^)
284 UNKNOWN (>>)
260 UNKNOWN (**)
283 UNKNOWN (<<)
; SEMICOLON
, COMMA
( L_PARENTHESIS
) R_PARENTHESIS
== EQ_OP
= ASSIGNMENT_STMT
0 UNKNOWN ()
%token LSHIFT "<<"
...
%left "<<"
...
expression: expression "<<" expression {...}
"<<" return LSHIFT;