如何使用赋值 (=) 和相等 (==) 操作数创建文法?
How to make a grammar with assignation (=) and equality (==) operands?
作为我正在学习的编译器理论课程的作业,我必须在 lex/yacc 中编写一个计算器。一些要求是:
- 用户必须能够为变量分配数值或布尔值
- 计算器必须能够比较布尔语句
如果我尝试输入:
a=5;
a; // Output: 5
a==5; // Syntax error
但是,如果我输入这个就可以了:
5==a; // Output: 1
我认为问题在于 yacc 将 a==5
读取为 <a> <=> <=5>
形式的新赋值,而不是 <a> <==> <5>
。不过,我不知道如何解决这个问题。我尝试使用 %prec 注释,但这并没有解决问题。
代码如下:
calc.l
%{
#include "y.tab.h"
void yyerror(char* s);
%}
%%
"exit" { return exit_command; }
[0-9]+ { yylval.num = atoi(yytext); return number; }
[a-zA-Z] { yylval.id = yytext[0]; return identifier; }
[ \t\n] ;
[-+*/()^%;] { return yytext[0]; }
[<>=!&|] { return yytext[0]; }
. { ECHO; yyerror("Unexpected character"); }
%%
int yywrap(void) { return 1; }
calc.y
%{
void yyerror(char *s);
int yylex();
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <math.h>
int yydebug = 1;
void print(int num);
int symbols[52];
int symbolVal(char symbol);
void updateSymbolVal(char symbol, int val);
%}
%union { int num; char id; }
%start line
%token exit_command
%token <num> number
%token <id> identifier
%type <num> line bool_exp arit_exp term factor
%type <id> assignment
%%
line: line bool_exp ';' { print(); }
| bool_exp ';' { print(); }
| line assignment ';' {;}
| assignment ';' {;}
| line equality ';' {;}
| equality ';' {;}
| line exit_command { printf("Goodbye\n"); exit(EXIT_SUCCESS); }
| exit_command { printf("Goodbye\n"); exit(EXIT_SUCCESS); }
;
bool_exp: arit_exp { $$ = ; }
| bool_exp '<' arit_exp { $$ = < ; }
| bool_exp '>' '=' arit_exp { $$ = >= ; }
| bool_exp '>' arit_exp { $$ = > ; }
| bool_exp '<' '=' arit_exp { $$ = <= ; }
| bool_exp '=' '=' arit_exp { $$ = == ; }
| bool_exp '!' '=' arit_exp { $$ = != ; }
| '!' bool_exp { $$ = !; }
| bool_exp '&' '&' arit_exp { $$ = && ; }
| bool_exp '|' '|' arit_exp { $$ = || ; }
| '+' '+' identifier { updateSymbolVal(, symbolVal() + 1); $$ = symbolVal(); }
| '-' '-' identifier { updateSymbolVal(, symbolVal() - 1); $$ = symbolVal(); }
;
arit_exp: term { $$ = ; }
| arit_exp '+' term { $$ = + ; }
| arit_exp '-' term { $$ = - ; }
;
term: factor { $$ = ; }
| term '*' factor { $$ = * ; }
| term '/' factor { $$ = / ; }
| term '^' factor { $$ = pow(, ); }
| term '%' factor { $$ = % ; }
| '-' factor { $$ = * -1; }
;
factor: number { $$ = ; }
| identifier { $$ = symbolVal(); }
| '(' bool_exp ')' { $$ = ; }
;
assignment: identifier '=' bool_exp { updateSymbolVal(, ); printf("> %c <- %i\n> ", , ); } ;
%%
void print(int num) {
printf("> Result: %i\n< ", num);
}
int computeSymbolIndex(char token) {
int idx = -1;
if (islower(token)) {
idx = token - 'a' + 26;
}
else if (isupper(token)) {
idx = token - 'A';
}
return idx;
}
/* Returns the value of a given symbol */
int symbolVal(char symbol) {
int bucket = computeSymbolIndex(symbol);
return symbols[bucket];
}
void updateSymbolVal(char symbol, int val) {
int bucket = computeSymbolIndex(symbol);
symbols[bucket] = val;
}
int main(void) {
printf("Calculator made with lex and yacc\n");
printf("Usage: <Arithmetic or boolean expression> <semicolon>\n");
printf("e.g: 2+2;\n\n< ");
return yyparse();
}
void yyerror(char *s) { fprintf(stderr, "Error: %s\n", s); }
运算符应该是令牌。所以你会得到一个 Lex 扫描仪:
"==" { return EQUAL; }
等等。像现在使用 '=' '='
.
那样在解析器中形成标记是错误的
在 Yacc 文件中,您可以使用 %left TOKEN
和 %right TOKEN
定义运算符的关联性。您放置它们的顺序决定了它们的优先级(参见 this post 或 yacc
手册)。
作为我正在学习的编译器理论课程的作业,我必须在 lex/yacc 中编写一个计算器。一些要求是:
- 用户必须能够为变量分配数值或布尔值
- 计算器必须能够比较布尔语句
如果我尝试输入:
a=5;
a; // Output: 5
a==5; // Syntax error
但是,如果我输入这个就可以了:
5==a; // Output: 1
我认为问题在于 yacc 将 a==5
读取为 <a> <=> <=5>
形式的新赋值,而不是 <a> <==> <5>
。不过,我不知道如何解决这个问题。我尝试使用 %prec 注释,但这并没有解决问题。
代码如下: calc.l
%{
#include "y.tab.h"
void yyerror(char* s);
%}
%%
"exit" { return exit_command; }
[0-9]+ { yylval.num = atoi(yytext); return number; }
[a-zA-Z] { yylval.id = yytext[0]; return identifier; }
[ \t\n] ;
[-+*/()^%;] { return yytext[0]; }
[<>=!&|] { return yytext[0]; }
. { ECHO; yyerror("Unexpected character"); }
%%
int yywrap(void) { return 1; }
calc.y
%{
void yyerror(char *s);
int yylex();
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <math.h>
int yydebug = 1;
void print(int num);
int symbols[52];
int symbolVal(char symbol);
void updateSymbolVal(char symbol, int val);
%}
%union { int num; char id; }
%start line
%token exit_command
%token <num> number
%token <id> identifier
%type <num> line bool_exp arit_exp term factor
%type <id> assignment
%%
line: line bool_exp ';' { print(); }
| bool_exp ';' { print(); }
| line assignment ';' {;}
| assignment ';' {;}
| line equality ';' {;}
| equality ';' {;}
| line exit_command { printf("Goodbye\n"); exit(EXIT_SUCCESS); }
| exit_command { printf("Goodbye\n"); exit(EXIT_SUCCESS); }
;
bool_exp: arit_exp { $$ = ; }
| bool_exp '<' arit_exp { $$ = < ; }
| bool_exp '>' '=' arit_exp { $$ = >= ; }
| bool_exp '>' arit_exp { $$ = > ; }
| bool_exp '<' '=' arit_exp { $$ = <= ; }
| bool_exp '=' '=' arit_exp { $$ = == ; }
| bool_exp '!' '=' arit_exp { $$ = != ; }
| '!' bool_exp { $$ = !; }
| bool_exp '&' '&' arit_exp { $$ = && ; }
| bool_exp '|' '|' arit_exp { $$ = || ; }
| '+' '+' identifier { updateSymbolVal(, symbolVal() + 1); $$ = symbolVal(); }
| '-' '-' identifier { updateSymbolVal(, symbolVal() - 1); $$ = symbolVal(); }
;
arit_exp: term { $$ = ; }
| arit_exp '+' term { $$ = + ; }
| arit_exp '-' term { $$ = - ; }
;
term: factor { $$ = ; }
| term '*' factor { $$ = * ; }
| term '/' factor { $$ = / ; }
| term '^' factor { $$ = pow(, ); }
| term '%' factor { $$ = % ; }
| '-' factor { $$ = * -1; }
;
factor: number { $$ = ; }
| identifier { $$ = symbolVal(); }
| '(' bool_exp ')' { $$ = ; }
;
assignment: identifier '=' bool_exp { updateSymbolVal(, ); printf("> %c <- %i\n> ", , ); } ;
%%
void print(int num) {
printf("> Result: %i\n< ", num);
}
int computeSymbolIndex(char token) {
int idx = -1;
if (islower(token)) {
idx = token - 'a' + 26;
}
else if (isupper(token)) {
idx = token - 'A';
}
return idx;
}
/* Returns the value of a given symbol */
int symbolVal(char symbol) {
int bucket = computeSymbolIndex(symbol);
return symbols[bucket];
}
void updateSymbolVal(char symbol, int val) {
int bucket = computeSymbolIndex(symbol);
symbols[bucket] = val;
}
int main(void) {
printf("Calculator made with lex and yacc\n");
printf("Usage: <Arithmetic or boolean expression> <semicolon>\n");
printf("e.g: 2+2;\n\n< ");
return yyparse();
}
void yyerror(char *s) { fprintf(stderr, "Error: %s\n", s); }
运算符应该是令牌。所以你会得到一个 Lex 扫描仪:
"==" { return EQUAL; }
等等。像现在使用 '=' '='
.
在 Yacc 文件中,您可以使用 %left TOKEN
和 %right TOKEN
定义运算符的关联性。您放置它们的顺序决定了它们的优先级(参见 this post 或 yacc
手册)。