首页 > 解决方案 > 在 lex/flex 中标记整数与浮点数

问题描述

为了好玩,我正在自学一点 flex/bison。我正在为 1975 版的 MS Extended BASIC(扩展为“有字符串”)编写解释器。不过,我有点被一个问题难住了。

浮点数可以通过查找 a.E(etc) 来识别,然后故障转移到 int 否则。所以我做了这个...

[0-9]*[0-9.][0-9]*([Ee][-+]?[0-9]+)? {
                      yylval.d = atof(yytext);
                      return FLOAT;
                    }
[0-9]+ {
                      yylval.i = atoi(yytext);
                      return INT;
                    }

yylval 联合中的子字段是 .d 代表双精度,.i 代表 int 和 .s 代表字符串。

但也有可能您需要使用浮点数,因为该数字太大而无法存储在 int 中 - 在本例中是 16 位有符号数。

有没有办法在正则表达式中做到这一点?还是我必须在关联的 c 端代码中使用 if 执行此操作?

标签: regexlex

解决方案


如果您希望整数优先于浮点数(以便看起来像整数的文字是整数),那么您需要首先放置整数模式。(匹配最长的模式总是获胜,但如果两个模式都匹配相同的最长前缀,则第一个获胜。)所以你的基本大纲是:

integer-pattern     { /* integer rule */ }
float-pattern       { /* float rule */ }

您的 float 规则看起来很合理,但请注意,它将匹配单个.,可能后跟一个指数。很少有语言将孤独.视为浮点常量(该文字通常写为0:-))因此您可能希望将其更改为类似

[0-9]*([0-9]\.?|\.[0-9])[0-9]*([Ee][-+]?[0-9]+)

要使用正则表达式匹配适合 16 位有符号的非负整数int,您可以使用以下丑陋的模式:

0*([12]?[0-9]{1,4}|3(2(7(6[0-7]|[0-5][0-9])|[0-6][0-9]{2})|[0-1][0-9]{3}))

(F)lex 将生成有效的代码来实现这个正则表达式,但这并不一定是一个好主意。

笔记:

  1. 该模式识别具有冗余前导零的整数,例如09. 某些语言(如 C)认为这是无效的八进制文字,但我认为 Basic 没有这种限制。

  2. 该模式无法识别 32768,因为它太大而不能成为正整数。但是,负整数也不算大;-32768会很好的。这始终是解析整数文字的极端情况。如果您只是对整数文字进行词法分析,则可以通过为以 a 开头的文字使用单独的模式来轻松处理正限制和负限制之间的差异-,但在整数文字中包含符号不适合表达式解析器,因为它会产生不正确的的词法分析a-1。(-32768作为一个有效的整数文字也有点奇怪,而- 32768被分析为一个浮点表达式,其计算结果为-32768.0.) 这里真的没有好的解决方案,除非您的语言包含无符号整数文字(如 C),在这种情况下,您可以将 0 到 32767 的文字分析为有符号整数;从 32768 到 65535 作为无符号整数;并从 65536 及以上作为浮点数。


推荐阅读