首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >词汇与分析者的责任

词汇与分析者的责任
EN

Stack Overflow用户
提问于 2014-05-13 00:47:44
回答 4查看 759关注 0票数 3

我目前正在为一种简单的编程语言实现一个lexer。到目前为止,我可以正确地标记标识符、赋值符号和整数文字;一般来说,空格是不重要的。

对于输入的foo = 42,识别出三个令牌:

  1. foo (标识符)
  2. = (符号)
  3. 42 (整数文字)

到现在为止还好。但是,考虑输入foo = 42bar,它是无效的,因为42bar之间(重要的)空间缺失。我的lexer错误地识别了以下令牌:

  1. foo (标识符)
  2. = (符号)
  3. 42 (整数文字)
  4. bar (标识符)

一旦雷克萨斯看到了数字4,它就会一直读取,直到遇到一个非数字。因此,它使用2并将42存储为整数文字标记。因为空格是不重要的,所以lexer放弃了任何空格(如果有的话),并开始读取下一个标记:它找到标识符bar

现在,我的问题是:是否仍然有责任承认在该位置不允许使用标识符?还是该检查属于解析器的职责?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2014-05-13 05:14:25

我认为对于42foo是否应该被认为是一个无效的数字还是两个标记的问题没有任何共识。这是一个风格问题,这两种用法在众所周知的语言中都很常见。

例如:

代码语言:javascript
运行
复制
$ python -c 'print 42and False'
False

$ lua -e 'print(42and false)'
lua: (command line):1: malformed number near '42a'

$ perl -le 'print 42and 0'
42

# Not an idiosyncracy of tcc; it's defined by the standard
$ tcc -D"and=&&" -run - <<<"main(){return 42and 0;}"
stdin:1: error: invalid number

# gcc has better error messages
$ gcc -D"and=&&" -x c - <<<"main(){return 42and 0;}" && ./a.out
<stdin>: In function ‘main’:
<stdin>:1:15: error: invalid suffix "and" on integer constant
<stdin>:1:21: error: expected ‘;’ before numeric constant

$ ruby -le 'print 42and 1'
42

# And now for something completely different (explained below)
$ awk 'BEGIN{print 42foo + 3}'
423

因此,这两种可能性都是共同使用的。

如果你想拒绝它,因为你认为一个数字和一个单词应该用空格隔开,你应该在词汇中拒绝它。解析器不能(或者不应该)知道空格是否分隔两个标记。与42and的有效性无关,42 + 142+142+ 1的片段都应该进行相同的解析。(除了,也许在堡垒里。但这是一种反常现象。如果您不介意将数字和单词放在一起,那么如果(并且只有当)它是语法错误时,就让解析器拒绝它。

另外,在C和C++中,42and最初被称为“预处理号”。经过预处理后,需要重新执行,并在这一点上产生错误消息。造成这种奇怪行为的原因是,将两个片段粘贴在一起产生一个有效数字是完全合法的:

代码语言:javascript
运行
复制
$ gcc -D"c_(x,y)=x##y" -D"c(x,y)=c_(x,y)"  -x c - <<<"int main(){return c(12E,1F);}"
$ ./a.out; echo $?
120

12E1F都是无效整数,但是与##运算符结合在一起,它们就形成了一个完全合法的浮点数。##运算符仅在单个令牌上工作,因此12E1F都需要作为单个令牌进行词汇处理。c(12E+,1F)不能工作,但是c(12E0,1F)也很好。

这也是为什么您应该总是在C:经典技巧C中的+运算符周围放置空格:“0x1E+2的值是什么?”

最后,对awk行的解释是:

代码语言:javascript
运行
复制
$ awk 'BEGIN{print 42foo + 3}'
423

这是由awk词汇作为BEGIN{print 42 foo + 3},然后被解析,就好像它是写的BEGIN{print (42)(foo + 3);}。在awk中,字符串连接是在没有运算符的情况下编写的,但绑定比任何算术运算符都要小。因此,通常的建议是在涉及级联的表达式中使用显式括号,除非它们非常简单。(此外,假设未定义变量的值为0 (算术使用),"" (用作字符串)。)

票数 3
EN

Stack Overflow用户

发布于 2014-05-13 01:24:56

我不同意这里的其他答案。应该由莱克星人来完成。如果数字后面的字符不是空格或特殊字符,则您处于非法令牌的中间,特别是一个不以字母开头的标识符。

否则,只需分别返回45和“bar”,并让解析器将其作为语法错误处理。

票数 2
EN

Stack Overflow用户

发布于 2014-05-13 01:10:27

是的,像这样的上下文检查属于解析器。

此外,您还会说foo = 42bar无效。不过,从雷克萨斯的角度来看,事实并非如此。您的lexer识别的4个令牌(可能)是正确的(您没有发布令牌定义)。

在您的语言中,foo = 42bar可能是有效的,也可能不是有效的。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/23621165

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档