我目前正在为一种简单的编程语言实现一个lexer。到目前为止,我可以正确地标记标识符、赋值符号和整数文字;一般来说,空格是不重要的。
对于输入的foo = 42
,识别出三个令牌:
foo
(标识符)=
(符号)42
(整数文字)到现在为止还好。但是,考虑输入foo = 42bar
,它是无效的,因为42
和bar
之间(重要的)空间缺失。我的lexer错误地识别了以下令牌:
foo
(标识符)=
(符号)42
(整数文字)bar
(标识符)一旦雷克萨斯看到了数字4
,它就会一直读取,直到遇到一个非数字。因此,它使用2
并将42
存储为整数文字标记。因为空格是不重要的,所以lexer放弃了任何空格(如果有的话),并开始读取下一个标记:它找到标识符bar
。
现在,我的问题是:是否仍然有责任承认在该位置不允许使用标识符?还是该检查属于解析器的职责?
发布于 2014-05-13 05:14:25
我认为对于42foo
是否应该被认为是一个无效的数字还是两个标记的问题没有任何共识。这是一个风格问题,这两种用法在众所周知的语言中都很常见。
例如:
$ 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 + 1
、42+1
和42+ 1
的片段都应该进行相同的解析。(除了,也许在堡垒里。但这是一种反常现象。如果您不介意将数字和单词放在一起,那么如果(并且只有当)它是语法错误时,就让解析器拒绝它。
另外,在C和C++中,42and
最初被称为“预处理号”。经过预处理后,需要重新执行,并在这一点上产生错误消息。造成这种奇怪行为的原因是,将两个片段粘贴在一起产生一个有效数字是完全合法的:
$ 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
12E
和1F
都是无效整数,但是与##
运算符结合在一起,它们就形成了一个完全合法的浮点数。##
运算符仅在单个令牌上工作,因此12E
和1F
都需要作为单个令牌进行词汇处理。c(12E+,1F)
不能工作,但是c(12E0,1F)
也很好。
这也是为什么您应该总是在C:经典技巧C中的+
运算符周围放置空格:“0x1E+2
的值是什么?”
最后,对awk行的解释是:
$ awk 'BEGIN{print 42foo + 3}'
423
这是由awk词汇作为BEGIN{print 42 foo + 3}
,然后被解析,就好像它是写的BEGIN{print (42)(foo + 3);}
。在awk中,字符串连接是在没有运算符的情况下编写的,但绑定比任何算术运算符都要小。因此,通常的建议是在涉及级联的表达式中使用显式括号,除非它们非常简单。(此外,假设未定义变量的值为0
(算术使用),""
(用作字符串)。)
发布于 2014-05-13 01:24:56
我不同意这里的其他答案。应该由莱克星人来完成。如果数字后面的字符不是空格或特殊字符,则您处于非法令牌的中间,特别是一个不以字母开头的标识符。
否则,只需分别返回45和“bar”,并让解析器将其作为语法错误处理。
发布于 2014-05-13 01:10:27
是的,像这样的上下文检查属于解析器。
此外,您还会说foo = 42bar
无效。不过,从雷克萨斯的角度来看,事实并非如此。您的lexer识别的4个令牌(可能)是正确的(您没有发布令牌定义)。
在您的语言中,foo = 42bar
可能是有效的,也可能不是有效的。
https://stackoverflow.com/questions/23621165
复制相似问题