⑴ 编译原理中pl/0符号表中oddsym是代表什么符号
判断一个表达式的结果是否为奇数,若为奇数返回真
⑵ 求C语言编译原理语法分析程序
一继承的词法来自
http://blog.sina.com.cn/s/blog_67c9fc300100srad.html
二语法
用扩充的BNF表示如下:
⑴<程序>::=begin<语句串>end
⑵<语句串>::=<语句>{;<语句>}
⑶<语句>::=<赋值语句>
⑷<赋值语句>::=ID:=<表达式>
⑸<表达式>::=<项>{+<项> | -<项>}
⑹<项>::=<因子>{*<因子> | /<因子>
⑺<因子>::=ID | NUM | (<表达式>)
三要求
输入单词串,以“#”结束,如果是文法正确的句子,则输出成功信息,打印“success”,否则输出“error”。
例如:
输入 begin a:=9; x:=2*3; b:=a+x end #
输出 success!
输入 x:=a+b*c end #
输出 error!
⑶ 什么是文法(编译原理)
【定义】
文法G定义为四元组(VN,VT,P,S)
其中 VN :非终结符号(即语法变量)集
VT : 终结符号集
VN∩VT =Φ,令V= VN∪VT,V称为文法G的字母表或字汇表。
P :产生式(α→β)集
S :开始符号,且S∈VN ,S至少要在一条规则的左部出现。
【约定】
一般地,文法G的 四元组 不用全部给出 ,而只将产生式写出。
约定:
(1)第一条产生式的左部是开始符号
(2)用尖括号括起来的(或 大写字母 )是非终结符号
(3)不用尖括号括起来(或 小写字母 )是终结符号
(4)还有一种习惯写法,即 G[S] ,其中 S 是 开始符号 。
【举例】
例: G=(VN,VT,P,S)
其中 VN={S},
VT ={0,1},
P={S→0S1,S→01}
S是开始符号
⑷ 编译原理全部的名词解释
书上有别那么懒!。。。。
编译过程的六个阶段:词法分析,语法分析,语义分析,中间代码生成,代码优化,目标代码生成
解释程序:把某种语言的源程序转换成等价的另一种语言程序——目标语言程序,然后再执行目标程序。解释方式是接受某高级语言的一个语句输入,进行解释并控制计算机执行,马上得到这句的执行结果,然后再接受下一句。
编译程序:就是指这样一种程序,通过它能够将用高级语言编写的源程序转换成与之在逻辑上等价的低级语言形式的目标程序(机器语言程序或汇编语言程序)。
解释程序和编译程序的根本区别:是否生成目标代码
句子的二义性(这里的二义性是指语法结构上的。):文法G[S]的一个句子如果能找到两种不同的最左推导(或最右推导),或者存在两棵不同的语法树,则称这个句子是二义性的。
文法的二义性:一个文法如果包含二义性的句子,则这个文法是二义文法,否则是无二义文法。
LL(1)的含义:(LL(1)文法是无二义的; LL(1)文法不含左递归)
第1个L:从左到右扫描输入串 第2个L:生成的是最左推导
1 :向右看1个输入符号便可决定选择哪个产生式
某些非LL(1)文法到LL(1)文法的等价变换: 1. 提取公因子 2. 消除左递归
文法符号的属性:单词的含义,即与文法符号相关的一些信息。如,类型、值、存储地址等。
一个属性文法(attribute grammar)是一个三元组A=(G, V, F)
G:上下文无关文法。
V:属性的有穷集。每个属性与文法的一个终结符或非终结符相连。属性与变量一样,可以进行计算和传递。
F:关于属性的断言或谓词(一组属性的计算规则)的有穷集。断言或语义规则与一个产生式相联,只引用该产生式左端或右端的终结符或非终结符相联的属性。
综合属性:若产生式左部的单非终结符A的属性值由右部各非终结符的属性值决定,则A的属性称为综合属
继承属性:若产生式右部符号B的属性值是根据左部非终结符的属性值或者右部其它符号的属性值决定的,则B的属性为继承属性。
(1)非终结符既可有综合属性也可有继承属性,但文法开始符号没有继承属性。
(2) 终结符只有综合属性,没有继承属性,它们由词法程序提供。
在计算时: 综合属性沿属性语法树向上传递;继承属性沿属性语法树向下传递。
语法制导翻译:是指在语法分析过程中,完成附加在所使用的产生式上的语义规则描述的动作。
语法制导翻译实现:对单词符号串进行语法分析,构造语法分析树,然后根据需要构造属性依赖图,遍历语法树并在语法树的各结点处按语义规则进行计算。
中间代码(中间语言)
1、是复杂性介于源程序语言和机器语言的一种表示形式。
2、一般,快速编译程序直接生成目标代码。
3、为了使编译程序结构在逻辑上更为简单明确,常采用中间代码,这样可以将与机器相关的某些实现细节置于代码生成阶段仔细处理,并且可以在中间代码一级进行优化工作,使得代码优化比较容易实现。
何谓中间代码:源程序的一种内部表示,不依赖目标机的结构,易于代码的机械生成。
为何要转换成中间代码:(1)逻辑结构清楚;利于不同目标机上实现同一种语言。
(2)便于移植,便于修改,便于进行与机器无关的优化。
中间代码的几种形式:逆波兰记号 ,三元式和树形表示 ,四元式
符号表的一般形式:一张符号表的的组成包括两项,即名字栏和信息栏。
信息栏包含许多子栏和标志位,用来记录相应名字和种种不同属性,名字栏也称主栏。主栏的内容称为关键字(key word)。
符号表的功能:(1)收集符号属性 (2) 上下文语义的合法性检查的依据: 检查标识符属性在上下文中的一致性和合法性。(3)作为目标代码生成阶段地址分配的依据
符号的主要属性及作用:
1. 符号名 2. 符号的类型 (整型、实型、字符串型等))3. 符号的存储类别(公共、私有)
4. 符号的作用域及可视性 (全局、局部) 5. 符号变量的存储分配信息 (静态存储区、动态存储区)
存储分配方案策略:静态存储分配;动态存储分配:栈式、 堆式。
静态存储分配
1、基本策略
在编译时就安排好目标程序运行时的全部数据空间,并能确定每个数据项的单元地址。
2、适用的分配对象:子程序的目标代码段;全局数据目标(全局变量)
3、静态存储分配的要求:不允许递归调用,不含有可变数组。
FORTRAN程序是段结构,不允许递归,数据名大小、性质固定。 是典型的静态分配
动态存储分配
1、如果一个程序设计语言允许递归过程、可变数组或允许用户自由申请和释放空间,那么,就需要采用动态存储管理技术。
2、两种动态存储分配方式:栈式,堆式
栈式动态存储分配
分配策略:将整个程序的数据空间设计为一个栈。
【例】在具有递归结构的语言程序中,每当调用一个过程时,它所需的数据空间就分配在栈顶,每当过程工作结束时就释放这部分空间。
过程所需的数据空间包括两部分
一部分是生存期在本过程这次活动中的数据对象。如局部变量、参数单元、临时变量等;
另一部分则是用以管理过程活动的记录信息(连接数据)。
活动记录(AR)
一个过程的一次执行所需要的信息使用一个连续的存储区来管理,这个区 (块)叫做一个活动记录。
构成
1、临时工作单元;2、局部变量;3、机器状态信息;4、存取链;
5、控制链;6、实参;7、返回地址
什么是代码优化
所谓优化,就是对代码进行等价变换,使得变换后的代码运行结果与变换前代码运行结果相同,而运行速度加快或占用存储空间减少。
优化原则:等价原则:经过优化后不应改变程序运行的结果。
有效原则:使优化后所产生的目标代码运行时间较短,占用的存储空间较小。
合算原则:以尽可能低的代价取得较好的优化效果。
常见的优化技术
(1) 删除多余运算(删除公共子表达式) (2) 代码外提 +删除归纳变量+ (3)强度削弱; (4)变换循环控制条件 (5)合并已知量与复写传播 (6)删除无用赋值
基本块定义
程序中只有一个入口和一个出口的一段顺序执行的语句序列,称为程序的一个基本块。
给我分数啊。。。
⑸ 编译原理——LR分析表
自底向上的语法分析
LR分析表的结构如上,其分为两个部分 Action Goto
两个参数状态i,终结符号a(s(i)代表第i个状态,r(i)代表第i条表达式)
Goto[i,A]=j
文法
容易得知这个文法可以推出 0 1 00 01 等的字符串。因为它是 左递归 。不适用于 LL 文法分析,只能使用 LR 分析。
因为本题入口有两个—— S → L·L S → L ,所以需要构造额外的产生式 S'->S
2.1 第一次遍历
我们从 [S -> . L·L] 开始,构造这个状态的闭包,也就是加上所有能从这个产生式推出的表项。
首先,判断 . 后面是否为 非终结符号A 。如果是,那我们就得找所有由 A-> 推出的产生式,并将它们添加进入 闭包 里(也就是State包里)。循环做即可。
因此我们可以得到 State 0 有
下一步,就是我的 . 往下一位移动。对每个符号X后有个 . 的项,都可以从 State 0 过渡到其他状态。
由以上6条式子可以得知下一位符号可以是 S L B 0 1 。所以自然可以得到5个状态。
State 1 是由 State 0 通过 S 转移到这里的,所以我们找出所有 State 0 中在 S 前有 . 的项。
此状态作为结束状态 Accept ,不需要继续状态转移了。
State 2 是由 State 0 通过 L 转移到这里的,所以我们找出所有 State 0 中在 L 前有 . 的项。
S -> . L·L S -> . L L -> . LB
有3条式子,现在我们将 . 向后推一格,就得到 State 1 的项了。
但是 . 之后的符号分别是 · $ B , B 为非终结符号,我们得包含 B -> 的项
State 3 是由 State 0 通过 B 转移到这里的,所以我们找出所有 State 0 中在 B 前有 . 的项。
因为 . 后没有其他符号了,因此这个状态不需要继续转移了。
State 4 是由 State 0 通过 0 转移到这里的,所以我们找出所有 State 0 中在 0 前有 . 的项。
因为 . 后没有其他符号了,因此这个状态不需要继续转移了。
很简单,同样的道理找 State 5
State 5 是由 State 0 通过 1 转移到这里的,所以我们找出所有 State 0 中在 1 前有 . 的项。
因为 . 后没有其他符号了,因此这个状态不需要继续转移了。
好的,现在我们第一次遍历完成。
2.2 第二次遍历
第二次遍历自然从 State 2 开始。
我们回到 State2 ,可以看出 . 之后的符号有 · B 0 1 。
State 6 是由 State 2 通过 · 转移到这里的,所以我们找出所有 State 2 中在 · 前有 . 的项。
S -> L. ·L 只有1条,我们往后移发现 L 又为非终结符号,参考 State 0 做的操作,我们得找出所有的式子。
共有5条式子,共同组成 State 6 ,由上面的式子可以看出我们还得继续下一次遍历。先不管着,我们进行下一次状态查找。
State 7 是由 State 2 通过 B 转移到这里的,所以我们找出所有 State 2 中在 B 前有 . 的项。
L -> L. B 也是只有1条,我们往后移发现没有非终结符号了,那就不需要再继续添加其他式子了。
这个状态也不需要继续进行转移了。
接下来很关键,因为我们通过 State2 的 . 后的符号找出了 State 6 State 7 ,接下来还差符号 0 1 ,那么是否像之前一样按例添加状态呢, 答案是不是的 ,因为我们发现通过 0 1 找到的闭包集分别是 B -> 0 B -> 1 ,这与我们的之前的 State 4 State 5 相同。所以我们得将其整合起来,相当于 State 2 通过 0 1 符号找到了 State 4 State 5 状态。
2.3 第三次遍历
回头看第二次遍历,可以看出只有 State 6 可以进行状态转移了。
那么就将 State 6 作为第三次遍历的源头,可以看出 . 之后的符号有 L B 0 1 。
State 8 是由 State 6 通过 L 转移到这里的,所以我们找出所有 State 6 在 L 前有 . 的项。
S -> L· .L L -> . LB 有两条式子,往后移发现有非终结符号 B ,所以经过整合可以得到
可以看出 . 的后面还有一个符号,所以这里我们还得再进行一次遍历。
接下来,又是遇到重复的包的情况,可以看出我们由 State 6 通过 B 0 1 得到的闭包分别是 L->B B->0 B->1 ,很明显,这分别对应于 State 3 State 4 State 5 。
第三次遍历也就结束了。
2.4 第四次遍历
回看第三次遍历,可以看出只有 State 8 可以进行状态转移,其 . 之后的符号分别是 B 0 1 。
诶,感觉很熟悉,就是上面几行刚说的情况,也就是说通过这三个符号找到的闭包是我们之前遇到的状态,分别是 State 3 State 4 State 5 。
做到这里,我们发现我们已经全部遍历完毕!
总共有8个状态,通过以上流程做成个图是什么样子的?来看看!
这么一看就很清晰明了了,我们就可以通过这个图做出我们的 LR分析表
其实就是我们之前呈现的表
在状态 I2 和 I8 中,既有 移入 项目,也有 规约 项目,存在 移入 - 规约的冲突 ,所以不是 LR(0) 文法,但是因为 FOLLOW(S) ∩ {0, 1} = ∅,所以可以用 FOLLOW 集解决冲突,所以该文法是 SLR(1) 文法。
上表我们发现还有 r1,r2,r3 等。这个其实就是代表状态停止转移时为 第几条表达式 ,r3代表第三条表达式 L -> LB 。
当我们构建了表之后,我们如何运用起来呢?
下面我们通过一个例子来说明
以上字符串是如何被SLR分析器识别的呢?
⑹ 编译原理有有符号un-1.u=un吗
编译程序把源程序翻译为目标程序。根据源程序的语言种类,翻译程序可以分为汇编程序与编译程序。与之相对,解释程序是对源程序进行解释执行的程序。相应的可以将高级语言分为
编译型 C/C++, Swift, etc.
解释型 Python, javascript, etc.
混合型 Java, etc.
本文重点放在编译程序的设计上。典型的编译程序具有 7 77 个逻辑部分
对源程序扫描一次被称为一遍 (pass)。典型的一遍扫描编译程序有如下形式
通常将中间代码生成前的分析部分称为编译器的前端,其后的综合部分则被称为后端。这样就把一个编译程序分为了与源语言相关和与目标机有关的两个独立的部分,降低了程序的耦合。假设 llvm 编译器 支持 M MM 种源语言到 N NN 种目标语言的编译
传统的编译器如 gcc 可能需要开发 M × N M \times NM×N 个不同的子模块。而 llvm 使用统一的中间语言 llvm Intermediate Representation 只需要 M MM 个前端与 N NN 个后端,大大降低了开发成本。
文法
设非空有穷集合 Σ \SigmaΣ 为一字母表,则其上的符号串为 ∀ s ∈ Σ ∗ \forall s \in \Sigma^*∀s∈Σ
∗
,其中 ∗ *∗ 表示集合的闭包。特别的记 Σ 0 = ε \Sigma^0 = {\varepsilon}Σ
0
=ε 为空串组成的集合。规则通常写作
U : : = x or U → x , ∣ U ∣ = 1 , ∣ x ∣ ≥ 0 U ::= x\text{ or }U\rightarrow x,\quad |U| = 1, |x| \ge 0U::=x or U→x,∣U∣=1,∣x∣≥0
其中左部 U UU 是符号,右部 x xx 是有穷符号串。规则的集合 P PP 即可确定一个文法 G GG
<程序> ::= <常量说明><变量说明><函数说明>
<常量说明> ::= {const<常量定义>;}
<常量定义> ::= int<标识符>=<整数>{,<标识符>=<整数>}|char<标识符>=<字符>{,<标识符>=<字符>}
<变量说明> ::= {<类型标识符><变量定义>;}
<变量定义> ::= <标识符>[<下标>]{,<标识符>[<下标>]}
<下标> ::= '['<无符号整数>']' // <无符号整数>表示数组元素的个数,其值需大于0
<函数说明> ::= {(<类型标识符>|void)<函数定义>}void<主函数>
<函数定义> ::= <标识符>'('<参数表>')'<复合语句>
<参数表> ::= [<类型标识符><标识符>{,<类型标识符><标识符>}]
<主函数> ::= main'('')'<复合语句>
<复合语句> ::= '{'<常量说明><变量说明>{<语句>}'}'
<语句> ::= <条件语句>|'{'{<语句>}'}'|<函数调用语句>;|<赋值语句>;|<读语句>;|<写语句>;|<返回语句>;|;
<条件语句> ::= <if语句>|<while语句>|<do语句>|<for语句>
<if语句> ::= if'('<条件>')'<语句>[else<语句>]
<while语句> ::= while'('<条件>')'<语句>
<do语句> ::= do<语句>while'('<条件>')'
<for语句> ::= for'('<标识符>=<表达式>;<条件>;<标识符>=<标识符><加法运算符><无符号整数>')'<语句>
<条件> ::= <表达式>[<关系运算符><表达式>] // 表达式为0条件为假,否则为真
<函数调用语句> ::= <标识符>'('[<表达式>{,<表达式>}]')'
<赋值语句> ::= <标识符>['['<表达式>']']=<表达式>
<读语句> ::= scanf'('<标识符>{,<标识符>}')'
<写语句> ::= printf'('<字符串>[,<表达式>]')'|printf'('<表达式>')'
<返回语句> ::= return['('<表达式>')']
<表达式> ::= [<加法运算符>]<项>{<加法运算符><项>} // [+|-]只作用于第一个<项>
<项> ::= <因子>{<乘法运算符><因子>}
<因子> ::= <标识符>['['<表达式>']']|'('<表达式>')'|<整数>|<字符>|<函数调用语句>
<整数> ::= [<加法运算符>]<无符号整数>
<标识符> ::= <字母>{<字母>|<数字>}
<无符号整数> ::= <非零数字>{<数字>}|0
<数字> ::= 0|<非零数字>
<非零数字> ::= 1|...|9
<字符> ::= '<加法运算符>'|'<乘法运算符>'|'<字母>'|'<数字>'
<字符串> ::= "{十进制编码为32,33,35-126的ASCII字符}"
<类型标识符> ::= int|char
<加法运算符> ::= +|-
<乘法运算符> ::= *|/
<关系运算符> ::= <|<=|>|>=|!=|==
<字母> ::= _|a|...|z|A|...|Z
复制
上述文法使用扩充的 BNF 表示法进行描述
符号 定义 说明
∣ \vert∣ 或 作用域由括号限定
{ t } n m \{t\}^m_n{t}
n
m
将 t tt 重复连接 n ∼ m n \sim mn∼m 次 缺省时 m = ∞ , n = 0 m = \infin,\ n = 0m=∞, n=0
[ t ] [t][t] 符号串 t tt 可有可无 等价于 { t } 1 \{t\}^1{t}
1
( t ) (t)(t) 局部作用域 主要用于限定 ∣ \vert∣ 范围
相关概念有
概念 符号 定义 示例
识别符号 Z ZZ 文法中第一条规则的左部符号 <程序>
字汇表 V VV 文法中出现的全部符号 { <程序>, <常量说明>, …, 0, 1, … }
非终结符号集 V n V_nV
n
全部规则的左部组成的集合 { <程序>, <常量说明>, <变量说明>, … }
终结符号集 V t V_tV
t
V − V n V - V_nV−V
n
{ 0, 1, …, _, a, b, … }
设 U : : = u ∈ P U ::= u \in PU::=u∈P 则对于 ∀ x , y ∈ V ∗ \forall x, y \in V^*∀x,y∈V
∗
有直接推导 x U y ⇒ x u y xUy \Rightarrow xuyxUy⇒xuy 。如果 y ∈ V t ∗ y \in V_t^*y∈V
t
∗
则 x U y ⤃ x u y xUy\ ⤃\ xuyxUy ⤃ xuy 称为规范推导。直接推导序列 u 0 ⇒ u 1 ⇒ ⋯ ⇒ u n u_0 \Rightarrow u_1 \Rightarrow \cdots \Rightarrow u_nu
0
⇒u
1
⇒⋯⇒u
n
可简记为
{ u 0 ⇒ + u n n > 0 u 0 ⇒ ∗ u n n ≥ 0 \begin{cases} u_0 \mathop\Rightarrow\limits^+ u_n & n > 0\\ u_0 \mathop\Rightarrow\limits^* u_n & n \ge 0\\ \end{cases}{
u
0
⇒
+
u
n
u
0
⇒
∗
u
n
n
>
0
n
≥
0
进一步定义
句型 V ∗ ∋ x ⇐ ∗ Z V^* \ni x \mathop\Leftarrow\limits^* ZV
∗
∋x
⇐
∗
Z
句子 V t ∗ ∋ x ⇐ + Z V_t^* \ni x \mathop\Leftarrow\limits^+ ZV
t
∗
∋x
⇐
+
Z
语言 L ( G ) = { x ∣ x is sentence } L(G) = \{ x| x\text{ is sentence} \}L(G)={x∣x is sentence}
如果文法 G GG 和 G ′ G'G
′
有 L ( G ) = L ( G ′ ) L(G) = L(G')L(G)=L(G
′
) ,则称这两个文法等价。设 w = x u y w=xuyw=xuy 为一句型,称 u uu 为一个相对于 U ∈ V n U \in V_nU∈V
n
的
w ww 的短语 如果 Z ⇒ ∗ x U y ∧ U ⇒ + u Z \mathop\Rightarrow\limits^* xUy \land U \mathop\Rightarrow\limits^+ uZ
⇒
∗
xUy∧U
⇒
+
u
w ww 的简单短语 如果 u uu 是短语且 U ⇒ u U \mathop\Rightarrow\limits uU⇒u
句型的最左简单短语称为句柄。
二义性
文法 G GG 是二义性的,如果 ∃ x ∈ L ( G ) \exist x \in L(G)∃x∈L(G) 使下列条件之一成立
x xx 可以对应两颗不同的语法树
x xx 有两个不同的规范推导
⑺ 编译原理课程设计
%{
/* FILENAME: C.Y */
%}
#define YYDEBUG_LEXER_TEXT (yylval) /* our lexer loads this up each time */
#define YYDEBUG 1 /* get the pretty debugging code to compile*/
#define YYSTYPE char * /* interface with flex: should be in header file */
/* Define terminal tokens */
/* keywords */
%token AUTO DOUBLE INT STRUCT
%token BREAK ELSE LONG SWITCH
%token CASE ENUM REGISTER TYPEDEF
%token CHAR EXTERN RETURN UNION
%token CONST FLOAT SHORT UNSIGNED
%token CONTINUE FOR SIGNED VOID
%token DEFAULT GOTO SIZEOF VOLATILE
%token DO IF STATIC WHILE
/* ANSI Grammar suggestions */
%token IDENTIFIER STRINGliteral
%token FLOATINGconstant INTEGERconstant CHARACTERconstant
%token OCTALconstant HEXconstant
/* New Lexical element, whereas ANSI suggested non-terminal */
%token TYPEDEFname /* Lexer will tell the difference between this and
an identifier! An identifier that is CURRENTLY in scope as a
typedef name is provided to the parser as a TYPEDEFname.*/
/* Multi-Character operators */
%token ARROW /* -> */
%token ICR DECR /* ++ -- */
%token LS RS /* << >> */
%token LE GE EQ NE /* <= >= == != */
%token ANDAND OROR /* && || */
%token ELLIPSIS /* ... */
/* modifying assignment operators */
%token MULTassign DIVassign MODassign /* *= /= %= */
%token PLUSassign MINUSassign /* += -= */
%token LSassign RSassign /* <<= >>= */
%token ANDassign ERassign ORassign /* &= ^= |= */
%start translation_unit
%%
/* CONSTANTS */
constant:
INTEGERconstant
| FLOATINGconstant
/* We are not including ENUMERATIONconstant here because we
are treating it like a variable with a type of "enumeration
constant". */
| OCTALconstant
| HEXconstant
| CHARACTERconstant
;
string_literal_list:
STRINGliteral
| string_literal_list STRINGliteral
;
/************************* EXPRESSIONS ********************************/
primary_expression:
IDENTIFIER /* We cannot use a typedef name as a variable */
| constant
| string_literal_list
| '(' comma_expression ')'
;
postfix_expression:
primary_expression
| postfix_expression '[' comma_expression ']'
| postfix_expression '(' ')'
| postfix_expression '(' argument_expression_list ')'
| postfix_expression {} '.' member_name
| postfix_expression {} ARROW member_name
| postfix_expression ICR
| postfix_expression DECR
;
member_name:
IDENTIFIER
| TYPEDEFname
;
argument_expression_list:
assignment_expression
| argument_expression_list ',' assignment_expression
;
unary_expression:
postfix_expression
| ICR unary_expression
| DECR unary_expression
| unary_operator cast_expression
| SIZEOF unary_expression
| SIZEOF '(' type_name ')'
;
unary_operator:
'&'
| '*'
| '+'
| '-'
| '~'
| '!'
;
cast_expression:
unary_expression
| '(' type_name ')' cast_expression
;
multiplicative_expression:
cast_expression
| multiplicative_expression '*' cast_expression
| multiplicative_expression '/' cast_expression
| multiplicative_expression '%' cast_expression
;
additive_expression:
multiplicative_expression
| additive_expression '+' multiplicative_expression
| additive_expression '-' multiplicative_expression
;
shift_expression:
additive_expression
| shift_expression LS additive_expression
| shift_expression RS additive_expression
;
relational_expression:
shift_expression
| relational_expression '<' shift_expression
| relational_expression '>' shift_expression
| relational_expression LE shift_expression
| relational_expression GE shift_expression
;
equality_expression:
relational_expression
| equality_expression EQ relational_expression
| equality_expression NE relational_expression
;
AND_expression:
equality_expression
| AND_expression '&' equality_expression
;
exclusive_OR_expression:
AND_expression
| exclusive_OR_expression '^' AND_expression
;
inclusive_OR_expression:
exclusive_OR_expression
| inclusive_OR_expression '|' exclusive_OR_expression
;
logical_AND_expression:
inclusive_OR_expression
| logical_AND_expression ANDAND inclusive_OR_expression
;
logical_OR_expression:
logical_AND_expression
| logical_OR_expression OROR logical_AND_expression
;
conditional_expression:
logical_OR_expression
| logical_OR_expression '?' comma_expression ':'
conditional_expression
;
assignment_expression:
conditional_expression
| unary_expression assignment_operator assignment_expression
;
assignment_operator:
'='
| MULTassign
| DIVassign
| MODassign
| PLUSassign
| MINUSassign
| LSassign
| RSassign
| ANDassign
| ERassign
| ORassign
;
comma_expression:
assignment_expression
| comma_expression ',' assignment_expression
;
constant_expression:
conditional_expression
;
/* The following was used for clarity */
comma_expression_opt:
/* Nothing */
| comma_expression
;
/******************************* DECLARATIONS *********************************/
/* The following is different from the ANSI C specified grammar.
The changes were made to disambiguate typedef's presence in
declaration_specifiers (vs. in the declarator for redefinition);
to allow struct/union/enum tag declarations without declarators,
and to better reflect the parsing of declarations (declarators
must be combined with declaration_specifiers ASAP so that they
are visible in scope).
Example of typedef use as either a declaration_specifier or a
declarator:
typedef int T;
struct S { T T;}; /* redefinition of T as member name * /
Example of legal and illegal statements detected by this grammar:
int; /* syntax error: vacuous declaration * /
struct S; /* no error: tag is defined or elaborated * /
Example of result of proper declaration binding:
int a=sizeof(a); /* note that "a" is declared with a type in
the name space BEFORE parsing the initializer * /
int b, c[sizeof(b)]; /* Note that the first declarator "b" is
declared with a type BEFORE the second declarator is
parsed * /
*/
declaration:
sue_declaration_specifier ';'
| sue_type_specifier ';'
| declaring_list ';'
| default_declaring_list ';'
;
/* Note that if a typedef were redeclared, then a declaration
specifier must be supplied */
default_declaring_list: /* Can't redeclare typedef names */
declaration_qualifier_list identifier_declarator {} initializer_opt
| type_qualifier_list identifier_declarator {} initializer_opt
| default_declaring_list ',' identifier_declarator {} initializer_opt
;
declaring_list:
declaration_specifier declarator {} initializer_opt
| type_specifier declarator {} initializer_opt
| declaring_list ',' declarator {} initializer_opt
;
declaration_specifier:
basic_declaration_specifier /* Arithmetic or void */
| sue_declaration_specifier /* struct/union/enum */
| typedef_declaration_specifier /* typedef*/
;
type_specifier:
basic_type_specifier /* Arithmetic or void */
| sue_type_specifier /* Struct/Union/Enum */
| typedef_type_specifier /* Typedef */
;
declaration_qualifier_list: /* const/volatile, AND storage class */
storage_class
| type_qualifier_list storage_class
| declaration_qualifier_list declaration_qualifier
;
type_qualifier_list:
type_qualifier
| type_qualifier_list type_qualifier
;
declaration_qualifier:
storage_class
| type_qualifier /* const or volatile */
;
type_qualifier:
CONST
| VOLATILE
;
basic_declaration_specifier: /*Storage Class+Arithmetic or void*/
declaration_qualifier_list basic_type_name
| basic_type_specifier storage_class
| basic_declaration_specifier declaration_qualifier
| basic_declaration_specifier basic_type_name
;
basic_type_specifier:
basic_type_name /* Arithmetic or void */
| type_qualifier_list basic_type_name
| basic_type_specifier type_qualifier
| basic_type_specifier basic_type_name
;
sue_declaration_specifier: /* Storage Class + struct/union/enum */
declaration_qualifier_list elaborated_type_name
| sue_type_specifier storage_class
| sue_declaration_specifier declaration_qualifier
;
sue_type_specifier:
elaborated_type_name /* struct/union/enum */
| type_qualifier_list elaborated_type_name
| sue_type_specifier type_qualifier
;
typedef_declaration_specifier: /*Storage Class + typedef types */
typedef_type_specifier storage_class
| declaration_qualifier_list TYPEDEFname
| typedef_declaration_specifier declaration_qualifier
;
typedef_type_specifier: /* typedef types */
TYPEDEFname
| type_qualifier_list TYPEDEFname
| typedef_type_specifier type_qualifier
;
storage_class:
TYPEDEF
| EXTERN
| STATIC
| AUTO
| REGISTER
;
basic_type_name:
INT
| CHAR
| SHORT
| LONG
| FLOAT
| DOUBLE
| SIGNED
| UNSIGNED
| VOID
;
elaborated_type_name:
aggregate_name
| enum_name
;
aggregate_name:
aggregate_key '{' member_declaration_list '}'
| aggregate_key identifier_or_typedef_name
'{' member_declaration_list '}'
| aggregate_key identifier_or_typedef_name
;