语法制导翻译
语法制导翻译
或1,3,5,2,4,6,7,8,9
编译原理
20
循环依赖Circular dependency
产生式 AB
语义规则 A.s := B.i B.i := A.s + 1
A A.s
B B.i
编译原理
21Biblioteka 属性计算次序构造输入的分析树, 构造属性依赖图, 对结点进行拓扑排序, 按拓扑排序的次序计算属性。
介绍语法制导翻译的实现方法。
编译原理
3
语法制导翻译的一般过程
输入符号串 分析树 依赖图 语义规则的计算顺序
一个句子的翻译过程可以与语法分析过程并行。
编译原理
4
5.1 语法制导定义
语法制导定义是对CFG的推广,每个文法符号都有 一个相关的属性集。
属性:语义信息。一个文法符号通常用一个或若干 个属性来描述它的语义信息。典型例子: ▪ 变量的数据类型 ▪ 表达式的值 ▪ 变量的存储位置 ▪ 程序的目标代码
F.val := digit.lexval
编译原理
13
图5-4
T.val = 15
F.val = 3
T′.inh = 3
.syn =15
digit.lexval =3
*
T1′.inh = 15
F.val = 5
.syn =15
digit.lexval = 5
编译原理
14
继承属性
一个结点的继承属性值由该结点的父结点和(或) 兄弟结点的属性决定。
分析树各结点属性的计算可以自底向上地完成。
编译原理
11
8+5*2 n的注释分析树 (annotated parse tree)
编译原理 第5章语法制导的翻译
属性和文法符号相关联 规则和产生式相关联
根据需要,将文法符号和某些属性相关联, 并通过语义规则来描述如何计算属性的值
E→E1+T E.code=E1.code || T.code || ‘+’ code表示了我们关心的表达式的逆波兰表示,规则说明 加法表达式的逆波兰表示由两个分量的逆波兰表示并置, 然后加上‘+’得到。
digitlexval=3
18
适用于自顶向下分析的SDD
前面的表达式文法存在直接左递归,因 此无法直接用自顶向下方法处理。 消除左递归之后,无法直接使用属性val 进行处理:
比如规则:T→FT’ T’→*FT’ T对应的项中,第一个因子对应于F, 而运算符在T’中。
19
相同表达式的不同文法的比较
38
例5.15 分析栈实现的例子
假设语法分析栈存放在一个被称为stack 的记录数组中,下标top指向栈顶;
stack[top]指向这个栈的栈顶;stack[top-1] 指向栈顶下一个位置; 如果不同的文法符号有不同的属性集合,我 们可以使用union来保存这些属性值。(归 约时,我们知道栈顶向下的各个符号分别是 什么)
语义翻译的流程
输 入 符 号 串 分 析 树 依 赖 图
语
义
规
则
的 计
实际上,编译中语义翻译的实现并不是 按图中的流程处理的;而是随语法分析 的进展,识别出一个语法结构,就对它 的语义进行分析和翻译。
算
9
5.1 语法制导定义
4.什么是语法制导定义(SDD) 上下文无关文法和属性/规则的结合;
语法制导翻译
2
4.1 语法制导翻译简介
语法与语义
1. 语法与语义的关系 语法是指语言的结构、即语言的“样子”;语义是指附着于语
言结构上的实际含意 ,即语言的“意义”。 ① 语义不能离开语法独立存在; ② 语义远比语法复杂; ③ 同一语言结构可包含多种含意,不同语言结构可表示相
② 若b是α中某文法符号Xi的属性,c1, c2, ..., ck是A的属性, 或者是α中其它文法符号的属性,则称b是Xi的继承属性。
③ 称(4.1)中属性b依赖于属性c1, c2, ..., ck。
④ 若语义规则的形式如下述(4.2),则可将其想像为产生式左 部文法符号A的一个虚拟属性。属性之间的依赖关系,在 虚拟属性上依然存在。
k := k+1;
9
4.1 语法制导翻译简介
产生式
语法制导定义
翻译方案
L→E
print(E.post)
print_post(post);
E → E1 + E2 E → num
E.post := E1.post || post(k) := '+'; E2.post || '+'; k := k+1;
1. 编译器各阶段的完整输出,均可以被认为是源程序的某种 中间表示。
2. 本章讨论的是中间代码生成器输出的中间表示,称之为中 间代码。
3. 中间代码实际上应起一个编译器前端与后端分水岭的作用。 4. 要求中间代码具有如下特性,以便于编译器的开发移植和
代码的优化: ① 便于语法制导翻译; ② 既与机器指令的结构相近,又与具体机器无关。 5. 中间代码的主要形式:树、后缀式、三地址码等。
属性文法和语法制导翻译
id1
如果一属性文法不存在属性 之间的循环依赖关系,那么 称该文法为良定义的
T type
5 in L
4
real
7 in L y 8 ,
y6 id3 entry 3
9 in L y 10 ,
id2 entry 2
id1 entry 1
属性的计算顺序
无环有向图的拓扑排序
无环有向图中节点m1,m2,…,mk的拓扑排序是:若 mi→mj是从mi到mj的边,那么在此排序中mi先于mj 依赖图的任何拓扑排序都给出了一个分析树中各节点 语义规则计算的正确顺序,即在计算f之前,语义规则
real id1,id2,id3
语法制导翻译
基于属性文法的处理过程通常是:
对符号串进行语法分析,
构造语法分析树
根据需要遍历语法树并在语法树的各结点处按语义规 则进行计算。
这种由源程序的语法结构驱动的处理办法就是语法制 导翻译法。
在某些情况下,在进行语法分析的同时完成语义规则
的计算而无须明显地构造语法树或构造属性之间的依
real L.in=real ,
id3
L.in=real ,
id2
id1
产生式 D→TL T→int T→real L→L1 , id
L→id
语义规则 L.in := T.type T.type := integer T.type := real L1.in := L.in addtype(id.entry, L.in) addtype(id.entry, L.in)
为每个包括过程调用的语义规则引入一个虚综合属性b,把每条 语义规则都变成b=f(c1,c2,...,ck)的形式 依赖图的每个结点表示一个属性 边表示属性间的依赖关系。如果属性b依赖于属性c,那么从c到 b就有一条有向边
第8讲 语法制导翻译_1
3*5+4n
副作用(Side effect)
语义规则
E.val=15 + T.val=4
print(E.val)
E.val = E1 .val + T.val E.val = T.val
T.val = T1val × F.val
T.val = F.val
T.val=15
F.val=4
T.val=3 * F.val=5 digit.lexval=4
如果一个SDD是S属性的,可以按照语法分析树节点的任何 自底向上顺序来计算它的各个属性值
S-属性定义可以在自底向上的语法分析过程中实现
L- 属 性 定 义
L-属性定义( 也称为L属性的SDD或L-SDD) 的 直观含义:在一个产生式所关联的各属性之间, 依赖图的边可以从左到右,但不能从右到左 ( 个SDD是L-属性定义,当且仅当它的每个属性要 么是一个综合属性,要么是满足如下条件的继承属 性:假设存在一个产生式A→X1X2…Xn,其右部符 号Xi (1 i n)的继承属性仅依赖于下列属性:
A的继承属性 产生式中Xi左边的符号 X1, X2, … , Xi-1 的属性 Xi本身的属性,但Xi 的全部属性不能在依赖图中形成环路
将每个产生式和一组语义规则相关联,用来计算 该产生式中各文法符号的属性值
文法符号的属性
综合属性 ( synthesized attribute) 继承属性 ( inherited attribute)
综 合 属 性 ( synthesized attribute)
在分析树结点 N上的非终结符A的综合属性只能通 过 N的子结点或 N本身的属性值来定义
两个概念
将语义规则同语法规则(产生式)联系起来要 涉及两个概念
第5章 语法制导翻译和中间代码生成
剩余串 3+ 45# +45# +45# +45# +45# 5# 5# 5# 5# 5# #
主要动作
r6 r4 r2
r6 r4
r6 # # r3 r1 acc
表达式3 + 4 5的语法语义分析和计值过程
§5.3
中间语言
所谓中间语言,也称中间代码,是复杂性介 于源程序语言和机器语言的一种记号系统。一般 来说,快速编译程序直接生成目标代码,没有将 中间代码翻译成目标代码的额外开销。但是为了 使编译程序结构在逻辑上更为简单明确,使生成 的的目标代码更为高效,通常采用中间语言。 编译程序所使用的中间语言形式较多。常见 的逆波兰式、三元式、四元式和树形表示等。来自bcd
3. 间接三元式 为了尽量不改变三元式表,可以另设一张间 接码表来表示有关三元式在三元式表的 计值顺序。用这种方法获得的中间代码 称为间接三元式。
例如,表达式a := x+y z b := t-y z 的间接三元式表示如图所示。
三元式列表 (1)( ,y,z) (2)(+,x,(1)) (3)(:=,a,(2)) (4)(-,t,(1)) (5)(:=,—,(4))
§5.4 自底向上语法制导翻译
语法制导翻译分为自底向上和自底向下两种。 自底向上语法制导翻译方法就是在自底向上语法 分析过程中逐步执行语义规则。也就是在每次归 约的同时执行相应的语义动作。
5.4.1 简单算术表达式和赋值语句的翻译
简单算术表达式和赋值语句是指不含数组 元素、记录等复杂数据结构的算术表达式和赋值 语句。
简单算术表达式求值的属性文法。 例5.1 :
规则 1.S→E 2.E→E1+T 3.E→T 4.T→T1 F 5.T→T1 6.F→(E) 7.F→digit 语义规则 print(E.val) E.val := E1.val+T.val E.va1 := T.valv T.val := T1.val F.val T.val := T1.val F.val := E.val F.val := digit.lexval
最新六章语法制导翻译与属文法
2021/1/11
10
典型处理方法二
翻译模式
通过将属性与文法符号关联,并将语义规则插入到产生式 的右部来描述语言结构的翻译方案
在产生式的右部的适当位置,插入相应的语义动 作,按照分析的进程,执行遇到的语义动作
D → T { L.inh := T.type } L
T → int { T.type := integer }
这两种情况下,都说属性b依赖于属性c1,c2,…,ck
2021/1/11
14
例6.1 台式计算器的语法制导定义
产生式 LEn E E1+T E T T T1*F T F F (E) F digit
语义规则 print(Eval)(可看作是L的虚属性) Eval := E1val+Tval Eval := Tval Tval := T1val+Fval Tval := Fval Fval := Eval Fval := digitlexval
E→E1 + E2
E.val:=E1.val+E2.val
语法结构具有规定的语义
问题:如何根据被识别出的语法成分进行 语义处理?
亦即怎样将属性值的计算及翻译工作同产生式 相关联?
2021/1/11
9
典型处理方法一
语法制导定义
通过将属性与文法符号关联、将语义规则与产生 式关联来描述语言结构的翻译方案
2021/1/11
16
继承属性
当分析树的结构同源代码的抽象语法不“匹 配”时,继承属性将非常有用。下面的例子 可以说明怎样用继承属性来解决这种不匹配 问题,产生这种不匹配的原因是因为文法通 常是为语法分析而不是为翻译设计的。
例6.2
第08章语法制导翻译和中间代码生成
常用的中间语言
• 三地址代码(四元式) 三地址代码(四元式) • 语法结构树(三元式) 语法结构树(三元式) • 后缀式
特点
• 形式简单、语义明确、便于翻译 形式简单、语义明确、 • 独立于目标语言
29
三元式和树形表示
• 每个三元式由三个部分组成,分别是:算符op, 每个三元式由三个部分组成,分别是:算符op, op 第一运算对象ARG1和第二运算对象ARG2 ARG1和第二运算对象ARG2。 第一运算对象ARG1和第二运算对象ARG2。运算 对象可能是源程序中的变量, 对象可能是源程序中的变量,也可能是某个三 元式的结果,用三元式的编号表示。 元式的结果,用三元式的编号表示。 • 表达式的树形表示很容易实现:简单变量或常 表达式的树形表示很容易实现: 数的树就是该变量或常数自身,如果表达式e1 数的树就是该变量或常数自身,如果表达式e1 e2的树分别为T1和T2,那么e1+e2 e1*e2, 的树分别为T1 e1+e2, 和e2的树分别为T1和T2,那么e1+e2,e1*e2, e1的树分别为 的树分别为: -e1的树分别为:
9
–lexval 是单词 digit 的属性 lexval
例8-3 3*5+4 的
语法树与属性计算
L Print(19) E.val=19
E.val=15 T.val=15 T.val=3 F.val=3 digit.lexval=3 *
+
T.val=4 F.ቤተ መጻሕፍቲ ባይዱal=4
F.val=5 dgit.lexval=5
• 用中间语言过渡的好处: 用中间语言过渡的好处:
–便于编译系统的实现、移植、代码优化 便于编译系统的实现、移植、 便于编译系统的实现
第5章 语法制导翻译1
2. Expr Name (1) Add Name ( 2 ) { Attribution: Name (1) . environment Expr . environment ; Name ( 2 ) . environment Expr . environment ;
int Entry(char *Name){ int i=LookUp(Name);
if(i) return i; else return Enter(Name);
翻译程序中使用的辅助函数(续)
⒋int Trip(int op,int arg1,int arg2)—根据给定 的参数产生一个三元式 (op,arg1,arg2) 并将它送入三元式表中,其返回值为表中序号。 为区分参数 arg 表示的是 三元式 还是变量,约定 当arg<0时表示三元式序号;arg>0表示变量在 符号表中登记项序号;arg=0表示参数为空。
文法符号及其语义属性
例如,文法G[E]: 产生式 语义子程序 E→E(1)+T {E.Val=E(1).val+T.val;} E→T {E.Val=T.Val;} T→digit {T.Val=digit;} 为了能在语法分析过程中平行地进行语 义处理,可在语法分析栈旁边并行地设 置一个语义信息栈
语法分 析栈 T + E … # … 语义分 析栈 T.Val ‘+’
5.2 属性文法与属性翻译文法
语法制导翻译方法的实质,就是根据文法中每个产 生式所蕴含的语义,为其配备一个(或多个)处理 语句或子程序,对所要完成的功能进行描述。 产生式的语义是由组成该产生式的文法符号的语义 所决定的。 将这些语义以“属性”的形式附加到各个文法符号 上,再根据产生式所蕴含的语义,给出每个文法符 号的属性的求值规则,从而形成一种附带有语义属 性的前后文无关文法,即属性文法。 语义属性主要有两类:综合属性和继承属性
编译原理分知识点习题-语法制导和翻译
编译原理分知识点习题-语法制导和翻译1.⼀般情况下,为什么语义分析部分仅产⽣中间代码解答:⼀般情况下,语义分析部分仅产⽣中间代码,其原因是:可使难点分解,分别解决。
可对语义分析产⽣的中间代码进⾏优化,以产⽣⾼效率的⽬标代码。
语义分析通常与机器⽆关,⽬标代码往往与机器有关。
把语义分析与⽬标代码⽣成分开,可让⼀个语义分析程序适⽤于多个⽬标代码⽣成程序。
2.(湖北省⾼等教育⾃学考试)什么是语法制导翻译为什么把这种⽅法叫语法制导翻译解答:所谓语法制导翻译,是指在语法规则的制导下,通过计算语义规则,完成对输⼊符号串的翻译。
由于使⽤属性⽂法时把语法规则和语义规则分开,但在使⽤语法规则进⾏推导或规约的同时⼜使⽤这些语义规则来知道翻译与最终产⽣⽬标代码,所以称为语法制导翻译。
3.给出将附值语句翻译成四元式的语法制导定义,允许右部表达式含有加法、乘法、取负、括号运算。
⽣成赋值语句X:=B*(C+D)+A 的四元式。
解答:赋值语句的⾃下⽽上的语法制导翻译过程描述为:规则语义动作(1)A::=i:=E {GEN (:=,,__,ENTRY(i) ) }(2)E::=E1+E2 {:=NEWTEMP;GEN(+,, ,}(3)E::= E1*E2 { :=NEWTEMP;GEN(*,, ,}(4)E::=-E1 { :=NEWTEMP;GEN(@,,__,}(5)E::=(E1) {:= }(6)E::=i {:= ENTRY(i) }⽣成的赋值语句X:=B*(C+D)+A的四元式为:(+,C,D,T1)(*,B,T1,T2)(+,T2,A,T3)(:=,T3,_,X)4.给出将布尔表达式翻译成四元式的语法制导定义。
解答:布尔表达式的语义⼦程序为:规则语义动作(1) E::=I {:=null;:=NXQ;GEN (Jez , ENTRY(i), __,0) }(2) E::= i1 rop i2 { :=null;:=NXQ;GEN (Jnrop,ENTRY(i1), ENTRY(i2),0)}(3) E::= (E1) {:=, :=; }(4) E::= ? E1 { :=NXQ;GEN ( J, __, __, 0); BP , NXQ);}(5) E A::=E1∧ { if =nullthen begin::=NXQ;GEN ( J, __, __, 0)End;BP ( , NXQ );:=null; := }(6) E ::= E A E2 {if ≠nullthen beginBP , NXQ);:=nullEnd:=; }(7) E0::=E1∨ { if :=nullthen begin:=NXQ;GEN ( J, __, __, 0)End;:=;BP ,NXG);}(8) E::=E0E2 { if ≠nullthen:=MERG,Else beginBP ,NXQ);:=End;:=}其中:NXQ指⽰器指向下⼀个将要形成但尚未形成的四元式的地址(编号),初值为1,每当执⾏GEN⼀次,NXQ⾃动加1。
编译原理分知识点习题-语法制导和翻译
1.一般情况下,为什么语义分析部分仅产生中间代码解答:一般情况下,语义分析部分仅产生中间代码,其原因是:可使难点分解,分别解决。
可对语义分析产生的中间代码进行优化,以产生高效率的目标代码。
语义分析通常与机器无关,目标代码往往与机器有关。
把语义分析与目标代码生成分开,可让一个语义分析程序适用于多个目标代码生成程序。
2.(湖北省高等教育自学考试)什么是语法制导翻译为什么把这种方法叫语法制导翻译解答:所谓语法制导翻译,是指在语法规则的制导下,通过计算语义规则,完成对输入符号串的翻译。
由于使用属性文法时把语法规则和语义规则分开,但在使用语法规则进行推导或规约的同时又使用这些语义规则来知道翻译与最终产生目标代码,所以称为语法制导翻译。
3.'4.5.给出将附值语句翻译成四元式的语法制导定义,允许右部表达式含有加法、乘法、取负、括号运算。
生成赋值语句X:=B*(C+D)+A的四元式。
解答:赋值语句的自下而上的语法制导翻译过程描述为:规则语义动作(1)A::=i:=E {GEN (:=,,__,ENTRY(i) ) }(2)E::=E1+E2{:=NEWTEMP;GEN(+,, ,}(3)E::= E1*E2{ :=NEWTEMP;'GEN(*,, ,}(4)E::=-E1{ :=NEWTEMP;GEN(@,,__,}(5)E::=(E1) {:= }(6)E::=i {:= ENTRY(i) }生成的赋值语句X:=B*(C+D)+A的四元式为:(+,C,D,T1)((*,B,T1,T2)(+,T2,A,T3)(:=,T3,_,X)6.给出将布尔表达式翻译成四元式的语法制导定义。
解答:布尔表达式的语义子程序为:规则语义动作(1) E::=I {:=null;:=NXQ;【GEN (Jez , ENTRY(i), __,0) }(2) E::= i1 rop i2 { :=null;:=NXQ;GEN (Jnrop,ENTRY(i1), ENTRY(i2),0)}(3) E::= (E1) {:=, :=; }(4) E::= ¬ E1 { :=NXQ;GEN ( J, __, __, 0); BP , NXQ);}(5) E A::=E1∧{ if =null】then begin::=NXQ;GEN ( J, __, __, 0)End;BP ( , NXQ );:=null; := }(6) E ::= E A E2 {if ≠null,then beginBP , NXQ);:=nullEnd:=; }(7) E0::=E1∨{ if :=nullthen begin>:=NXQ;GEN ( J, __, __, 0)End;:=;BP ,NXG);}(8) E::=E0E2 { if ≠nullthen::=MERG,Else beginBP ,NXQ);:=End;:=}其中:~NXQ指示器指向下一个将要形成但尚未形成的四元式的地址(编号),初值为1,每当执行GEN一次,NXQ自动加1。
语法制导翻译
语法制导翻译
语法制导翻译是一种将源语言(通常为自然语言)的语法结构与目标语言的语法结构相对应的翻译方法。
它通过语法分析器和语法制导翻译器来实现。
在语法制导翻译中,源语言和目标语言的语法规则被定义成一个或多个上下文无关文法。
语法制导翻译的主要思想是在语法分析树中嵌入翻译动作,并通过语法制导翻译器将源语言转换为目标语言。
语法制导翻译器的主要任务是对每个语法分析树节点进行翻译动作的定义,并将这些翻译动作与语法分析器的分析过程相结合,最终生成目标语言的语法结构。
语法制导翻译是机器翻译领域的一种重要研究方向,它可以有效地解决自然语言翻译中的语言差异和歧义问题。
同时,它也是编译原理、计算机语言学等领域中的基础性问题。
语法制导翻译【共41张PPT】
一个属性文法称为L-属性文法,如果对于每个产生式
int T_val, R_i, R_s; int E_val;
AX1X2Xn,其中每条语义规则中的每个属性或者
是综合属性,或者是X (1jn)的一个继承属性且这 (3) E→(E(1))
val[ntop]= val[top–1]
使用标记非终结符M和N改写为
2. 函数过程A的代码(指用符号形式表示的数据和程序)
要根据当前的输入符号来决定使用哪一个产生式。
3. 与每一个产生式有关的代码,从左到右根椐产生式右部是
终结符(单词符号)、非终结符号还是语义动作,分别处 理:
保存下来,以便以后语义子程序引用这些信息。
原LR分析器的分析栈也加以扩充,存放三类信息:分析
状态、文法符号及文法符号对应的语义值。
top
sk
Xk
Xk.val
... ... ...
s1
X1
X1.val
s0
#
_
状态 文法符号 语义值
扩充后的LR分析栈
例6-3 考虑下面的语法制导定义
产生式
语义规则
9–5+2的带语义动作的分析树
设计翻译模式(根据语法制导定义)
语法制导定义是L-属性文法 保证语义动作不会引用还没有计算的属性值。
只需要综合属性的情况
为每一个语义规则建立一个包含赋值的动作,并把这个 动作放在相应的产生式右边的末尾。
例如:T T(1)*F T.val:=T(1).val*F.val
产生式 语义规则 A LM L.i:=l(A.i)
M.i:=m(L.s) A.s:=f(M.s) A QR R.i:=r(A.i) Q.i:=q(R.s) A.s:=f(Q.s)
编译第七章语法制导翻译_OK
{PRINT E ●VAL}
• (1)E E(1) +E(2) {E●VAL=E(1)●VAL+E(2)●VAL}
• (2)E E(1) * E(2) {E●VAL=E(1)●VAL*E(2)●VAL}
• (3)E (E(1)) {E●VAL=E(1)●VAL}
• (4)E i
{E●VAL=LEXVAL}
语义子程序
• (0)S’ E
{PRINT VAL[TOP]}
• (1)E E(1) +E(2) {VAL[TOP]=VAL[TOP]+VAL[TOP+2]}
• (2)E E(1) * E(2) {VAL[TOP]=VAL[TOP]*VAL[TOP+2]}
• (3)E (E(1)) {VAL[TOP]=[TOP+1]}
语义子程序
• (1)A i=E {GEN(=,E●PLACE,_,ENTRY(i)}
• (2)E -E(1) {T=NEWTEMP;
• ----
GEN(@,E(1)●PLACE,_,T);
• ----
E●PLACE=T}
• (3)E E(1)*E(2) {T=NEWTEMP;
•
GEN(*,E(1)●PLACE,E(2)●PLACE,T);
• 2、实例:对布尔式X+Y>Z∨A∧( B∨C) 进行翻译:
SYM栈
i i= i=i=-i i=-E i=E i=E* i=E*( i=E*(i i=E*(E
PLACE栈
---------B --T1 --T1--T1---T1--C --T1--C
生成四元式
(@,B,-,T1)
❖21
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
for循环语句翻译递归下降法输出三地址码/////////////#define MAX 100#include<iostream.h>#include<stdio.h>#include<string.h>char str[MAX];char ch;int turn;char strToken[MAX];int kind;int n=0;//存放strtoken[]元素的个数struct Word//结构体存放单词{int sort;char word[MAX];//存放strtoken[]的内容};//record[x]=new Word;Word *record[12];//放所有识别出来的单词,分别存放他们的编号以及字符串,x是其下标////////////////////词法分析///////////////////////int buffer()//载入{int i=0;cout<<"输入程序,以“#”作为结束标志。
"<<endl;for(int n=0;n<=MAX;n++){for(;i<=MAX;i++){scanf("%c",&str[i]);/////////////cin>>str[i]不可用,用C语言读入字符。
if(str[i]=='#')break;///////如果尾数为识别码#,则表示程序读完,跳出循环.}break;}return(i);bool IsLetter(char ch)///////////判断是否是字母{if(ch>=65&&ch<=90||ch>=97&&ch<=122)return(true);elsereturn(false);}bool IsDigit(char ch)//////////判断是否是数字{if(ch>=48&&ch<=57)return(true);elsereturn(false);}char GetChar(int i)///////读取字符{char ch;ch=str[i];return(ch);}char GetBC(char ch)////判断是不是空格或者换行,如果是,直接读取下一个字符直道不再空白为止{if(ch==32||ch==10){turn++;ch=GetChar(turn);ch=GetBC(ch);/////////递归实现return(ch);}elsereturn(ch);}void Concat()/////////////连接,即为strtoken[]赋值{strToken[n]=ch;n++;int Reserve()/////以单词为单位查找保留字,是则返回编码,不是则返回0,用来区分标志符和保留字{if(strcmp(strToken," DIM\0")==0)///////调用strcmp函数实现,return(1);else if(strcmp(strToken,"for\0")==0)return(2);else if(strcmp(strToken,"step\0")==0)return(3);else if(strcmp(strToken,"until\0")==0)return(4);else if(strcmp(strToken,"do\0")==0)return(5);elsereturn(6);}void clear(){n=0;}/////////////*语法递归分析*/////////////////int A(int * c,int & q){if(c[q++]==3){if(c[q]==7){ q++;return 1;}else {cout<<"step右部出错"<<endl;return 0;}}else {cout<<"error 'step'"<<endl;return 0;}}int B(int * b,int & o)if(b[o++]==4){if(b[o]==7){ o++;return 1;}else {cout<<"until右部出错"<<endl;return 0;}}else {cout<<"error 'until'"<<endl;return 0;}}int S2(int * d,int & h){if(d[h++]==6){if(d[h++]==8){if((d[h]==6||d[h]==7)) {h++; return 1;}else {cout<<"赋值语句右部出错"<<endl;return 0;}}else {cout<<"赋值语句缺少赋值运算符"<<endl;return 0;} }else {cout<<"赋值语句左部出错"<<endl;return 0;}}int S1(int * m,int & n){if(S2(m,n)){if(A(m,n)){if(B(m,n)) return 1;else return 0;}else return 0;}else return 0;}int S(int *a,int & z){if (a[z++]==2){if (S1(a,z)){if(a[z++]==5){{cout<<"succeed!"<<endl;return 1;}else return 0;}else {cout<<"error 'do'"<<endl; return 0;}}else return 0;}else {cout<<"error 'for'"<<endl; return 0;}}void main(){cout<<"*************产生式***************"<<endl;// for step until do i j =cout<<" S ->for S1 do S2"<<endl; // 编号2 3 4 5 6 7 8cout<<" S1 ->S2AB"<<endl;cout<<" S2 ->i=j"<<endl;cout<<" A ->stepj"<<endl;cout<<" B ->untilj"<<endl;int num;turn=0;num=buffer()-1;int x=0;//计识别的单词的个数for(;turn<=num;turn++)//总循环,ch存放刚读入的字符,strtoken[]存放已识别的标志付或保留字,turn是数组str[]的下标{ch=GetChar(turn);ch=GetBC(ch);if(IsLetter(ch)){while(IsLetter(ch)&&turn<=num||IsDigit(ch)&&turn<=num){Concat();ch=GetChar(++turn);}strToken[n]='\0';ch=NULL;//此ch不是标志符中的符号kind=Reserve();record[x]=new Word; record[x]->sort=kind;//12345或6 //cout<<kind; //测试cout<<"(";for(int i=0;i<n;i++){record[x]->word[i]=strToken[i];cout<<record[x]->word[i];//输出识别的标志符或保留字}cout<<","<<kind<<")"<<endl;record[x]->word[i]='\0';clear();x++;}else if(IsDigit(ch)){while(IsDigit(ch)&&turn<=num){Concat();ch=GetChar(++turn);}ch=NULL;turn=turn-1;kind=7;//////////////record[x]=new Word;record[x]->sort=kind;////////////////cout<<"(";for(int i=0;i<n;i++){record[x]->word[i]=strToken[i];cout<<record[x]->word[i];}cout<<","<<kind<<")"<<endl;record[x]->word[i]='\0';clear();x++;}else if(ch=='='){kind=8;///////record[x]=new Word;record[x]->word[0]='=';record[x++]->sort=kind;cout<<"(=,"<<kind<<")"<<endl;}elsecout<<"error input!"<<endl;}//////////////////////*语法分析*//////////////////int y;/*for(y=0;y<x;y++){cout<<record[y]->sort<<" ";//打印单词的编号。