'unrecognized rule' 和 'fatal parse error' 在 FLEX 上
'unrecognized rule' and 'fatal parse error' on FLEX
我必须使用 flex 和 bison 为简化的 Python 3 创建一个解析器,我得到这些 2 errors.terminal 说它们在我写的 78 行中的第 79 行。我还有来自 class 的其他 '.l' 示例,使用这种格式,它们工作正常
这是我写的
%option noyywrap
%{
#define YYSTYPE double
#include "scanner.tab.h"
#include <stdlib.h>
#include <string>
extern int flag;
extern int line;
%}
DELIMITER [ ]+|[/t]+
KEYWORD False|class|finally|is|return|None|continue|for|lambda|try|True|def|from|nonlocal|while|and|del|global|not|with|as|elif|if|or|yield|assert|else|import|pass|break|except|in|raise
OPERATOR ([+\-$@&|^~])|(\*{1,2})|(\/{1,2})|(<[=<]?)|(>[=>]?)|(==)|!
COMMENT #.+
IDENTIFIER [a-zA-Z_][a-zA-Z0-9_]*
ID_ERR [0-9]{IDENTIFIER}
STRINGESCAPESEQ [\].
SHORTSTRINGCHAR1 [^\'\n]*
SHORTSTRINGCHAR2 [^\"\n]*
SHORTSTRINGITEM1 {SHORTSTRINGCHAR1}|{STRINGESCAPESEQ}
SHORTSTRINGITEM2 {SHORTSTRINGCHAR2}|{STRINGESCAPESEQ}
STRING [']{SHORTSTRINGITEM1}*[']|(["]{SHORTSTRINGITEM2}*["])
STRING_ERR ['].[^'\n\t]*|["].[^"\n\t]*
BINDIGIT [01]
BININTEGER 0[bB]{BINDIGIT}+
BIN_ERR1 0[Bb]+{BINDIGIT}+
DIGIT [0-9]
NONZERODIGIT [1-9]
INTEGER {NONZERODIGIT}{DIGIT}*|[0]+
INT_ERR1 {INTEGER}[a-zA-Z]{DIGIT}
INT_ERR2 [-+]{INTEGER}
INT_ERR3 [0+]{INTEGER}
INTPART {DIGIT}+
EXPONENT [eE][+-]*{INTPART}
FRACTION [\.]{INTPART}
EXPONENTFLOAT ({INTPART}|{POINTFLOAT}){EXPONENT}
POINTFLOAT {INTPART}*{FRACTION}|{INTPART}[\.]
FLOATNUMBER {POINTFLOAT}|{EXPONENTFLOAT}
FLOAT_ERR_POINT {INTPART}*[\.]+{DIGIT}+[\.]*{DIGIT}*|{INTPART}[\.]+
FLOAT_ERR_SIGN ([-+]{FLOATNUMBER})
FLOAT_ERR_LETTER {FLOATNUMBER}[A-Za-z]+
IMAGINARYNUMBER ({FLOATNUMBER}|{INTPART})[jJ]
%%
{DELIMITER} { }
{KEYWORD} { return KEYWORD; }
{OPERATOR} { }
{COMMENT} { printf("Line %d: Found COMMENT\n", line); }
{IDENTIFIER} { printf("Line %d: Found IDENTIFIER %s\n", line, yytext); return IDENTIFIER; }
{ID_ERR} { printf("Line %d: !!ERROR!!\tWrong IDENTIFIER statement %s\n", line, yytext); return ID_ERR;}
{STRING} { printf("Line %d: Found STRING %s\n", line, yytext); return STRING; }
{STRING_ERR} { printf("Line %d: !!ERROR!!\tWrong STRING statement %s\n", line, yytext); return STRING_ERR;}
{BININTEGER} { printf("Line %d: Found BINARY INTEGER NUMBER %s\n", line, yytext); return BININTEGER; }
{BIN_ERR1} { printf("Line %d: !!ERROR!!\tWrong BINARY NUMBER statement, too many 'Bb's%s\n", line, yytext); return BIN_ERR1;}
{INTEGER} { printf("Line %d: Found INTEGER NUMBER %s\n", line, yytext); return INTEGER; }
{INT_ERR1} { printf("Line %d: !!ERROR!!\tWrong INT statement %s\n", line, yytext); return INT_ERR1;}
{INT_ERR2} { printf("Line %d: !!ERROR!!\tWrong INT statement, '+/-' found %s\n", line, yytext); return INT_ERR2;}
{INT_ERR3} { printf("Line %d: !!ERROR!!\tWrong INT statement, first digit(s) zeros %s\n", line, yytext); return INT_ERR3;}
{FLOATNUMBER} { printf("Line %d: Found FLOAT NUMBER %s\n", line, yytext); return FLOATNUMBER; }
{FLOAT_ERR_POINT} { printf("Line %d: !!ERROR!!\tWrong FLOAT statement, too many '.' %s\n", line, yytext); return FLOAT_ERR_POINT;}
{FLOAT_ERR_POINT} { printf("Line %d: !!ERROR!!\tWrong FLOAT statement, '+/-' FOUND %s\n", line, yytext); return FLOAT_ERR_SIGN;}
{FLOAT_ERR_LETTER { printf("Line %d: !!ERROR!!\tWrong FLOAT statement, letter FOUND %s\n", line, yytext); return FLOAT_ERR_LETTER;}
{IMAGINARYNUMBER} { printf("Line %d: Found IMAGINARY NUMBER %s\n", line, yytext); return IMAGINARYNUMBER; }
. { printf("Line %d: UNKNOWN TOKEN:%s", line, yytext); BEGIN(error);}
\n { line++; }
<<EOF>> { printf("#END OF FILE\n"); exit(0); }
完整的错误输出:
flex scanner.l
scanner.l:79: unrecognized rule
scanner.l:79: fatal parse error
第 74 行末尾缺少一个大括号:
{FLOAT_ERR_LETTER { printf("Line %d: !!ERROR!!\tWrong FLOAT statement, letter FOUND %s\n", line, yytext); return FLOAT_ERR_LETTER;}
^ <--- here
为了让这个答案对未来的读者有用,这是一个模糊的尝试,因为这个问题只是一个简单的错字,所以我是这样发现这个问题的:
for n in {57..79}; do head -n$n g.l | flex -o /dev/null -w || { echo $n; break; } done
大多数情况下,在 flex 输入结束后的那一行发生的致命错误是由于缺少大括号或其他类似问题造成的,但是校对整个文件是一件痛苦的事情,令人惊讶的是,很少有 IDE 能正确地语法颜色弹性文件。所以像上面这样的技巧可以节省大量时间。 (它并不总是那么简单;在这种情况下,没有任何动作跨越一行。)
修复该错误后,您会发现有几个模式无法匹配。无法匹配第 73 行,因为模式与第 72 行 ({FLOAT_ERR_POINT}
) 相同。第 65 行和第 66 行(BININTEGER
和 BIN_ERR1
)无法匹配,因为有问题的模式以 0B
开头后跟一个数字,也匹配 IDERR
,这是(奇怪的是) 一个数字后跟一个标识符。 (您的意思可能是 [[:digit:]]+{IDENTIFIER}
。)总的来说,您应该将错误模式放在末尾,这样它们永远不会优先于正确标记的模式。这也使得编写错误标记变得更加简单。 (此外,您需要将特定的错误模式放在更一般的错误模式之前,这样 BIN_ERR1
应该出现在 IDERR
之前。)
其他一些评论:
如果您想观看灵活匹配模式,请将 --debug
(或 -d
)添加到命令行,而不是在您的代码中散布 printf
命令。它可以更好地向您展示正在发生的事情,并且可以在不编辑整个文件的情况下打开和关闭。
<意见>
总的来说,在输入文件中过度使用 flex 宏并不是很有用。它实际上使规范更难阅读,因为您必须查找宏的每次使用。就个人而言,我只在需要多次使用宏时才使用宏,即便如此,如果它们只是隐藏内置字符 class(例如 [[:digit:]]
)的一种方式,我也不会使用。
意见>
我必须使用 flex 和 bison 为简化的 Python 3 创建一个解析器,我得到这些 2 errors.terminal 说它们在我写的 78 行中的第 79 行。我还有来自 class 的其他 '.l' 示例,使用这种格式,它们工作正常
这是我写的
%option noyywrap
%{
#define YYSTYPE double
#include "scanner.tab.h"
#include <stdlib.h>
#include <string>
extern int flag;
extern int line;
%}
DELIMITER [ ]+|[/t]+
KEYWORD False|class|finally|is|return|None|continue|for|lambda|try|True|def|from|nonlocal|while|and|del|global|not|with|as|elif|if|or|yield|assert|else|import|pass|break|except|in|raise
OPERATOR ([+\-$@&|^~])|(\*{1,2})|(\/{1,2})|(<[=<]?)|(>[=>]?)|(==)|!
COMMENT #.+
IDENTIFIER [a-zA-Z_][a-zA-Z0-9_]*
ID_ERR [0-9]{IDENTIFIER}
STRINGESCAPESEQ [\].
SHORTSTRINGCHAR1 [^\'\n]*
SHORTSTRINGCHAR2 [^\"\n]*
SHORTSTRINGITEM1 {SHORTSTRINGCHAR1}|{STRINGESCAPESEQ}
SHORTSTRINGITEM2 {SHORTSTRINGCHAR2}|{STRINGESCAPESEQ}
STRING [']{SHORTSTRINGITEM1}*[']|(["]{SHORTSTRINGITEM2}*["])
STRING_ERR ['].[^'\n\t]*|["].[^"\n\t]*
BINDIGIT [01]
BININTEGER 0[bB]{BINDIGIT}+
BIN_ERR1 0[Bb]+{BINDIGIT}+
DIGIT [0-9]
NONZERODIGIT [1-9]
INTEGER {NONZERODIGIT}{DIGIT}*|[0]+
INT_ERR1 {INTEGER}[a-zA-Z]{DIGIT}
INT_ERR2 [-+]{INTEGER}
INT_ERR3 [0+]{INTEGER}
INTPART {DIGIT}+
EXPONENT [eE][+-]*{INTPART}
FRACTION [\.]{INTPART}
EXPONENTFLOAT ({INTPART}|{POINTFLOAT}){EXPONENT}
POINTFLOAT {INTPART}*{FRACTION}|{INTPART}[\.]
FLOATNUMBER {POINTFLOAT}|{EXPONENTFLOAT}
FLOAT_ERR_POINT {INTPART}*[\.]+{DIGIT}+[\.]*{DIGIT}*|{INTPART}[\.]+
FLOAT_ERR_SIGN ([-+]{FLOATNUMBER})
FLOAT_ERR_LETTER {FLOATNUMBER}[A-Za-z]+
IMAGINARYNUMBER ({FLOATNUMBER}|{INTPART})[jJ]
%%
{DELIMITER} { }
{KEYWORD} { return KEYWORD; }
{OPERATOR} { }
{COMMENT} { printf("Line %d: Found COMMENT\n", line); }
{IDENTIFIER} { printf("Line %d: Found IDENTIFIER %s\n", line, yytext); return IDENTIFIER; }
{ID_ERR} { printf("Line %d: !!ERROR!!\tWrong IDENTIFIER statement %s\n", line, yytext); return ID_ERR;}
{STRING} { printf("Line %d: Found STRING %s\n", line, yytext); return STRING; }
{STRING_ERR} { printf("Line %d: !!ERROR!!\tWrong STRING statement %s\n", line, yytext); return STRING_ERR;}
{BININTEGER} { printf("Line %d: Found BINARY INTEGER NUMBER %s\n", line, yytext); return BININTEGER; }
{BIN_ERR1} { printf("Line %d: !!ERROR!!\tWrong BINARY NUMBER statement, too many 'Bb's%s\n", line, yytext); return BIN_ERR1;}
{INTEGER} { printf("Line %d: Found INTEGER NUMBER %s\n", line, yytext); return INTEGER; }
{INT_ERR1} { printf("Line %d: !!ERROR!!\tWrong INT statement %s\n", line, yytext); return INT_ERR1;}
{INT_ERR2} { printf("Line %d: !!ERROR!!\tWrong INT statement, '+/-' found %s\n", line, yytext); return INT_ERR2;}
{INT_ERR3} { printf("Line %d: !!ERROR!!\tWrong INT statement, first digit(s) zeros %s\n", line, yytext); return INT_ERR3;}
{FLOATNUMBER} { printf("Line %d: Found FLOAT NUMBER %s\n", line, yytext); return FLOATNUMBER; }
{FLOAT_ERR_POINT} { printf("Line %d: !!ERROR!!\tWrong FLOAT statement, too many '.' %s\n", line, yytext); return FLOAT_ERR_POINT;}
{FLOAT_ERR_POINT} { printf("Line %d: !!ERROR!!\tWrong FLOAT statement, '+/-' FOUND %s\n", line, yytext); return FLOAT_ERR_SIGN;}
{FLOAT_ERR_LETTER { printf("Line %d: !!ERROR!!\tWrong FLOAT statement, letter FOUND %s\n", line, yytext); return FLOAT_ERR_LETTER;}
{IMAGINARYNUMBER} { printf("Line %d: Found IMAGINARY NUMBER %s\n", line, yytext); return IMAGINARYNUMBER; }
. { printf("Line %d: UNKNOWN TOKEN:%s", line, yytext); BEGIN(error);}
\n { line++; }
<<EOF>> { printf("#END OF FILE\n"); exit(0); }
完整的错误输出:
flex scanner.l
scanner.l:79: unrecognized rule
scanner.l:79: fatal parse error
第 74 行末尾缺少一个大括号:
{FLOAT_ERR_LETTER { printf("Line %d: !!ERROR!!\tWrong FLOAT statement, letter FOUND %s\n", line, yytext); return FLOAT_ERR_LETTER;}
^ <--- here
为了让这个答案对未来的读者有用,这是一个模糊的尝试,因为这个问题只是一个简单的错字,所以我是这样发现这个问题的:
for n in {57..79}; do head -n$n g.l | flex -o /dev/null -w || { echo $n; break; } done
大多数情况下,在 flex 输入结束后的那一行发生的致命错误是由于缺少大括号或其他类似问题造成的,但是校对整个文件是一件痛苦的事情,令人惊讶的是,很少有 IDE 能正确地语法颜色弹性文件。所以像上面这样的技巧可以节省大量时间。 (它并不总是那么简单;在这种情况下,没有任何动作跨越一行。)
修复该错误后,您会发现有几个模式无法匹配。无法匹配第 73 行,因为模式与第 72 行 ({FLOAT_ERR_POINT}
) 相同。第 65 行和第 66 行(BININTEGER
和 BIN_ERR1
)无法匹配,因为有问题的模式以 0B
开头后跟一个数字,也匹配 IDERR
,这是(奇怪的是) 一个数字后跟一个标识符。 (您的意思可能是 [[:digit:]]+{IDENTIFIER}
。)总的来说,您应该将错误模式放在末尾,这样它们永远不会优先于正确标记的模式。这也使得编写错误标记变得更加简单。 (此外,您需要将特定的错误模式放在更一般的错误模式之前,这样 BIN_ERR1
应该出现在 IDERR
之前。)
其他一些评论:
如果您想观看灵活匹配模式,请将 --debug
(或 -d
)添加到命令行,而不是在您的代码中散布 printf
命令。它可以更好地向您展示正在发生的事情,并且可以在不编辑整个文件的情况下打开和关闭。
<意见>
总的来说,在输入文件中过度使用 flex 宏并不是很有用。它实际上使规范更难阅读,因为您必须查找宏的每次使用。就个人而言,我只在需要多次使用宏时才使用宏,即便如此,如果它们只是隐藏内置字符 class(例如 [[:digit:]]
)的一种方式,我也不会使用。
意见>