在编译器构造中使用令牌或字符串之间有什么区别吗?
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
的令牌种类。它对应于输入文件中可能出现的无限多个字符串:apple
、pear
、fruitBasket
。它还定义了一个标记类型 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 制作。
我试图在 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
的令牌种类。它对应于输入文件中可能出现的无限多个字符串:apple
、pear
、fruitBasket
。它还定义了一个标记类型 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 制作。