Linux 用于生成文件的Lex analyzer不生成包含词法错误消息的程序列表
我正在尝试构建一个lex分析器,该分析器生成一个程序列表,其中的词法错误消息包含在它们出现的行之后。换句话说,如果读取的字符无法启动令牌,则将其视为错误。它还应该生成一个包含lexeme令牌对的文件,以便验证分析器是否工作。我可以得到一个输出文件,但它不能正常工作,因为当我试图运行它时,它只会给我一个命令屏幕,就像我在文件中工作一样。以下是用于读取输入文本的扫描仪文件的代码:Linux 用于生成文件的Lex analyzer不生成包含词法错误消息的程序列表,linux,ubuntu,compiler-construction,flex-lexer,lex,Linux,Ubuntu,Compiler Construction,Flex Lexer,Lex,我正在尝试构建一个lex分析器,该分析器生成一个程序列表,其中的词法错误消息包含在它们出现的行之后。换句话说,如果读取的字符无法启动令牌,则将其视为错误。它还应该生成一个包含lexeme令牌对的文件,以便验证分析器是否工作。我可以得到一个输出文件,但它不能正常工作,因为当我试图运行它时,它只会给我一个命令屏幕,就像我在文件中工作一样。以下是用于读取输入文本的扫描仪文件的代码: %{ #include <stdio.h> #include <ctype.h> #inc
%{
#include <stdio.h>
#include <ctype.h>
#include "tokens.h"
void toTitle(char* yytext, int yyleng);
%}
%option noyywrap
ws [ \t\r\n]+
quoted \".*\"
letter [A-Za-z]
digit [0-9]
word {letter}+(\-{letter}+)?
number {digit}+
punc [,:;()]
begin { ECHO; return(begin);}
boolean { ECHO; return(BOOLEAN);}
else { ECHO; return(ELSE); }
end { ECHO; return(END); }
endif void toTitle(char* yytext, int yyleng){ ECHO; return(ENDIF); }
function { ECHO; return(FUNCTION); }
if { ECHO; return(IF); }
is { ECHO; return(IS); }
integer { ECHO; return(INTEGER); }
real { ECHO; return(REAL); }
returns { ECHO; return(RETURNS); }
then { ECHO; return(THEN); }
line [\n]
%%
"&&" { return(LOGOPAND); }
"||" { return(LOGOPOR); }
"!=" { return(LOGOPNOT); }
[ \t\n] ;
{ws} { ECHO; }
"<" { ECHO; return(RELOP); }
"=" { ECHO; return(RELOP); }
"/=" { ECHO; return(RELOP); }
">" { ECHO; return(RELOP); }
">=" { ECHO; return(RELOP); }
"<=" { ECHO; return(RELOP); }
"*" { ECHO; return(MULTOP); }
"/" { ECHO; return(MULTOP); }
"+" { ECHO; return(ADDOP); }
"-" { ECHO; return(ADDOP); }
"true" { ECHO; return(BOOLLITERAL); }
"false" { ECHO; return(BOOLLITERAL); }
{digit} { ECHO; return(I_LITERAL); }
{digit}+"."{digit}* { ECHO; return(R_LITERAL); }
begins { ECHO; return(BEGINS); }
{punc} { ECHO; return yytext[0]; }
{quoted} { ECHO; }
{word} {toTitle(yytext, yyleng); }
{number} { ECHO; }
%%
void toTitle(char* yytext, int yyleng)
{
}
void tokenCount(int token)
{
while (token = yylex())
fprintf(yyout, "%d %s\n", token, yytext);
}
int main() {
while (yylex());
return 0;
}
我的输出应该是这样的:
1 -- Simple program with one function
2
3 function main a: integer returns integer;
4 b: integer is a * 2;
5 begin
6 if a <= 0 then
7 b + b;
8 else
9 b * b;
10 endif;
11 end;
Compiled Successfully
1——具有一个函数的简单程序
2.
3函数主a:整数返回整数;
4b:整数是a*2;
5开始
6如果a我注意到这是您针对同一问题提出的第三个问题,并且怀疑您可能不完全理解如何完成此任务,或者您迄今为止看到的文档和答案。Stackoverflow提供了关于形成问题的最佳方式的指导和标准,以从这里的许多世界级专家那里获得最佳价值和服务,例如:。我知道你可能是这方面的初学者,就你的问题而言,学习对你是有利的。我将以您的代码为例,演示如何简化问题,从而获得对问题和最终解决方案的良好描述
代码的问题与@rici在您的“该lex文件看起来像是使用不同样式从随机片段粘贴到一起”的注释中指出的问题相同
让我们回到第页,看看flex程序的总体结构:
definitions
%%
rules
%%
user code
%%
行的位置将代码分为三个部分,因此您在%%
之前放置的内容和在%%
之后放置的内容非常重要
现在@nlu在回答你最后一个问题时写道:
ECHO是一个特殊语句,只能在actions部分使用
然后你回答说:
我通过将所有保留字及其操作移到%%
语法之前的第一部分来更正代码
不幸的是,您误读了该建议,并在声明部分留下了规则/操作部分的代码。不幸的是,这并没有导致flex向您提供任何有用的消息,因为它仍然是一个有意义的flex程序;只是不是你期待的那个
为了澄清,您不能在第一个%%
之前执行任何操作,包括回显
,因为这样它将位于定义部分。它们必须在第一个%%
之后,因此位于规则/操作部分。因此,所有这些线路都位于错误的位置:
begin { ECHO; return(begin);}
boolean { ECHO; return(BOOLEAN);}
else { ECHO; return(ELSE); }
end { ECHO; return(END); }
endif void toTitle(char* yytext, int yyleng){ ECHO; return(ENDIF); }
function { ECHO; return(FUNCTION); }
if { ECHO; return(IF); }
is { ECHO; return(IS); }
integer { ECHO; return(INTEGER); }
real { ECHO; return(REAL); }
returns { ECHO; return(RETURNS); }
then { ECHO; return(THEN); }
你怎么能自己调试呢?正如其在SO帮助页面中所建议的:简化。我将举例说明如何做到这一点。如果您将问题简化为只有一个关键字的语言,让我们说begin
和一些空格,并删除所有其他关键字和符号的所有其他行,那么将有一个更简单的问题需要解决。让我们在您的代码中尝试以下操作:
%option noyywrap
ws [ \t\r\n]+
begin { ECHO; return(begin);}
line [\n]
%%
[ \t\n] ;
{ws} { ECHO; }
begins { ECHO; return(BEGINS); }
%%
int main() {
while (yylex());
return 0;
}
您会注意到,我刚刚删除了所有与其他关键字和符号相关的行,因为它们将图片与一堆额外的行混淆。这正是专家和专业程序员在解决日常问题时所做的。你认为我们没有找到虫子的灵媒吗?:-)这是伴随着练习而来的技能
现在,专注于这个更简单的程序,我们可以看到一些东西。顺便说一下,它确实可以编译和运行,而且它的所有代码都是您的(只是更简单)。如果我们运行它,关键字begins
会得到ECHO
ed,但关键字begin
不会。这里有一个线索。如果将开始
的行移到%%
的下方,它将与开始
行一样工作。但是为什么flex接受了这个糟糕的程序而没有给你一个有用的错误呢?这是因为根据flex正则表达式表示法,该行仍然是词素的有效定义。您定义的是一个名为begin
(使用规则部分中的符号{begin}
访问)的词素,它被定义为与字符串“{ECHO;return(begin);}”匹配。但是,由于您从未键入该字符串,也从未使用过名称{begin}
,因此该定义片段从未被使用
还有一个问题:你的语言真的有一个名为begin
的关键字和另一个名为begins
的关键字吗。我觉得很可疑。也许是另一个bug?
同样,我们可以看到同样的空白。您已尝试在三个位置匹配换行符\n
。这会令人困惑,因为您无法确定遇到换行符时flex将执行哪些定义和操作。由于您希望在某个点对行进行编号,这可能会给您带来问题。您还告诉它忽略和ECHO
whitespace。是哪一个?它不能两者兼而有之。从您的示例输出中,您可能希望它们得到响应。对简单的程序进行所有这些修复,我们得到以下结果:
%option noyywrap
ws [ \t\r]+
line [\n]
%%
{ws} { ECHO; }
begin { ECHO; return(BEGIN); }
%%
int main() {
while (yylex());
return 0;
}
它适用于只包含关键字begin
的简单语言。我们现在所要做的就是慢慢地、小心地把其他部分放回去。接下来,让我们将关键字endif
添加到代码中,我们得到:
%option noyywrap
ws [ \t\r]+
line [\n]
%%
{ws} { ECHO; }
begin { ECHO; return(BEGIN); }
endif void toTitle(char* yytext, int yyleng){ ECHO; return(ENDIF); }
%%
int main() {
while (yylex());
return 0;
}
但是,此不会编译。当您从其他人的计算机上对代码进行黑客攻击时,这段代码void-toTitle(char*yytext,int-yyleng)
看起来像是错误的粘贴
%option noyywrap
ws [ \t\r]+
line [\n]
%%
{ws} { ECHO; }
begin { ECHO; return(BEGIN); }
endif void toTitle(char* yytext, int yyleng){ ECHO; return(ENDIF); }
%%
int main() {
while (yylex());
return 0;
}