A simple grammar compiler.
- 词法分析器设计
- 语法(语义)分析器设计
- 符号表设计
- 四元式生成
- 四元式优化
- 活跃信息生成
- 目标(8086汇编)代码生成
GrassGrowingMachine Hello.ggml Hello.asm
转至16位环境:
masm Hello.asm
link Hello.obj
Hello.exe
#ggml:grass-growing-machine language (这是个单行注释)
program p1; #程序开始动作
var #先声明全局变量,便于函数访问
{
int a; int b; int c;
real f; char ch; #没有const
}
function #函数声明
{
int f1
{
args #参数定义
{
val{int a; char b;} #赋值形参
ptr{int pa;} #换名形参
}
var #临时变量定义
{
int tmp;
}
body #函数体
{
tmp = a * 2;
if (tmp <= 0)
{
return 0;
}
else
{
tmp = a+2;
pa = 5;
return tmp+2;
}
return 1;
}
}
}
body
{
a = 1;
b = 2;
c = 3;
a = a+b;
a = f1(a;b+1;c;);
putc(a+48;); #ascii
putc(c+48;); #ascii
endp; #程序结束动作
}
注意:本套语言对大小写敏感
斜体非终结符不单独编写递归子程序
-
<程序> ::= <程序头声明><全局变量声明区><函数声明区><程序体>
-
<程序头声明> ::= program <标识符> ;
-
<标识符> ::= <字母> | <标识符><字母数字串>
-
<全局变量声明区> ::= var '{'{<变量定义>}'}'
-
<变量定义> ::= <数据类型><标识符>;
-
<数据类型> ::= int | char | real
-
<函数声明区> ::= function '{'{<函数定义>}'}'
-
<函数定义> ::= <数据类型><标识符>'{'<参数声明区><临时变量声明区><函数体>'}'
-
<参数声明区> ::= args '{'<赋值形参声明区><换名形参声明区>'}'
-
<赋值形参声明区> ::= val '{'{<函数变量定义>}'}'
-
<换名形参声明区> ::= ptr '{'{<函数变量定义>}'}'
-
<临时变量声明区> ::= var '{'{<函数变量定义>}'}'
-
<函数变量定义> ::= <数据类型><标识符>;
-
<函数体> ::= body '{'{<函数语句>}'}'
-
<函数语句> ::= <赋值语句> | <打印语句> | <结束语句> | <条件语句> | <循环语句> | <返回语句>
-
<返回语句> ::= return <表达式>;
-
<程序体> ::= body '{'{<程序语句>}'}'
-
<程序语句> ::= <赋值语句> | <打印语句> | <结束语句> | <条件语句> | <循环语句>
-
<赋值语句> ::= <标识符> '=' (<表达式>|<函数调用语句>);
-
<打印语句> ::= putc '('<表达式>;')';
-
<结束语句> ::= endp;
-
<条件语句> ::= if '('<表达式>')' '{'<复合语句>'}' else '{'<复合语句>'}' 需要根据语义情况判断语句块中为复合语句还是函数语句
-
<循环语句> ::= while '('<表达式>')' '{'<复合语句>'}'需要根据语义情况判断语句块中为复合语句还是函数语句
-
<函数调用语句> ::= <标识符> '(' {<表达式>;} ')' 注:对于函数调用,必须有一个变量接收返回值
-
<表达式> :== <逻辑表达式>
-
<逻辑表达式> :== <关系表达式><逻辑后缀式>
-
<逻辑后缀式> :== (and|or)<关系表达式><逻辑后缀式> | ε
-
<关系表达式> :== <算数表达式><关系后缀式>
-
<关系后缀式> :== ('>'|'<'|'=='|'>='|'<='|'!=')<算数表达式><关系后缀式> | ε
-
<算术表达式> :== <乘法表达式><加法后缀式>
-
<加法后缀式> :== ('+'|'-')<乘法表达式><加法后缀式> | ε
-
<乘法表达式> :== <项><乘法后缀式>
-
<乘法后缀式> :== ('*'|'/'|'%')<项><乘法后缀式> | ε
-
<项> :== (<标识符>|<常量>|'('<表达式>')') 注:没有负号,负数用0-n表示
-
程序头 (PROG, _, _, _)
-
全局变量声明区开头 (GV, _, _, _)
-
全局变量声明区结束 (GVE, _, _, _)
-
运行入口 (ENT, _, _, _)
-
程序出口 (EXIT, _, _, _)
-
程序尾 (END, _, _, _)
- 全局变量定义 (VAR, name, length, _)
- 局部变量定义 (VT, name, length, _)
-
加法语句 (ADD, arg1, arg2, tg)
-
减法语句 (SUB, arg1, arg2, tg)
-
乘法语句 (MUL, arg1, arg2, tg)
-
除法语句 (DIV, arg1, arg2, tg)
-
取余语句 (MOD, arg1, arg2, tg)
-
赋值语句 (ASSI, arg1, _, tg)
-
大于 (GT, arg1, arg2, tg)
-
大于等于 (GE, arg1, arg2, tg)
-
小于 (LT, arg1, arg2, tg)
-
小于等于 (LE, arg1, arg2, tg)
-
等于 (EQ, arg1, arg2, tg)
-
不等于 (NE, arg1, arg2, tg)
-
与 (AND, arg1, arg2, tg)
-
或 (OR, arg1, arg2, tg)
-
传参语句 (PARAM, arg1, _, funcname)
-
调用语句 (CALL, func, _, ret)
-
返回语句 (RET, arg1, _, _)
-
函数定义头 (FUNC, name, _, _)
-
函数定义尾 (EF, _, _, _)
-
if语句 (IF, arg1, _, _)
-
else语句 (EL, _, _, _)
-
if语句结束 (IE, _, _, _)
-
循环语句 (WH, _, _, _)
-
arg1不为0时做 (DO, arg1, _, _)
-
循环语句结束 (WE, _, _, _)
- 打印ASCII字符 (PUTC, arg1, _, _)
公用数据 (Tables.c)
词法分析器 (LexicalAnalyser.c): Tables.c
语法/语义分析器 (GrammarAnalyser.c): LexicalAnalyser.c, Tables.c, SymblList.c
符号表与四元式 (SymblList.c)
优化 (Optimizer.c): SymblList.c
目标代码生成 (DestGenerator.c): SymblList.c
在符号表主表中,当CAT为vfCAT, vnCAT, svCAT时,addr指向其所属的函数。
-
无法判断程序是否总能结束,以及函数是否总能返回。(建立条件判断分支树?)
-
变量、函数、参数定义时,未检查符号表中是否已经存在冲突的名称