【问题标题】:Flex & Bison: "true" being interpreted as and IDFlex & Bison:“真”被解释为和 ID
【发布时间】:2021-04-11 22:55:07
【问题描述】:

我正在 Ubuntu 操作系统中编写解析器和扫描器。在我的弹性代码“scanner.l”中,我有一个 IDENTIFIER 令牌和 BOOL_LITERAL 令牌。 IDENTIFIER 是任何单词,BOOL_LITERAL 是真或假。 在我的野牛代码“parser.y”中,我有一个语法,它应该能够通过初级生产获取 BOO_LITERAL。

但是,代码没有按预期工作。这是错误

这是我所有的文件:

scanner.l

%{
#include <string>
#include <vector>

using namespace std;

#include "listing.h"
#include "tokens.h"

%}

%option noyywrap

ws [ \t\r]+
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); }

%%

parser.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:

listing.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("%s\n", error.c_str());
    error = "";
}

ma​​keile

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 enter image description here

请帮助我了解为什么会出现语法错误。

【问题讨论】:

    标签: c linux ubuntu bison lex


    【解决方案1】:

    你的布尔模式应该是“true”|“false”而不是[“true”“false”]。

    老实说,你的模式设置方式很奇怪。有什么理由不使用:

    ...
    %%
    "true" { /* */ return BOOL_LITERAL; }
    "false { /* */ return BOOL_LITERAL; }
    

    当您不尝试匹配文字时,模式才有意义,但您就在这里。

    【讨论】:

    • 我更改了代码以遵守您的建议,它没有任何区别。我仍然遇到同样的错误。
    【解决方案2】:

    @SoronelHaetir 肯定有 identified one of the problems 与您的解析器。但是该问题无法创建出现在您的图像中的语法错误消息。 [注 1] 您的语法允许标识符与布尔文字在完全相同的位置,因此 true 实际上被扫描为标识符这一事实不会在以 true and 开头的表达式中产生语法错误。 (换句话说,x and... 的解析方式相同。)

    问题实际上是您将8.E+1 用作数字文字。 REAL_LITERAL 的规则使用了该模式

    {int}"."{int}([eE][+-]?{digit})?
    

    8.E+1 不匹配,因为在. 后面没有{int}。所以当扫描器到达输入8.E+1时,它会产生INT_LITERAL8,这是最长的匹配。当它被要求输入下一个令牌时,它首先看到一个.,但它与任何模式都不匹配,因此它使用默认的回退操作(ECHO),然后继续下一个字符(E)匹配IDENTIFIER 模式。和输入

    true and 8 E ...
    

    确实是语法错误:8 后面有一个意外的标识符,这就是 bison 报告的内容。

    除了修复真实文字的模式外,您还应该确保对无法识别的字符进行合理的处理; flex 的默认操作——基本上只是忽略不能匹配任何模式的字符——并没有多大用处,尤其是在调试中(我认为上面的解释表明了这一点)。

    您的模式还有许多其他问题,这些问题涉及与布尔文字模式中所示的字符类语法相同的误解。这向我表明,在将词法扫描器连接到解析器之前,您没有尝试测试它。这是编写解析器的重要步骤;如果您的词法扫描器没有返回您希望它返回的标记,那么您将很难找出语法中可能存在的错误。

    您可能会发现this answer 中概述的调试技术很有用。 (该帖子还包含指向 flex 和 bison 手册的链接。flex 手册的第 6 节是对 flex 模式语法的简短但完整的指南,您可能需要花几分钟时间阅读它。)

    注意事项

    1. 请将错误消息的文本复制并粘贴到您的问题中,而不是使用显示屏幕截图的图像。例如,图像很难在智能手机上阅读,或者对于依赖屏幕阅读器的人来说。而且不可能将屏幕截图的一部分复制到答案中,我本来希望在这里完成。

    【讨论】:

      猜你喜欢
      • 2018-08-13
      • 2011-10-01
      • 1970-01-01
      • 2013-10-24
      • 1970-01-01
      • 1970-01-01
      • 2015-06-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多