上节符号表的部分只是涉及到一个具体的思路,这节才是具体的实现,考试很重要!
符号表是在程序运行到某一个位置的时候是有效的,考试的时候一般都会给出一个具体的时刻然后写出这个时刻的符号表。
删除法是把整个当前退出的层的符号表删除,并删除指向当前层符号表起始位置的Scope栈中的指针。
首先进入主程序,第一层为0,即P。Scope(0)指向符号表第一个元素P的位置。
然后进入主程序,定义了var i,j,k三个integer类型的变量,此时层数+1,Scope(2)指向当前层,同时下一个函数(局部化区的开始)写入符号表。
继续进入函数Q的内部,执行var a,ba和b写入符号表,同时下一个函数R的局部化区域开始也进入符号表。Scope(3)指向当前层的开始位置。
4. 进入函数R内部,执行定义var a,b将a和b写入符号表,同时Scope(4)指向当前区域的起始位置。 5. 执行使用性说明即R的过程体之后,退出当前局部化区域,删除符号表中属于当前区域的全部元素,并将Scope栈中的指针清除。并继续执行Q的过程体,Q函数部分结束,将符号表中所在层的全部内容删除,并删除Scope栈中的相应指针。同时进入新的procedure即函数S,将S写入符号表中。 6. 继续分析函数S,执行var c,ec和e写入符号表 7. 执行S的过程体,将所有S的部分清除 8. 执行P的过程体,将Scope(1)指向的部分清除
主要是在执行完相应局部区域的函数体之后没有采用将符号表的内容删除的方式,也没有将Scope栈中的内容删除,而是在符号表中开辟另外的空间存储相应的指向局部化区域头部的指针,原来的局部化区域中的内容并没有被删除,而是在从下到上顺序查找符号表的时候将原来的区域略过。
前面的部分和删除法相同2. 当局部化区域退出的时候,重新开辟一部分空间指向当前局部化区域的头部,然后进入新的局部化区域即函数体S,将S入符号表,同时Scope部分继续生成指针指向符号表中的S位置。 3. 继续向下执行相应函数,将c和e入符号表,然后执行S的过程体(这个时候执行S的过程体会出现访问错误但是也继续执行),这个时候删除Scope栈中指向当前过程体的指针,并在符号表中生成一个新的指针指向当前局部化区域S的头部。 然后执行P的过程体,再生成一个指针指向P过程体的头部,同时删除Scope栈中的指针。
带有分程序的,每一个{}开始的区域都使用指针指向用来进行标记,而且后面的每个变量的偏移都是在前一个变量偏移的基础上的。后面的d可以有两种取值的原因是,考虑了跳过上面的c和d,实际上在退出上一个局部化区域之后,c和d就不会被使用了,接上面的d部分。
和之前的删除没有什么区别
标号在程序中出现共有三种形式
声明性出现 在程序的声明部分给出一个声明,声明哪些标识符是标号。例如:label R1,R2定位性出现 起到定位的作用,例如: R1:s, s是一个语句,R1是一个语句标号,表示R1这个语句标号定位在s语句前面转移性出现 例如goto R1, 即把程序的控制结构转到标号为R1的位置上开始去执行如果遇到转移性标号的时候(goto的时候),到标号表中去找,找有没有这个标号,找到就找到了。如果找到这个标号状态是0,并不意味着它出错了,而是要把这个标号存在另一个表里,表示该标号目前没有找到定位,一直处理到整个程序单位结束的。
首先根据r1,r2构建标号表,当前的标号为0,然后r1定位使用r1位置变成1 然后执行goto r2,但是当前标号表中的r2位置是0,将r2先写入未找到定位标号表中,等待程序段完成进行复查。 接着执行goto r1,在标号表中r1的值为1,🙆;继续向下执行有r2定位,将标号表中的r2标号改成1,最后复查未找到标号表,检查r2对应符号表中的值为1,🙆。