我正在用Ubuntu OS编写解析器和扫描器。在我的弹性代码"scanner.l"中,我有一个标识符令牌和BOOL_LITERAL令牌。标识符是任何单词,BOOL_LITERAL为真或假。 在我的野牛代码"parser.y"中,我有语法,它应该能够通过初级生产进行BOO_LITERAL。
但是,代码未按预期工作。这是错误
这是我的所有文件:
扫描仪.l
%{
#include <string>
#include <vector>
using namespace std;
#include "listing.h"
#include "tokens.h"
%}
%option noyywrap
ws [ tr]+
comment (--.*n)|//.*n
line [n]
digit [0-9]
int {digit}+
real {int}"."{int}([eE][+-]?{digit})?
boolean ["true""false"]
punc [(),:;]
addop ["+""-"]
mulop ["*""/"]
relop [="/=">">=""<="<]
id [A-Za-z][A-Za-z0-9]*
%%
{ws} { ECHO; }
{comment} { ECHO; nextLine();}
{line} { ECHO; nextLine();}
{relop} { ECHO; return(RELOP); }
{addop} { ECHO; return(ADDOP); }
{mulop} { ECHO; return(MULOP); }
begin { ECHO; return(BEGIN_); }
boolean { ECHO; return(BOOLEAN); }
end { ECHO; return(END); }
endreduce { ECHO; return(ENDREDUCE); }
function { ECHO; return(FUNCTION); }
integer { ECHO; return(INTEGER); }
real { ECHO; return(REAL); }
is { ECHO; return(IS); }
reduce { ECHO; return (REDUCE); }
returns { ECHO; return(RETURNS); }
and { ECHO; return(ANDOP); }
{boolean} { ECHO; return(BOOL_LITERAL); }
{id} { ECHO; return(IDENTIFIER);}
{int} { ECHO; return(INT_LITERAL); }
{real} { ECHO; return(REAL_LITERAL); }
{punc} { ECHO; return(yytext[0]); }
. { ECHO; appendError(LEXICAL, yytext); }
%%
解析器.y
%{
#include <string>
using namespace std;
#include "listing.h"
int yylex();
void yyerror(const char* message);
%}
%error-verbose
%token INT_LITERAL REAL_LITERAL BOOL_LITERAL
%token IDENTIFIER
%token ADDOP MULOP RELOP ANDOP
%token BEGIN_ BOOLEAN END ENDREDUCE FUNCTION INTEGER IS REDUCE RETURNS REAL
%%
function:
function_header optional_variable body ;
function_header:
FUNCTION IDENTIFIER RETURNS type ';' ;
parameters:
parameters ',' |
parameter ;
parameter:
IDENTIFIER ':' type |
;
optional_variable:
variable |
;
variable:
IDENTIFIER ':' type IS statement_ ;
type:
INTEGER |
BOOLEAN |
REAL ;
body:
BEGIN_ statement_ END ';' ;
statement_:
statement ';' |
error ';' ;
statement:
expression |
REDUCE operator reductions ENDREDUCE ;
operator:
ADDOP |
MULOP ;
reductions:
reductions statement_ |
;
expression:
expression ANDOP relation |
relation ;
relation:
relation RELOP term |
term;
term:
term ADDOP factor |
factor ;
factor:
factor MULOP primary |
primary ;
primary:
'(' expression ')' |
INT_LITERAL |
REAL_LITERAL |
BOOL_LITERAL |
IDENTIFIER ;
%%
void yyerror(const char* message)
{
appendError(SYNTAX, message);
}
int main(int argc, char *argv[])
{
firstLine();
yyparse();
lastLine();
return 0;
}
Other associated files:
列出.h
enum ErrorCategories {LEXICAL, SYNTAX, GENERAL_SEMANTIC, DUPLICATE_IDENTIFIER,
UNDECLARED};
void firstLine();
void nextLine();
int lastLine();
void appendError(ErrorCategories errorCategory, string message);
listing.cc
#include <cstdio>
#include <string>
using namespace std;
#include "listing.h"
static int lineNumber;
static string error = "";
static int totalErrors = 0;
static void displayErrors();
void firstLine()
{
lineNumber = 1;
printf("n%4d ",lineNumber);
}
void nextLine()
{
displayErrors();
lineNumber++;
printf("%4d ",lineNumber);
}
int lastLine()
{
printf("r");
displayErrors();
printf(" n");
return totalErrors;
}
void appendError(ErrorCategories errorCategory, string message)
{
string messages[] = { "Lexical Error, Invalid Character ", "",
"Semantic Error, ", "Semantic Error, Duplicate Identifier: ",
"Semantic Error, Undeclared " };
error = messages[errorCategory] + message;
totalErrors++;
}
void displayErrors()
{
if (error != "")
printf("%sn", error.c_str());
error = "";
}
马基尔
compile: scanner.o parser.o listing.o
g++ -o compile scanner.o parser.o listing.o
scanner.o: scanner.c listing.h tokens.h
g++ -c scanner.c
scanner.c: scanner.l
flex scanner.l
mv lex.yy.c scanner.c
parser.o: parser.c listing.h
g++ -c parser.c
parser.c tokens.h: parser.y
bison -d -v parser.y
mv parser.tab.c parser.c
mv parser.tab.h tokens.h
listing.o: listing.cc listing.h
g++ -c listing.cc
注意:我必须再次运行"makeile","bison -d parser.y",最后运行"makefile"。然后,我运行以下命令"./compile
请帮助我理解为什么我会收到语法错误。
@SoronelHaetir肯定已经确定了解析器的问题之一。但是该问题无法创建图像中显示的语法错误消息。[注1]您的语法允许标识符位于与布尔文字完全相同的位置,因此true
实际上被扫描为标识符的事实不会在以true and
开头的表达式中产生语法错误。(换句话说,x and...
将被解析为相同的内容。
问题实际上是您将8.E+1
用作数字文字。您的REAL_LITERAL
规则使用该模式
{int}"."{int}([eE][+-]?{digit})?
这与8.E+1
不匹配,因为没有{int}
遵循.
.所以当扫描器到达输入8.E+1
时,它会产生INT_LITERAL
8
,这是最长的匹配。当它被要求输入下一个令牌时,它首先看到一个.
,但这与任何模式都不匹配,因此它使用默认的回退操作(ECHO
),然后继续到下一个与IDENTIFIER
模式匹配的字符(E
)。和输入
true and 8 E ...
确实是一个语法错误:8 后面有一个意外的标识符,这就是 Bison 报告的内容。
除了修复真实文字的模式之外,你应该确保对无法识别的字符做一些明智的事情;flex的默认操作 - 基本上只是忽略无法匹配任何模式的字符 - 没有多大用处,特别是在调试中(我认为上面的解释证明)。
您的模式还有许多其他问题,涉及对字符类语法的相同误解,如布尔文字模式所示。这向我表明,在将词法扫描器挂接到解析器之前,您没有尝试测试它。这是编写解析器的重要步骤;如果你的词法扫描器没有返回你期望它返回的标记,你将在试图找出语法中可能存在哪些错误时会遇到很多麻烦。
您可能会发现此答案中概述的调试技术很有用。(该帖子也有指向flex和野牛手册的链接。Flex 手册的第 6 节是 flex 模式语法的简短但完整的指南,您可能需要花几分钟时间阅读它。
笔记
- 请将错误消息的文本复制并粘贴到您的问题中,而不是使用显示屏幕截图的图像。例如,图像很难在智能手机上阅读,或者对于依赖屏幕阅读器的人来说也是如此。而且不可能将屏幕截图的一部分复制到答案中,我更愿意在这里这样做。
你的布尔模式应该是"true"|"false"而不是["true"false"]。
老实说,你的模式设置方式很奇怪。是否有理由不使用:
...
%%
"true" { /* */ return BOOL_LITERAL; }
"false { /* */ return BOOL_LITERAL; }
当您不尝试匹配文字但在这里时,模式是有意义的。