【发布时间】:2012-02-28 14:20:28
【问题描述】:
我正在设计一种语言,我想使用 .. 来定义整数范围。问题是 0..10 被标记为浮点数 0. 和 .10。
如何允许使用 flex 支持这种语法?把 0. 设为无效浮点数是不是很简单?
【问题讨论】:
-
请注意,“Flex”标签指的是 Adobe Flex。请改用“Lex”标签。
标签: floating-point lex tokenize ellipsis
我正在设计一种语言,我想使用 .. 来定义整数范围。问题是 0..10 被标记为浮点数 0. 和 .10。
如何允许使用 flex 支持这种语法?把 0. 设为无效浮点数是不是很简单?
【问题讨论】:
标签: floating-point lex tokenize ellipsis
如果您不想使 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.。所以我们必须把这个case放在第二位,这样3.0就可以通过FLO匹配出来。
【讨论】:
这实际上取决于您如何定义词法分析器。如果您将省略号定义为由两个句点组成的标记,并且还正确定义了浮点数,则不应存在冲突。只需确保在您的规范中首先定义省略号的标记。而且,是的,0. 应该是一个无效的浮点数。
【讨论】:
1. 在 Common Lisp 中是一个有效的标记,但它实际上表示一个整数,而不是一个有效的浮点数! (type-of 123.) -> INTEGER.