5

我正在学习编译器构造课程,我目前的任务是为我们正在实现的语言编写词法分析器。我不知道如何满足词法分析器必须识别连接标记的要求。也就是说,没有用空格分隔的标记。例如:字符串39if应该被识别为数字39和关键字if。同时,词法分析器exit(1)在遇到无效输入时也必须这样做。

我拥有的代码的简化版本:

%{
#include <stdio.h>
%}

%option main warn debug

%%

if      |
then    |
else    printf("keyword: %s\n", yytext);

[[:digit:]]+    printf("number: %s\n", yytext);

[[:alpha:]][[:alnum:]]*     printf("identifier: %s\n", yytext);

[[:space:]]+    // skip whitespace
[[:^space:]]+   { printf("ERROR: %s\n", yytext); exit(1); }

%%

当我运行它(或我的完整版本)并将其传递给 input39if时,错误规则匹配并且输出为ERROR: 39if,当我希望它是:

number: 39
keyword: if

(即,就像我39 if作为输入输入一样。)

根据手册,我有一种预感,原因是错误规则匹配的可能输入比数字和关键字规则更长,而 flex 会更喜欢它。也就是说,我不知道如何解决这种情况。编写一个将拒绝所有非错误输入的显式正则表达式似乎是不可行的,而且我不知道如何编写“catch-all”规则来处理词法分析器错误。

更新:我想我可以制定包罗万象的规则,. { exit(1); }但我想获得一些比“我在第 1 行感到困惑”更好的调试输出。

4

1 回答 1

4

你是对的,你应该只匹配一个“任何”字符作为后备。获取有关解析所在行的信息的“标准”方法是使用该--bison-bridge选项,但这可能有点痛苦,特别是如果您不使用bison. 还有很多其他方法——例如,在手册中查看指定你自己的 i/o 函数的方法——但最简单的恕我直言是使用开始条件:

%x LEXING_ERROR
%%
// all your rules; the following *must* be at the end
.                 { BEGIN(LEXING_ERROR); yyless(1); }
<LEXING_ERROR>.+  { fprintf(stderr,
                            "Invalid character '%c' found at line %d,"
                            " just before '%s'\n",
                            *yytext, yylineno, yytext+1);
                    exit(1);
                  }

注意:确保您在规则中忽略了空格。该模式.+匹配任何数字,但至少匹配一个非换行符,或者换句话说,直到当前行的末尾(它将强制 flex 读取那么远,这应该不是问题)。yyless(n)按字符备份读取指针n,因此在.规则匹配后,它将重新扫描该字符,从而产生(希望)半合理的错误消息。(如果您的输入是多字节的,或者有奇怪的控制字符,这将是不合理的,因此您可以编写更仔细的代码。取决于您。如果错误位于行尾,也可能不合理,所以您可能还想编写一个更仔细的正则表达式来获取更多上下文,甚至可能限制读取的转发字符的数量。这里有很多选项。)

在 flex 手册中查找开始条件以获取有关%xBEGIN

于 2013-04-16T03:22:06.683 回答