如何在Flex(词法分析器)中定义数字格式?

时间:2015-11-26 15:28:23

标签: c compiler-construction flex-lexer lex lexical-analysis

我需要什么:

可接受> 1234& 12.34

错误(不可接受)> 12.34.56

Scanner.L:

      ...
%%

[0-9]+                printf("Number ");
[0-9]+"."[0-9]+       printf("Decimal_Number ");
"."                   printf("Dot "):

%%
      ...

编译后&跑:

Input :
1234    12.34    12.34.65

Output :
Number    Decimal_Number      Decimal_Number Dot Number

如何打印Error而不是Decimal_Number Dot Number(或者只是忽略它)?

是否可以在&之前定义space以数字作为分隔符?

3 个答案:

答案 0 :(得分:2)

通常认为在解析器而不是扫描程序中检测12.34.56之类的错误会更好。但是也有一个论点是你可以通过词汇检测错误来产生更好的错误信息。

如果你想这样做,你可以使用两种模式;第一个检测到正确的数字,第二个检测到更大的字符串集,包括所有错误的字符串(但不是任何可能合法的字符串)。这取决于(f)lex的匹配行为:它总是接受最长匹配,如果最长令牌与两个或多个规则匹配,则它使用第一个匹配规则。

例如,假设您希望自己接受点为'.',数字为NUMBER标记,并在具有多个点的数字字符串上产生错误。你可以用三条规则来做到这一点:

  /* If the token is just a dot, match it here */
\.                             { return '.';    }
  /* Match integers without decimal points */
[[:digit:]]+                   { return INTEGER; }
  /* If the token is a number including a decimal point,
   * match it here. This pattern will also match just '.',
   * but the previous rules will be preferred.) */
[[:digit:]]*\.[[:digit:]]*     { return FLOAT; }
  /* This rule matches any sequence of dots and digits.
   * That will also match single dots and correct numbers, but
   * again, the previous rules are preferred. */
[.[:digit:]]+                  { /* signal error */
                                 return BADNUMBER; }

您需要非常小心上述解决方案。例如,最后一条规则将匹配.....,这可能是有效的令牌(甚至是.令牌的有效序列。)

例如,假设您的语言允许"范围"像4 .. 17这样的表达式(意思是4到17之间的整数列表,或者其中的一些)。您的用户可能希望4..17被接受为范围表达式,但即使您添加规则,上述内容也会产生BADNUMBER错误

".."                           { return RANGE; }

开头,因为4..会在扫描的前一个点匹配BADNUMBER

为了避免错误警报,我们需要修改BADNUMBER规则以避免匹配包含两个(或更多)连续点的字符串。我们还需要确保4..17不会被4.作为.17后跟.。 (可以通过坚持"." { return '.'; } ".." { return RANGE; } "..." { return ELLIPSIS; } 既不开始不结束数字令牌来避免第二个问题,但这可能会使一些用户烦恼。)

所以,我们从实际的点令牌开始:

..

为了避免匹配.之后的数字,我们可以使用flex的尾随上下文运算符。在这里,只有当字符串后跟.以外的其他内容时,我们才会识别由[[:digit:]]+ { return INTEGER; } /* Change * to + so that we don't do numbers ending with . */ [[:digit:]]*(\.[[:digit:]]+)? { return FLOAT; } /* Numbers which end with dot not followed by dot */ [[:digit:]]+\./[^.] { return FLOAT; } 作为数字终止的数字序列:

[[:digit:]]*(\.[[:digit:]]+)+  { return BADNUMBER; }
[[:digit:]]*(\.[[:digit:]]+)+\./[^.] { return BADNUMBER; }

现在我们需要修复错误规则。首先,我们将其限制为识别每个点后跟一个数字的字符串。然后,类似于上面的说法,我们确实匹配了一个尾随点后面没有另一个点的情况:

configure(AuthenticationManagerBuilder)

答案 1 :(得分:1)

这不是词法分析员的责任,而是解析器(yacc或bison)的责任。如果您将.定义为有效符号,则毫无疑问

12.34.56

被标记为

Decimal_Number Dot Number

关键是解析器没有接受该令牌序列的规则,因此稍后会引发错误。通常会忽略空格,因此强制数字之间的空格是没有意义的,尤其是在您可能12.34+56.78不会被标记为Decimal_Number Binary_Operator Decimal_Number的情况下,因为它没有空格。

答案 2 :(得分:0)

您可以查看我的程序来处理您的问题。但是当您尝试使用lex时,您应该知道无论何时匹配任何情况,它都能正常工作。 现在改变如下:

%%

[0-9]+                {printf("Number ");}
[0-9]+[.][0-9]*[.]+[0-9|.]*       {printf("error ");}
[0-9]+[.][0-9]+       {printf("Decimal_Number ");}
%%

现在程序可以正常工作。

Input :
1234    12.34    12.34.65

Output :
Number    Decimal_Number     Error