我试图坐在这里阅读有关YACC如何使用lex文件的教程,但是我不确定我是否可以绕过它。我理解它是用于读取实际的输入文件并确定添加或减少等函数是否格式正确,但这是如何工作的?我理解Lex文件是如何工作的,并构建了一个根据文件中的内容返回定义变量的文件。
如果我有一个非常简单的程序,我将如何分析这个测试编程语言的第一行。我们假设“program”是lex中定义的值,以及“is”,“var”,“begin”,“+”,“print”,“;”,“,”和“end”。
如何读取yacc文件以便读取前几行?
测试文件:
program xyz is
var a, b, c
begin
a = 2;
b = 3;
c = a + b;
print c
end
Yaccer.y
%token EOFNUM 0
%token SEMINUM 1
%token LPARENNUM 2
%token RPARENNUM 3
%token ICONSTNUM 4
%token BEGINNUM 5
%token PROGRAMNUM 6
%token MINUSNUM 7
%token TIMESNUM 8
%token VARNUM 9
%token COMMANUM 10
%token IDNUM 11
%token ENDNUM 12
%token ISNUM 13
%token PLUSNUM 14
%token DIVNUM 15
%token PRINTNUM 16
%token EQUALNUM 17
%left '+' '-'
%left '*' '/'
%%
%%
#include "lex.yy.c"
#include <stdio.h>
yyerror(str)
char *str;
{ printf("yyerror: %s at line %d\n", str, yyline); }
main () {
if (!yyparse()) { printf("accept\n");}
else { printf("reject\n"); }
}
我知道需要为方程式定义一些%类型,但是我不知道如何使用类型和%left声明,或者即使这是正确的。我对如何分析第一行感到困惑。
答案 0 :(得分:1)
您需要创建一个lex文件和一个yacc文件。在lex文件中,您为每种类型的令牌定义单个令牌,而不是语法包含的令牌。然后你以适合yacc的BNF形式构造语法。对于您的简单输入,它看起来有点像这样。我认为print
语句之后没有;
这是一个错字,这个语法需要一个分号。
%token IDENTIFIER
%token PROGRAM
%token BEGIN
%token END
%token IS
%token VAR
%token PRINT
%token NUMBER
program
statementlist
statement
printstatement
assignstatement
expression
%%
program : PROGRAM IDENTIFIER IS VAR variables BEGIN statementlist END;
variables : IDENTIFIER | variables ',' IDENTIFIER;
statementlist : statement | statementlist statement;
statement : assignstatement | printstatement;
printstatement : PRINT IDENTIFIER ';';
assignstatement : IDENTIFIER '=' expression ';';
expression : value | expression '+' value;
value : NUMBER | IDENTIFIER;
%%
%left
和%right
是关联修饰符,在您的情况下并不是真正需要的。如果您使用与-
相同的优先级来支持+
,则需要使用它们。嗯,技术上并不是真的需要,但它们使语法更容易理解。
Yacc不容易理解,我推荐一个关于这个主题的教程。规则很快就会变成递归的,你在使用规则时必须有一定的心态。从最高阶语句开始,以增量方式逐步构建语法会更容易。创建一个只识别程序开始结束的解析器,然后随时使用这些功能。
测试和验证语法的好工具是找到的javascript解析器生成器here