(f)lex PRINTA$ 和 PRINT A$ 之间的区别

(f)lex the difference between PRINTA$ and PRINT A$

我正在解析 BASIC:

530 FOR I=1 TO 9:C(I,1)=0:C(I,2)=0:NEXT I

本例中使用的模式是:

FOR  { return TOK_FOR; }
TO   { return TOK_TO; }
NEXT { return TOK_NEXT; }
(many lines later...)
[A-Za-z_@][A-Za-z0-9_]*[$%\!#]? {
          yylval.s = g_string_new(yytext);
          return IDENTIFIER;
        }
(many lines later...)
[ \t\r\l]   { /* eat non-string whitespace */ }

问题出现在去掉空格的时候,这在8k内存时代很常见。所以在超级星际迷航中实际找到的那行是:

530 FORI=1TO9:C(I,1)=0:C(I,2)=0:NEXTI

现在我知道为什么会这样了:"FORI" 比 "FOR" 长,它在我的模式中是一个有效的 IDENTIFIER,所以它匹配 IDENTIFIER。

原来MS BASIC的规则是变量名只能是两个字符,所以没有*所以匹配失败。但是这个版本也支持 GW BASIC 和 Atari BASIC,它们允许长名称的变量。所以 "FORI" 在我的扫描器中是一个合法的变量名,所以匹配是最长的匹配。

现在当我look at the manual和唯一类似的例子故意returns出错。看来我需要的是"match the ID, but only if it's not the same as defined %token",有这样的吗?

即使将标识符串联在一起,也很容易识别关键字。棘手的是决定在什么情况下应该应用该技术。

这是一个使用尾随上下文识别关键字的简单模式:

tail       [[:alnum:]]*[$%!#]?
%%
FOR/{tail}    { return TOK_FOR; }
TO/{tail}     { return TOK_TO; }
NEXT/{tail}   { return TOK_NEXT; }
  /* etc. */
[[:alpha:]]{tail}  { /* Handle an ID */ }

实际上,这只是扩展关键字匹配而不扩展匹配的标记。

但我怀疑问题这么简单。例如,FORFORTO 应该如何标记?