在 flex 中检查错误的标识符模式
Checking wrong identifier patterns in flex
我只是想学习 flex,这里是 flex 中用于检测标识符和数字的示例代码。我想通过识别错误的标识符和数字模式(例如:1var、12.2.2、5.等)来改进代码。我将如何检测它?我必须在代码中进行哪些更改?
我的示例代码如下:
ID [a-zA-z][a-zA-z0-9]*
DIGIT [0-9]
%%
[\t]+
{ID} {printf("\n identifier found");}
{DIGIT} {printf("\nDigit found");}
. {}
%%
int main(int argc, char *argv[]){
yylex();
}
这不是一个微不足道的问题,因为在词法分析器中检测到哪些错误是语言处理系统整个设计以及语言句法和词汇结构的本质的重要组成部分。有些元素在检查时可能看起来像是词汇错误,但事实证明可能并非如此。这实际上取决于语言的性质;例如,在 Fortran 中,空格没有意义,还有著名的例子:
DO 10 I = 1.10
这是关键字 DO
、标签 10
、标识符 I
、运算符 =
和数字 1.10
吗?其实就是标识符DO10I
...等等;而
DO 10 I = 1,10
是否有关键字 DO
...
所以有时候,当看到序列 123abc
时,您不能自动假设它只是一个无效的标识符。有时最好将 return 作为两个有效标记 NUMBER
和 IDENTIFIER
并将其留给解析器报告由此产生的任何错误。使用此方法时唯一需要注意的困难区域是在浮点数常量中指定指数时以及使用整数范围时。指数使用的一个例子是:
-1234.457E+12
它在数字中嵌入了一个字母,需要将其 return 编辑为某种 NUMBER
标记。同样,符号运算符的重载会导致词法分析错误检测出现问题。在前面的数字中它有两个符号 -
和 +
。如果它们被识别为数字的一部分,那么符号 -
和 +
何时被识别为 SUBTRACT
和 ADD
标记?以这个表达式为例:
i=i-1;
这是IDENTIFIER
、EQUALS
、IDENTIFIER
、NUMBER
吗?不,当然不。所以这意味着我们不能总是假设 -1
只是一个 NUMBER
.
前面提到的整数范围,在许多语言(尤其是 Pascal)中表示为 1..8
,使用两个点来表示上限和下限,在处理浮点表达式如 1.2
.
所以,只是这个问题,"How do I checked for ill-formed identifiers and numbers in a lexer?" 是相当沉重的,并且表明它可能代表了一个没有完全吸收主题领域的人。通常在 class 测试中发布这样的问题,因为它们是教师查看学生是否拥有更深层次的语言处理知识的好方法,或者只是以表面的方式回答它,并尝试编写模式对于此类对象。
正如刚才提到的,天真的答案就是编写正则表达式模式来匹配无效词位的示例。
例如,我可以添加模式:
[0-9]+\.[0-9]+(\.[0-9]+)+ {printf("Bad float: %s\n", yytext);}
[0-9]+[a-zA-Z][a-zA-Z0-9]+ {printf("Bad Identifier: %s\n", yytext);}
但大多数编译器通常不会这样做。大多数编译器检测到的唯一词法错误是未闭合的字符串和注释。这也是为什么大多数语言不允许在字符串中换行的原因,因为这样可以很容易地检测到未闭合的字符串。
我只是想学习 flex,这里是 flex 中用于检测标识符和数字的示例代码。我想通过识别错误的标识符和数字模式(例如:1var、12.2.2、5.等)来改进代码。我将如何检测它?我必须在代码中进行哪些更改?
我的示例代码如下:
ID [a-zA-z][a-zA-z0-9]*
DIGIT [0-9]
%%
[\t]+
{ID} {printf("\n identifier found");}
{DIGIT} {printf("\nDigit found");}
. {}
%%
int main(int argc, char *argv[]){
yylex();
}
这不是一个微不足道的问题,因为在词法分析器中检测到哪些错误是语言处理系统整个设计以及语言句法和词汇结构的本质的重要组成部分。有些元素在检查时可能看起来像是词汇错误,但事实证明可能并非如此。这实际上取决于语言的性质;例如,在 Fortran 中,空格没有意义,还有著名的例子:
DO 10 I = 1.10
这是关键字 DO
、标签 10
、标识符 I
、运算符 =
和数字 1.10
吗?其实就是标识符DO10I
...等等;而
DO 10 I = 1,10
是否有关键字 DO
...
所以有时候,当看到序列 123abc
时,您不能自动假设它只是一个无效的标识符。有时最好将 return 作为两个有效标记 NUMBER
和 IDENTIFIER
并将其留给解析器报告由此产生的任何错误。使用此方法时唯一需要注意的困难区域是在浮点数常量中指定指数时以及使用整数范围时。指数使用的一个例子是:
-1234.457E+12
它在数字中嵌入了一个字母,需要将其 return 编辑为某种 NUMBER
标记。同样,符号运算符的重载会导致词法分析错误检测出现问题。在前面的数字中它有两个符号 -
和 +
。如果它们被识别为数字的一部分,那么符号 -
和 +
何时被识别为 SUBTRACT
和 ADD
标记?以这个表达式为例:
i=i-1;
这是IDENTIFIER
、EQUALS
、IDENTIFIER
、NUMBER
吗?不,当然不。所以这意味着我们不能总是假设 -1
只是一个 NUMBER
.
前面提到的整数范围,在许多语言(尤其是 Pascal)中表示为 1..8
,使用两个点来表示上限和下限,在处理浮点表达式如 1.2
.
所以,只是这个问题,"How do I checked for ill-formed identifiers and numbers in a lexer?" 是相当沉重的,并且表明它可能代表了一个没有完全吸收主题领域的人。通常在 class 测试中发布这样的问题,因为它们是教师查看学生是否拥有更深层次的语言处理知识的好方法,或者只是以表面的方式回答它,并尝试编写模式对于此类对象。
正如刚才提到的,天真的答案就是编写正则表达式模式来匹配无效词位的示例。
例如,我可以添加模式:
[0-9]+\.[0-9]+(\.[0-9]+)+ {printf("Bad float: %s\n", yytext);}
[0-9]+[a-zA-Z][a-zA-Z0-9]+ {printf("Bad Identifier: %s\n", yytext);}
但大多数编译器通常不会这样做。大多数编译器检测到的唯一词法错误是未闭合的字符串和注释。这也是为什么大多数语言不允许在字符串中换行的原因,因为这样可以很容易地检测到未闭合的字符串。