The Symbol-Table Interface
符号表例程主要和保存和获取lexeme相关。当一个lexeme被保存的时候,我们也保存和lexeme相关的token。下面的操作将在符号表上被执行。
insert(s,t): 返回字符串s相关的新条目的索引,token t
lookup(s): 返回字符串s的条目的索引,返回0如果没有找到。
词法分析器使用lookup操作判断符号表中是否存在一个lexeme的对应条目。如果不存在,那么它使用insert操作去创建一个。我们应该讨论一个实现,其中词法分析器和解析器都知道符号表条目的格式。
Handling Reserved Keywords
上面的符号表例程能够处理任意的保留关键字集合。例如,考虑div和mod这两个token分别具有lexme div和mod。我们可以使用下面的调用初始化符号表
insert("div", div);
insert("mod", mod);
任何后面对lookup("div")的调用都将返回token div,因此div不能用作一个标识符。
任何保留关键字的集合都可以这样处理,通过适当地初始化符号表。
A Symbol-Table Implementation
一个特定符号表的一个特定实现的数据结构勾勒在Fig. 2.29中。

我们不希望设置一个固定的空间来保存lexemes形成的标识符,固定数量的空间可能不够大以容纳一个非常长的标识符,而对比较短的标识符可能太浪费了,例如i。在Fig. 2.29中,一个单独的数组lexemes用来保存形成一个标识符的那些字符串。字符串以字符结束字符结束,即EOS,不会出现在任何标识符中。符号表数组symtable中的每一个条目是一个包含两个字段的记录,lexptr,指向一个lexeme的开始,以及token。额外的字段可以容纳属性值,虽然我们这里不需要这样做。
在Fig. 2.29中,第0个条目保留为空,因为lookup返回0表示没有一个字符串对应的条目。第1和第2条目分别对应关键字div和mod。而第3和第4条分别对应标识符count和i.
处理标识符的一个词法分析器的伪代码如Fig. 2.30所示;一个C实现在Section 2.9中。空白和整数常量被词法分析器用上一节Fig. 2.28一样的方式处理。
function lexan:integer;
var lexbuf: array[0..100] of char;
c: char;
begin
read a character into c;
if c is a blank or a tab then
do nothing
else if c is a newline then
lineno := lineno + 1
else if c is a digit then begin
set tokenval to the value of this and following digits;
return NUM
end
else if c is a letter then begin
place c and successive letters and digits into lexbuf;
p := lookup(lexbuf);
if p = 0 then
p := insert(lexbuf, ID);
tokenval := p;
return the token field of table entry p
end
else begin /* token is a single character */
set tokenval to NONE;
return integer encoding of character c
end
end
当我们的词法分析器读到一个字母时,它开始在一个缓冲区lexbuf中保存字母和数字。在lexbuf中搜集好的字符串在符号表中进行lookup。因为符号表中已经初始化了关键字div和mod,因此如果lexbuf中是div或者mod,那么就会返回相应的条目。如果找补到,那么lexbuf包含一个新标识符的新lexme。使用insert插入一个新条目,p是这个新条目在符号表中的索引。该索引通过设置tokenval=p和解析器通讯,该条目的token字段被返回。
缺省的动作是返回字符的整数编码。既然单个字符的token在这里没有属性,tokenval设置为NONE。
没有评论:
发表评论