我正在设计一种语言,我想使用 .. 来定义整数范围。问题是 0..10 被标记为浮点数 0. 和 .10。
如何让 flex 支持这种语法?是不是就像让 0. 成为无效浮点数那么简单?
如果您不想使 0. 成为无效浮点数,您可以使用 Lex 尾随上下文:
[0-9]+[.]/[^.] { /* recognize <digits>. only if not followed by another . */ }
因此,该规则将根据尾随上下文不匹配而被拒绝,并且令牌仅作为整数常量匹配。然后下一个输入是
..
,它可以被识别为点点标记。
我现在必须接受我自己的建议了!
添加浮点支持的回归:
$ ./txr -v -l -c '@(bind a (1..3))'
spec:
(((bind a (1.0 0.3)))) # oops, should be (cons 1 3)
bindings:
nil
(a 1.0 0.3)
:)同样的问题。语言中的 DOTDOT 标记,以及可以以点开头并以点结尾的浮点数。
我提出的解决方案不会那么简单地应用,因为浮点标记与单个复杂的正则表达式匹配,其中小数点的匹配位于中间某处,在一些可选数字和指数部分之前。
lex
尾随上下文只能位于末尾。
有必要更改表达式,使其不将
123.
识别为有效标记,并使用具有尾随上下文的附加规则来识别 123.
。
实际代码的工作修复:
diff --git a/parser.l b/parser.l
index d8fd915..449cc14 100644
--- a/parser.l
+++ b/parser.l
@@ -149,8 +149,12 @@ static wchar_t num_esc(char *num)
%option noinput
SYM [a-zA-Z0-9_]+
-NUM [+\-]?[0-9]+
-FLO [+\-]?([0-9]+[.]?[0-9]*|[0-9]*[.][0-9]+)([eE][+-]?[0-9]+)?
+SGN [+\-]
+EXP [eE][+\-]?[0-9]+
+DIG [0-9]
+NUM {SGN}?{DIG}+
+FLO {SGN}?{DIG}*[.]({DIG}+{EXP}?|{EXP})
+FLODOT {SGN}?{DIG}+[.]
BSCHR [a-zA-Z0-9!$%&*+\-<=>?\\^_~]
BSYM {BSCHR}({BSCHR}|#)*
NSCHR [a-zA-Z0-9!$%&*+\-<=>?\\^_~/]
@@ -190,7 +194,8 @@ UONLY {U2}{U}|{U3}{U}{U}|{U4}{U}{U}{U}
return NUMBER;
}
-<SPECIAL,NESTED,BRACED>{FLO} {
+<SPECIAL,NESTED,BRACED>{FLODOT}/[^.] |
+<SPECIAL,NESTED,BRACED>{FLO} {
val str = string_own(utf8_dup_from(yytext));
if (yy_top_state() == INITIAL
所以浮点常量现在有两种形式:
可选的符号,后跟零个或多个数字,以及小数点,后跟指数或数字和可选的指数。
数字后跟点,尾随上下文断言下一个字符不是点。
请注意上面如何演示共享相同规则的多种模式的技术(也具有自己的
flex
开始状态):
PATTERN1 |
PATTERN2 |
...
PATTERNN { action; }
这些模式可以单独具有或不具有尾随上下文。
附注如果我改变主意并不允许
123.
,我就会删除 FLODOT
的所有痕迹。
此代码必须反转:
<SPECIAL,NESTED,BRACED>{FLODOT}/[^.] |
<SPECIAL,NESTED,BRACED>{FLO} {
即
<SPECIAL,NESTED,BRACED>{FLO} |
<SPECIAL,NESTED,BRACED>{FLODOT}/[^.] {
看起来
flex
正在考虑匹配的尾随上下文到匹配长度的一部分。即,在 3.0
情况下,FLODOT
被视为三字符匹配,即使提取的标记是 3.
。所以我们必须把这种情况放在第二位,以便通过 3.0
匹配出现 FLO
。
这实际上取决于您如何定义词法分析器。如果您将省略号定义为由两个句点组成的标记,并且还正确定义了浮点数,则应该不会发生冲突。只需确保在规范中首先定义省略号的标记即可。而且,是的,0. 应该是一个无效的浮点数。
使用卡兹的答案,我解决了省略号词法分析,如下所示。 我必须将一条规则分成两条才能使其发挥作用。
/* numbers like 5.1 and .5 */
[0-9]+.[0-9]+|.[0-9]+ { }
/* numbers like 5. but not 5.. */
/* The trailing context helps us tokenize 1..10 as INT, DOTDOT, INT */
/* instead of FLOAT, DOT, INT */
[0-9]+./[^.] { }