在编译器构造中使用令牌或字符串之间有什么区别吗?

Is there some difference between use Tokens or strings in compiler construction?

我试图在 JavaCC 中优化编译器,但后来遇到了一些我过去在使用编译器时从未发现的东西,因为我被教导要对任何终端使用令牌。

本编译器有时会在句法分析的正则表达式中使用字符串而不是token,例如:

<TK_IF> "(" log_expr ")" body

而不是:

<TK_IF> <TK_LPAREN> log_expr <TK_RPAREN> body

这只是一个示例,在代码的其他部分中,在 (+, -, !=, ==, >, <) 等运算符中使用了字符串。

我想知道的是,在编译器中使用标记或字符串之间是否存在一些差异,主要是关于性能,这是我优化它的目标。

在过去,实现词法分析器/分词器是很常见的,这样它们 return "small integer" 每个 token-type-number 的值:

IF the next token is the word "def" THEN RETURN 257 FI

例如。结合使用 7 位或 8 位字符集,我们立即看到所有 256 个可能的字符值都可用作标记值。所以“(”只能是标记号 40(参见任何 ASCII table)。

您通常可以判断是否有人在使用这种表示法,因为像 + 这样的单字符运算符将以这种方式编码 (+ = 43),但是像 + 这样的双字符运算符=14=] 将有一个命名的令牌。当生成令牌查找代码的代码生成令牌 table 并且第一个 named 令牌的数值刚好超过 255(最大 8 位值)时,会出现另一个赠品。

最后,这并不是很重要:它只是一个实现怪癖。如果您编写自己的扫描器和解析器,您将做任何适当的事情 return 为您的解析器提供适当的令牌代码。如何将某些输入语法转换为适当的 code 取决于您。

答案在the FAQ.

假设我有两个定义(或 JavaCC 术语中的词汇产生式)

TOKEN : { <ID : (["a"-"z","A"-Z"])+ > 
      |   <BECOMES : ":=" >}

这定义了一个名为 ID 的令牌种类。它对应于输入文件中可能出现的无限多个字符串:applepearfruitBasket。它还定义了一个标记类型 BECOMES,它只能作为字符串 :=.

出现

在您的 BNF 产品中,您需要参考令牌种类。所以 BNF 产生式可能是

void assignment() : {} { <ID> <BECOMES> expression() }

但是 ---as explained in the FAQ--- 因为 BECOMES 标记类型只能引用字符串 := --- 并且大概是唯一的这样的标记类型,JavaCC让你把这个 BNF 产生式写成

void assignment() : {} { <ID> ":=" expression() }

产生式的两种写法是一样的

在您的例子中,非终结符产生式中的字符串“(”和“)”分别简单地缩写为 <TK_LPAREN><TK_RPAREN>

此缩写只能用于 BNF 制作