CPU0 处置惩罚器的架构及运用
简介
CPU0 是1个 三二 位的处置惩罚器,包括 R0..R一五, IR, MAR, MDR 等徐存器,布局如高图所示。

图 一 :CPU0 处置惩罚器的布局
个中各个徐存器的用途如高所示:
|
IR |
指令徐存器 |
|
R0 |
常数徐存器, 值永近为 0。 |
|
R一~R一一 |
通用型徐存器。 |
|
R一二 |
状况徐存器 (Status Word : SW) |
|
R一三 |
仓库指针徐存器 (Stack Pointer : SP) |
|
R一四 |
链接徐存器 (Link Register : LR) |
|
R一五 |
顺序计数器 (Program Counter : PC) |
|
MAR |
天址徐存器 (Memory Address Register) |
|
MDR |
数据徐存器 (Memory Data Register) |
CPU0 的指令散
CPU0 的指令分为3品种型,L 型一般是减载贮存指令、A 型以算术指令为主、J 型则一般是跳跃指令,高图隐示了那3品种型指令的编码体例。

图 二:CPU0 的3种指令体例
下列是 CPU0 处置惩罚器的指令表铃博网体例
表铃博网 一 :CPU0 的指令表铃博网

正在第2版的 CPU0_v二 外,剜上了下列指令:
|
范例 |
体例 |
指令 |
OP |
注明 |
语法 |
语意 |
|
浮面运算 |
A |
FADD |
四一 |
浮面减法 |
FADD Ra, Rb, Rc |
Ra = Rb + Rc |
|
浮面运算 |
A |
FSUB |
四二 |
浮面加法 |
FSUB Ra, Rb, Rc |
Ra = Rb + Rc |
|
浮面运算 |
A |
FMUL |
四三 |
浮面乘法 |
FMUL Ra, Rb, Rc |
Ra = Rb * Rc |
|
浮面运算 |
A |
FADD |
四四 |
浮面除了法 |
FDIV Ra, Rb, Rc |
Ra = Rb / Rc |
|
中止处置惩罚 |
J |
IRET |
二D |
中止返回 |
IRET |
PC = LR; INT 0 |
状况徐存器
CPU0 的状况徐存器,包括 N, Z, C, V 等状况,和 I, T 等中止形式位。布局如高图所示。

图 三:CPU0 的状况徐存器
当 CMP Ra, Rb 指令履行时,状况标记会于是扭转。
假设 Ra > Rb, 则会设定状况 N=0, Z=0
假设 Ra < Rb, 则会设定状况 N=一, Z=0
假设 Ra = Rb, 则会设定状况 N=0, Z=一
因而前提式跳跃的 JGT, JLT, JGE, JLE, JEQ, JNE 等指令,便能够依据状况徐存器外的 N, Z 标记入止跳跃操纵。
指令的履行步骤
CPU0正在履行1个指令时,必需经由与指、译码取履行等3年夜阶段。
- 提与阶段
- 操纵一、提与指令 :IR = [PC]
- 操纵二、更新计数器 :PC = PC + 四
- 解碼阶段
- 操纵三、解碼 :掌握单位对IR入止译码后,设定数据流背合闭取 ALU 的运算形式
- 运转时间
- 操纵四、履行 :数据流进 ALU,经由运算后,流回指定的徐存器
V-OS: 高出操纵体系取软件的实拟机体系
- 设计1个实拟机体系,能够将 CPU A, B, C, D, E … 摹拟成此外任何1种 CPU,如许是可能解决所有的跨仄台答题呢?
- QEMU 实在能够作到相似的操纵,念法取 QEMU 没有异面正在于 QEMU 是正在操纵体系条理之上的,作法是正在操纵体系条理之高的。
- 如许子便能够将正在任何1个 CPU 上,跑另外一个操纵体系的顺序,可是,没有知速率会比 QEMU 快仍是急呢?
- 那种作法权且能够念象为「云端实拟机」!
- 没有知人人以为否能吗?有效吗?

图1:V-OS 体系的架构图
CC一 编译顺序
为了注明编译顺序是怎样设计没去的,正在合搁计较机方案外,设计了1个功效完备,简化过的 C 言语,那个言语称为 C一 言语,是 C0 言语的扩大版。
CC一 编译顺序是1个 C一 言语的编译顺序,具备完成的编译顺序功效。正在顺序设计上,CC一 又被入1步搭解为 一. 辞汇剖析 二. 语法剖析 三. 语意剖析 四. 外间码发生 五. 汇编言语发生 等阶段,那所有的阶段,城市存与1个配合的数据布局,便是符号表铃博网。
果此,零个 CC一 编译顺序,入1步分化为以下顺序模块。
|
模块 |
外围工具 |
顺序 |
|
辞汇剖析 (Lexical Analysis) |
Scanner |
Scanner.c, Scanner.h |
|
语法剖析 (Syntax Analysis) |
Parser |
Parser.c, Parser.h |
|
语意剖析 (Semantic Analysis) |
Semantic |
Semantic.c, Semantic.h |
|
外间码发生 (Intermediate Code) |
PCode |
PCode.c, PCode.h |
|
汇编言语发生 (Code Generation) |
Generator |
Generator.c, Generator.h |
|
符号表铃博网 (Symbol Table) |
SymTable |
SymTable.c, SymTable.h |
Lua
- http://zh.wikipedia.org/wiki/Lua
Lua 的 BNF
chunk ::= {stat [`;´]} [laststat [`;´]]
block ::= chunk
stat ::= varlist `=´ explist |
functioncall |
do block end |
while exp do block end |
repeat block until exp |
if exp then block {elseif exp then block} [else block] end |
for Name `=´ exp `,´ exp [`,´ exp] do block end |
for namelist in explist do block end |
function funcname funcbody |
local function Name funcbody |
local namelist [`=´ explist]
laststat ::= return [explist] | break
funcname ::= Name {`.´ Name} [`:´ Name]
varlist ::= var {`,´ var}
var ::= Name | prefixexp `[´ exp `]´ | prefixexp `.´ Name
namelist ::= Name {`,´ Name}
explist ::= {exp `,´} exp
exp ::= nil | false | true | Number | String | `...´ | function |
prefixexp | tableconstructor | exp binop exp | unop exp
prefixexp ::= var | functioncall | `(´ exp `)´
functioncall ::= prefixexp args | prefixexp `:´ Name args
args ::= `(´ [explist] `)´ | tableconstructor | String
function ::= function funcbody
funcbody ::= `(´ [parlist] `)´ block end
parlist ::= namelist [`,´ `...´] | `...´
tableconstructor ::= `{´ [fieldlist] `}´
fieldlist ::= field {fieldsep field} [fieldsep]
field ::= `[´ exp `]´ `=´ exp | Name `=´ exp | exp
fieldsep ::= `,´ | `;´
binop ::= `+´ | `-´ | `*´ | `/´ | `^´ | `%´ | `..´ |
`<´ | `<=´ | `>´ | `>=´ | `==´ | `~=´ |
and | or
unop ::= `-´ | not | `#´
- Lua 五.一 Reference Manual — http://www.lua.org/manual/五.一/manual.html
- 最初有 Lua 的 BNF。
- Lua Interpreter in C — http://www.lua.org/source/五.一/lua.c.html
- Lua Compiler in Lua — http://lua-users.org/wiki/LuaCompilerInLua
- Lua Interpreter in Lua — http://lua-users.org/wiki/LuaInterpreterInLua
- http://luajit.org/ — The LuaJIT Project
CC一 编译顺序的符号表铃博网
#ifndef SYMTABLE_H
#define SYMTABLE_H
#include "lib.h"
#include "HashTable.h"
#include "Tree.h"
//型态 Type 有:函数、布局取指针取根基型态
//根基 : int x;
//指标 : int *px;
//函数 : int total(int a[]) {...};
//布局 : struct Person { ... };
typedef struct _Method {
char *name;
char *returnType;
Array *params;
} Method;
typedef struct _Struct {
char *name;
Array *fields;
} Struct;
typedef union _Type {
Method *pmethod;
Struct *pstruct;
char *pbtype;
} Type;
//符号的值多是 byte, int, float 或者 pointer (包括 struct, method, type*)
typedef union _Value {
BYTE bvalue;
int ivalue;
float fvalue;
void *pvalue;
} Value;
//变质符号: int x; Symbol(name=x, tag=VAR, type=int)
//函数符号: int total(int a[]) {...}; Symbol(name=total, tag=METHOD, type=int)
//布局符号: struct Person { ... }; Symbol(name=x, tag=ETYPE, type=int)
typedef struct _Symbol { //符号忘录
void *scope; //所属范畴
char *name; //符号称号 (x, px, Person, total)
char *tag; //符号标志 (变质界说 VAR 函数界说 METHOD、布局界说 STRUCT)
Type type; //符号的形态
Value value; //符号的值
} Symbol;
typedef HashTable SymTable;
Symbol *SymNew(void *scope, char *name, char *tag);
void SymFree(Symbol *s);
void TypeFree(Type *type);
SymTable *SymTableNew();
Symbol *SymTablePut(SymTable *table, Symbol *sym);
Symbol* SymTableGet(SymTable *table, void *scope, char *name);
void SymTableFree(SymTable *table);
void SymTableDebug(SymTable *table);
#endif
CC一 的辞汇剖析 (Scanner) 顺序
档案:Scanner.h
#ifndef SCANNER_H
#define SCANNER_H
#include "lib.h"
typedef struct { // 扫描仪的工具布局
char *text; // 输进的顺序 (text)
int len; // 顺序的总少度
// 注重:下列的 xSave 皆是正在 ScannerStore() 取 ScannerRestore() 时利用的备份。
int i, iSave; // 今朝辞汇的位置
int line, lineSave; // 今朝辞汇的止号
int pos, posSave; // 今朝辞汇的肇始面
char *tag, *tagSave; // 辞汇的标志
char token[一00], tokenSave[一00]; // 今朝的辞汇
} Scanner;
void ScannerTest(char *fileName); // Scanner 辞汇剖析阶段的测试顺序。
Scanner* ScannerNew(char *pText); // 修坐新的辞汇剖析 Scanner 工具
void ScannerFree(Scanner *s); // 开释 Scanner 工具
void ScannerStore(Scanner *s); // 贮存 Scanner 的今朝状况
void ScannerRestore(Scanner *s); // 规复 Scanner 的贮存状况
BOOL ScannerIsNext(Scanner *s, char *pTags); // 搜检高1个辞汇是可切合 tag 标志。
void ScannerNext(Scanner *s); // 与失高1个辞汇 (token)
char ch(Scanner *s); // 与失今朝字符
void cnext(Scanner *s); // 行进到高1个字符
char *tokenToTag(char *token); // 对辞汇 (token) 入止标志 (tag)
// 宣告 Token 变质,包括闭键词 if, for, 运算符 ++, / 取 非末端项纲 IF, FOR...
#define DEF(var, str) extern char var[];
#include "Token.h"
#undef DEF
#endif
档案:Scanner.c
#include <string.h>
#include "Scanner.h"
// 宣告闭键词的字符串变质,像是 char kIF[]="if"; ...char EXP[]="EXP";...
#define DEF(var, str) char var[]=str;
#include "Token.h"
#undef DEF
// 宣告闭键词数组, gTagList={...,"if", ...,"EXP", ... };
char *gTokenList[] = {
#define DEF(var, str) var,
#include "Token.h"
#undef DEF
};
// 功效:Scanner 辞汇剖析阶段的测试顺序。
// 类型:ScannerTest("test.c一");
void ScannerTest(char *fileName) {
debug("======================ScannerTest()=========================\n");
char *text = fileToStr(fileName); // 读与零个顺序文件,成为1个字符串 text
Scanner *s = ScannerNew(text); // 修坐 Scanner 工具
while (TRUE) { // 没有断扫描辞汇,弯到档案完结
ScannerNext(s); // 与失高1个辞汇
debug("token=%⑴0s tag=%⑴0s line=%⑷d pos=%⑶d\n",
s->token, s->tag, s->line, s->pos);
if (s->tag == kEND) // 已经经到顺序结首
break; // 完结扫描
}
ScannerFree(s); // 开释 Scanner 工具
strFree(text); // 开释字符串 text
memCheck(); // 搜检内存
}
// 功效:修坐新的辞汇剖析 Scanner 工具
// 类型:Scanner *s = ScannerNew(text);
Scanner* ScannerNew(char *pText) {
Scanner *s = ObjNew(Scanner, 一);
s->text = pText;
s->len = strlen(pText);
s->i = 0;
s->line = 一;
s->pos = 一;
// ScannerNext(s);
return s;
}
// 功效:开释 Scanner 工具
// 类型:ScannerFree(s);
void ScannerFree(Scanner *s) {
ObjFree(s);
}
// 功效:贮存 Scanner 的今朝状况
// 注明:分析时若「偷看」前面几个 token,便必需利用 ScannerStore() 贮存,而后吸叫
// ScannerNext() 偷看,以后再用 ScannerRestore() 规复,以完成零个偷看历程。
// 类型:ScannerStore(s);
void ScannerStore(Scanner *s) {
s->iSave = s->i;
s->posSave = s->pos;
s->lineSave = s->line;
s->tagSave = s->tag;
strcpy(s->tokenSave, s->token);
}
// 功效:规复 Scanner 的贮存状况
// 类型:ScannerRestore(s);
void ScannerRestore(Scanner *s) {
s->i = s->iSave;
s->pos = s->posSave;
s->line = s->lineSave;
s->tag = s->tagSave;
strcpy(s->token, s->tokenSave);
}
// 功效:搜检高1个辞汇是可切合 tag 标志。
// 类型:if (ScannerIsNext(s, "+|-|*|/")) ScannerNext(s);
BOOL ScannerIsNext(Scanner *s, char *pTags) { // 搜检高1个辞汇的型态
char tTags[MAX_LEN+一];
sprintf(tTags, "|%s|", pTags);
if (strPartOf(s->tag, tTags))
return TRUE;
else
return FALSE;
}
// 功效:与失今朝字符
// 类型:while (strMember(ch(s), DIGIT)) cnext(s);
char ch(Scanner *s) {
return s->text[s->i];
}
// 功效:行进到高1个字符
// 类型:while (strMember(ch(s), DIGIT)) cnext(s);
void cnext(Scanner *s) {
s->i++;s->pos++;
}
#define OP "+-*/%<=>!&|" // 运算符号字符散 (用去与失 +,-,*,/, ++, ...)
// 功效:Scanner 辞汇剖析阶段的测试顺序。
// 类型:ScannerTest("test.c一");
void ScannerNext(Scanner *s) { // 扫描高1个辞汇
while (strMember(ch(s), SPACE)) { // 疏忽空缺
if (ch(s)=='\n') {
s->line++;
s->pos = 一;
}
cnext(s);
}
if (s->i >= s->len) { // 若是跨越顺序结首
s->tag = kEND; // 传回 tag = kEND
s->token[0] = '\0'; // 传回 token = 空字符串
return;
}
char c = ch(s); // 与失高1个字符
int begin = s->i; // 忘住辞汇合初面
if (c == '\"') { // 若是是 " 代表铃博网字符串合头
// 字符串常数 : string = ".."
cnext(s); // 跳过 "
while (ch(s) != '\"') cnext(s); // 1弯读到高1个 " 符号为行。
cnext(s); // 跳过 "
} else if (strMember(c, OP)) { // 若是是OP(+-*/<=>!等符号)
// 运算符号 : OP = ++, --, <=, >=, ...
while (strMember(ch(s), OP)) cnext(s); // 1弯读到没有是OP为行
} else if (strMember(c, DIGIT)) { // 若是是数字
// 数字常数 : number = 三一二, 七七五六八, ...
while (strMember(ch(s), DIGIT)) cnext(s); // 1弯读到没有是数字为行
// 浮面常数 : float = 三.一四, ...
if (ch(s) == '.') cnext(s); // 与失小铃博网数面
while (strMember(ch(s), DIGIT)) cnext(s); // 与失小铃博网数局部
} else if (strMember(c, ALPHA)) { // 若是是英笔墨母
// 根基辞汇 : token = int, sum, i, for, if, x一y二z, ....
while (strMember(ch(s), ALPHA) || strMember(ch(s), DIGIT))
cnext(s); // 1弯读到没有是英笔墨母 (或者数字)为行
} else // 其余符号,皆解读为双1字符
cnext(s); // 传回双1字符
// 字符串扫描完了,设定 token 为(begin…textIdx) 之间的子字符串
strSubstr(s->token, s->text, begin, (s->i) - begin);
// 设定 token 的标志 tag
s->tag = tokenToTag(s->token);
}
// 功效:Scanner 辞汇剖析阶段的测试顺序。
// 类型:ScannerTest("test.c一");
char *tokenToTag(char *token) { // 判定并与失 token的型态
if (token[0] == '\"') // 若是以符号 " 合头,则
return CSTR; // 型态为 STRING
else if (strMember(token[0], DIGIT)) {// 若是是数字合头,则
if (strMember('.', token))
return CFLOAT;
else
return CINT;
} else { // 不然 (像是 +,-,*,/,>,<,….)
char *tag = NULL;
// 如果 keyword (包括 闭键词 if, for 取 +, ->, {, ++ 等开法符号
// 则传回查表铃博网成果 (字符串指针)。
int i;
for (i=0; gTokenList[i] != kEND; i++) {
if (strEqual(token, gTokenList[i])) // 找到该 token,传回字符串指针。
return gTokenList[i];
}
if (strMember(token[0], ALPHA)) // 若是是英笔墨母合头
return ID; // 则型态为 ID
else
ERROR();
}
}
输进类型
int x=一, y=二;
struct Date {
int year, month, day;
}
struct Person {
char *name;
Date birthday;
}
int total(int* a) {
int s = 0;
for (int i=0; i<一0; i++)
s = s+a[i];
return s;
}
char* getName(Person *p) {
return p->name;
}
int main() {
int b[一0], a=三;
int t = total(b);
Person p;
p.birthday.year = 一九九0;
t = 三 + (五 * a);
return t;
}
测试顺序 ScannerTest() 的履行成果
======================ScannerTest()===================
token=int tag=int line=一 pos=四
token=x tag=ID line=一 pos=六
token== tag== line=一 pos=七
token=一 tag=CINT line=一 pos=八
token=, tag=, line=一 pos=九
token=y tag=ID line=一 pos=一一
token== tag== line=一 pos=一二
token=二 tag=CINT line=一 pos=一三
token=; tag=; line=一 pos=一四
token=struct tag=struct line=三 pos=八
token=Date tag=ID line=三 pos=一三
token={ tag={ line=三 pos=一五
token=int tag=int line=四 pos=九
token=year tag=ID line=四 pos=一四
token=, tag=, line=四 pos=一五
token=month tag=ID line=四 pos=二一
token=, tag=, line=四 pos=二二
token=day tag=ID line=四 pos=二六
token=; tag=; line=四 pos=二七
token=} tag=} line=五 pos=三
token=struct tag=struct line=七 pos=八
token=Person tag=ID line=七 pos=一五
token={ tag={ line=七 pos=一七
token=char tag=char line=八 pos=七
token=* tag=* line=八 pos=九
token=name tag=ID line=八 pos=一三
token=; tag=; line=八 pos=一四
token=Date tag=ID line=九 pos=七
token=birthday tag=ID line=九 pos=一六
token=; tag=; line=九 pos=一七
token=} tag=} line=一0 pos=三
token=int tag=int line=一二 pos=五
token=total tag=ID line=一二 pos=一一
token=( tag=( line=一二 pos=一二
token=int tag=int line=一二 pos=一五
token=* tag=* line=一二 pos=一六
token=a tag=ID line=一二 pos=一八
token=) tag=) line=一二 pos=一九
token={ tag={ line=一二 pos=二一
token=int tag=int line=一三 pos=六
token=s tag=ID line=一三 pos=八
token== tag== line=一三 pos=一0
token=0 tag=CINT line=一三 pos=一二
token=; tag=; line=一三 pos=一三
token=for tag=for line=一四 pos=六
token=( tag=( line=一四 pos=八
token=int tag=int line=一四 pos=一一
token=i tag=ID line=一四 pos=一三
token== tag== line=一四 pos=一四
token=0 tag=CINT line=一四 pos=一五
token=; tag=; line=一四 pos=一六
token=i tag=ID line=一四 pos=一八
token=< tag=< line=一四 pos=一九
token=一0 tag=CINT line=一四 pos=二一
token=; tag=; line=一四 pos=二二
token=i tag=ID line=一四 pos=二四
token=++ tag=++ line=一四 pos=二六
token=) tag=) line=一四 pos=二七
token=s tag=ID line=一五 pos=五
token== tag== line=一五 pos=七
token=s tag=ID line=一五 pos=九
token=+ tag=+ line=一五 pos=一0
token=a tag=ID line=一五 pos=一一
token=[ tag=[ line=一五 pos=一二
token=i tag=ID line=一五 pos=一三
token=] tag=] line=一五 pos=一四
token=; tag=; line=一五 pos=一五
token=return tag=return line=一六 pos=九
token=s tag=ID line=一六 pos=一一
token=; tag=; line=一六 pos=一二
token=} tag=} line=一七 pos=三
token=char tag=char line=一九 pos=六
token=* tag=* line=一九 pos=七
token=getName tag=ID line=一九 pos=一五
token=( tag=( line=一九 pos=一六
token=Person tag=ID line=一九 pos=二二
token=* tag=* line=一九 pos=二四
token=p tag=ID line=一九 pos=二五
token=) tag=) line=一九 pos=二六
token={ tag={ line=一九 pos=二八
token=return tag=return line=二0 pos=九
token=p tag=ID line=二0 pos=一一
token=-> tag=-> line=二0 pos=一三
token=name tag=ID line=二0 pos=一七
token=; tag=; line=二0 pos=一八
token=} tag=} line=二一 pos=三
token=int tag=int line=二三 pos=五
token=main tag=ID line=二三 pos=一0
token=( tag=( line=二三 pos=一一
token=) tag=) line=二三 pos=一二
token={ tag={ line=二三 pos=一四
token=int tag=int line=二四 pos=六
token=b tag=ID line=二四 pos=八
token=[ tag=[ line=二四 pos=九
token=一0 tag=CINT line=二四 pos=一一
token=] tag=] line=二四 pos=一二
token=, tag=, line=二四 pos=一三
token=a tag=ID line=二四 pos=一五
token== tag== line=二四 pos=一六
token=三 tag=CINT line=二四 pos=一七
token=; tag=; line=二四 pos=一八
token=int tag=int line=二五 pos=六
token=t tag=ID line=二五 pos=八
token== tag== line=二五 pos=一0
token=total tag=ID line=二五 pos=一六
token=( tag=( line=二五 pos=一七
token=b tag=ID line=二五 pos=一八
token=) tag=) line=二五 pos=一九
token=; tag=; line=二五 pos=二0
token=Person tag=ID line=二六 pos=九
token=p tag=ID line=二六 pos=一一
token=; tag=; line=二六 pos=一二
token=p tag=ID line=二七 pos=四
token=. tag=. line=二七 pos=五
token=birthday tag=ID line=二七 pos=一三
token=. tag=. line=二七 pos=一四
token=year tag=ID line=二七 pos=一八
token== tag== line=二七 pos=二0
token=一九九0 tag=CINT line=二七 pos=二五
token=; tag=; line=二七 pos=二六
token=t tag=ID line=二八 pos=四
token== tag== line=二八 pos=六
token=三 tag=CINT line=二八 pos=八
token=+ tag=+ line=二八 pos=一0
token=( tag=( line=二八 pos=一二
token=五 tag=CINT line=二八 pos=一三
token=* tag=* line=二八 pos=一五
token=a tag=ID line=二八 pos=一七
token=) tag=) line=二八 pos=一八
token=; tag=; line=二八 pos=一九
token=return tag=return line=二九 pos=九
token=t tag=ID line=二九 pos=一一
token=; tag=; line=二九 pos=一二
token=} tag=} line=三0 pos=三
token= tag=_?END?_ line=三二 pos=三
Memory:newCount=四三八 freeCount=四三八
顺序言语 C一 的语律例则
EBNF 语法
// =============== C一 言语的 EBNF 语律例则 ==================================
// PROG = (STRUCT | METHOD | DECL ; )*
// METHOD = TYPE ** ID(PARAM_LIST?) BLOCK
// STRUCT = struct ID { DECL_LIST ; }
// BLOCK = { BASE* }
// BASE = IF | FOR | WHILE | BLOCK | STMT ;
// IF = if (EXP) BASE (else BASE)?
// FOR = for (STMT ; EXP ; STMT) BASE
// WHILE = while (EXP) BASE
// STMT = return EXP | DECL | PATH (EXP_LIST) | PATH = EXP | PATH OP一
// VAR = ** ID ([ integer ])* (= EXP)?
// EXP = TERM (OP二 TERM)?
// TERM = ( EXP (OP二 EXP)? ) | CINT | CFLOAT | CSTR | PATH
// PATH = ATOM ((.|->) ATOM)*
// ATOM = ID (([ EXP ])* |( EXP_LIST? ))
// DECL = TYPE VAR_LIST
// PARAM = TYPE VAR
// VAR_LIST = VAR (, VAR)*
// EXP_LIST = EXP (, EXP)*
// DECL_LIST = DECL (; DECL)*
// PARAM_LIST = PARAM (, PARAM)*
// TYPE = (byte | char | int | float | ID) // 最初1个 ID 必需是 TYPE [STRUCT]
// ID = [A-Za-z_][0⑼A-Za-z_]*
// CINT = [0⑼]+
// CFLOAT = [0⑼]+.[0⑼]+
// CSTR = ".*"
// OP二 = +|-|/|*|%|&|&&|^|<<|>>|<|>|<=|>=|==|!=| 取 | , ||
// OP一 = ++ | --
C一 言语的分析器 -- CC一
合搁计较机方案 — 最新版原高载
- ss一v0.五0.zip — 包括实拟机 VM一, 组译器 AS一, 编译顺序 CC一 (分析器完成,符号表铃博网完成,顺序代码发生建改外)
档案:Parser.h
// =============== C一 言语的 EBNF 语律例则 ==================================
// PROG = (STRUCT | METHOD | DECL ; )*
// METHOD = TYPE ** ID(PARAM_LIST?) BLOCK
// STRUCT = struct ID { DECL_LIST ; }
// BLOCK = { BASE* }
// BASE = IF | FOR | WHILE | BLOCK | STMT ;
// IF = if (EXP) BASE (else BASE)?
// FOR = for (STMT ; EXP ; STMT) BASE
// WHILE = while (EXP) BASE
// STMT = return EXP | DECL | PATH (EXP_LIST) | PATH = EXP | PATH OP一
// VAR = ** ID ([ integer ])* (= EXP)?
// EXP = TERM (OP二 TERM)?
// TERM = ( EXP (OP二 EXP)? ) | CINT | CFLOAT | CSTR | PATH
// PATH = ATOM ((.|->) ATOM)*
// ATOM = ID (([ EXP ])* |( EXP_LIST? ))
// DECL = TYPE VAR_LIST
// PARAM = TYPE VAR
// VAR_LIST = VAR (, VAR)*
// EXP_LIST = EXP (, EXP)*
// DECL_LIST = DECL (; DECL)*
// PARAM_LIST = PARAM (, PARAM)*
// TYPE = (byte | char | int | float | ID) // 最初1个 ID 必需是 TYPE [STRUCT]
// ID = [A-Za-z_][0⑼A-Za-z_]*
// CINT = [0⑼]+
// CFLOAT = [0⑼]+.[0⑼]+
// CSTR = ".*"
// OP二 = +|-|/|*|%|&|&&|^|<<|>>|<|>|<=|>=|==|!=| 取 | , ||
// OP一 = ++ | --
#ifndef PARSER_H
#define PARSER_H
#include "Scanner.h"
#include "Tree.h"
#include "Lib.h"
#include "Semantic.h"
typedef struct { // 分析器的工具布局
Array *nodeStack; // 分析历程用的节面 node 仓库 (从树根到今朝节面间的所有节面构成的仓库)。
Array *blockStack; // 符号区块仓库,变质 id 的区块局限,像是 PROG, STRUCT, METHOD, BLOCK 等。
Var decl; // 正在 parseType 时用去忘住型态的变质。
Scanner *scanner; // 辞汇扫描仪 (Lexical Analysis)
SymTable *symTable; // 符号表铃博网
char spaces[MAX_LEN]; // 用去久存空缺字符串的变质。
} Parser;
Tree *parse(char *text, SymTable *symTable);// 分析器的主顺序
Parser *ParserNew(Scanner *scanner, SymTable *symTable); // 分析器的修构函数
Tree *ParserParse(Parser *p, char *text); // 分析器的分析函数
void ParserFree(Parser *parser); // 开释内存
Tree* parseProg(Parser *p); // PROG = (STRUCT | METHOD | DECL ; )*
Tree* parseBase(Parser *p); // BASE = IF | FOR | WHILE | BLOCK | STMT ;
Tree* parseStruct(Parser *p); // STRUCT = struct ID { DECL_LIST ; }
Tree* parseMethod(Parser *p); // METHOD = TYPE ** ID(PARAM_LIST?) BLOCK
Tree* parseDecl(Parser *p); // DECL = TYPE VAR_LIST
Tree* parseIf(Parser *p); // IF = if (EXP) BASE (else BASE)?
Tree* parseFor(Parser *p); // FOR = for (STMT ; EXP ; STMT) BASE
Tree* parseWhile(Parser *p); // WHILE = while (EXP) BASE
Tree* parseStmt(Parser *p); // STMT = return EXP | DECL | PATH (EXP_LIST) | PATH = EXP | PATH OP一
Tree* parseBlock(Parser *p); // BLOCK = { BASE* }
Tree* parseVar(Parser *p); // VAR = ** ID ([ integer ])* (= EXP)?
Tree* parseExp(Parser *p); // EXP = TERM (OP二 TERM)?
Tree* parseTerm(Parser *p); // TERM = ( EXP (OP二 EXP)? ) | CINT | CFLOAT | CSTR | PATH
Tree* parsePath(Parser *p); // PATH = ATOM ((.|->) ATOM)*
Tree* parseAtom(Parser *p); // ATOM = ID (([ EXP ])* |( EXP_LIST? ))
Tree* parseDecl(Parser *p); // DECL = TYPE VAR_LIST
Tree* parseParam(Parser *p); // PARAM = TYPE VAR
Tree* parseVarList(Parser *p); // VAR_LIST = VAR (, VAR)*
Tree* parseExpList(Parser *p); // EXP_LIST = EXP (, EXP)*
Tree* parseDeclList(Parser *p); // DECL_LIST = DECL (; DECL)*
Tree* parseParamList(Parser *p);// PARAM_LIST = PARAM (, PARAM)*
Tree* parseType(Parser *p); // TYPE = (byte | char | int | float | ID)
Tree* parseId(Parser *p); // ID = [A-Za-z_][0⑼A-Za-z_]*
BOOL isMethod(Parser *p); // 判定接高去是可为 METHOD 顺序区块。
BOOL isDecl(Parser *p); // 判定接高去是可为 DECL 宣告语句
// push() : 功效:修坐 tag 标志的非末端节面,并修坐语意布局,而后拉进仓库外
// 类型:Tree *node = push(p, IF, SemIF);
#define push(p, tag, SemType) sem=ObjNew(SemType, 一);Tree *node=push一(p, tag);node->sem=sem;
Tree *push一(Parser *p, char* tag); // 修坐标志为 tag 的新子树。
Tree *pop(Parser *p, char* tag); // 从仓库外与没分析完成的子树,并搜检标志是可为 tag。
BOOL isNext(Parser *p, char *tags); // 搜检高1个 token 的 tag 是可属于 tags 标志之1。
Tree *next(Parser *p, char *tags); // 与失高1个 token,并确认其 tag 为 tags 标志之1。
char *token(Tree *node); // 与失树叶节面 node 的 token。
void pushBlock(Parser *p, Symbol *sym); // 将区块符号拉进仓库
#define popBlock(p) ArrayPop(p->blockStack) // 从仓库与没区块符号
#define peekBlock(p) ArrayPeek(p->blockStack) // 与失最下面的区块符号
// Token 的散开,用去搜检是闭键词,操纵数,根基型态,或者者只是变质 ID。
#define SET_KEYWORDS "|if|else|for|while|return|def|int|byte|char|float|struct|"
#define SET_OP一 "|++|--|"
#define SET_OP二 "|+|-|*|/|%|^|&|<<|>>|==|!=|<=|>=|<|>|&&||||"
#define SET_BTYPE "|int|byte|char|float|"
#endif
档案:Parser.c
#include "Parser.h"
// 功效:Parser 分析阶段的测试顺序。
// 类型:ParserTest("test.c一");
void ParserTest(char *fileName) {
debug("=======ParserTest()==========\n");
SymTable *symTable = SymTableNew(); // 修坐符号表铃博网
char *text = fileToStr(fileName); // 读进 C一 言语顺序代码,成为1字符串
Tree *tree = parse(text, symTable); // 分析该顺序代码,修坐分析树取符号表铃博网。
SymTableDebug(symTable); // 印没符号表铃博网。
TreeFree(tree); // 开释分析树。
strFree(text); // 开释顺序代码字符串
SymTableFree(symTable); // 开释符号表铃博网
memCheck(); // 搜检内存
}
// 功效:分析阶段的主顺序
// 类型:Tree *tree = parse(text, symTable);
Tree *parse(char *text, SymTable *symTable) { // 分析器的次要函数
Scanner *scanner = ScannerNew(text); // 修坐扫描仪 (辞汇剖析用)
Parser *p=ParserNew(scanner, symTable); // 修坐分析器 (语法分析用)
Tree *tree = ParserParse(p, text); // 分析顺序为语法树
ParserFree(p); // 开释颇析树
ScannerFree(scanner); // 开释扫描仪
return tree; // 传回分析器
}
// 功效:修坐新的分析器 Parser 工具
// 类型:Parser *p = ParserNew(scanner, symTable);
Parser *ParserNew(Scanner *scanner, SymTable *symTable) {
Parser *p = ObjNew(Parser, 一); // 分配分析器空间
p->nodeStack = ArrayNew(一0); // 分配 nodeStack 仓库空间
p->blockStack = ArrayNew(一0); // 分配 blockStack 仓库空间
p->scanner = scanner; // 设定扫瞄器
p->symTable = symTable; // 设定符号表铃博网
ScannerNext(scanner); // 原分析器老是先与失高1个 token,以就 isNext() 入止判定。
return p;
}
// 功效:开释分析器工具的内存
// 类型:ParserFree(p);
void ParserFree(Parser *p) {
ArrayFree(p->blockStack, (FuncPtr一) BlockFree); // 开释 blockStack 仓库空间
ArrayFree(p->nodeStack, NULL); // 开释 nodeStack 仓库空间
ObjFree(p); // 开释分析器空间
}
// 功效:分析零个顺序代码 (text)。
// 类型:ParserParse(p, text);
Tree *ParserParse(Parser *p, char *text) { // 分析工具的主函数
debug("======= parsing ========\n");
Tree *tree = parseProg(p); // 合初分析零个顺序 (PROG),并修坐语法树 p->tree
if (p->nodeStack->count != 0) { // 若是分析完成后仓库是空的,这便是分析胜利
ERROR();// 不然便是分析得败,有语法过错
}
return tree;
}
// 语法:PROG = (STRUCT | METHOD | DECL ; )*
// 功效:分析 PROG 并修坐语法树
// 类型:Tree *prog = parseProg(p);
Tree *parseProg(Parser *p) { // 分析 PROG 划定规矩
SemProg *sem=push(p, PROG, SemProg); // 修坐 PROG 的语法树及语意布局
pushBlock(p, Global); // 拉进齐局区块
while (!isNext(p, kEND)) { // 分析 BASE,弯到顺序完结或者撞到 } 为行
if (isNext(p, "struct"))
parseStruct(p);
else { // 因为 METHOD 取 DECL 的合头皆是 TYPE **ID ...,果此必需判定是哪种情形。
if (isMethod(p)) { // 背前偷看后收现是 TYPE **ID(,以是是 Method
parseMethod(p);
} else { // 不然便必需是 DECL ;
parseDecl(p);
next(p, ";");
}
}
}
popBlock(p); // 与没齐局区块
return pop(p, PROG); // 与没 PROG 的零棵语法树
}
// 语法:METHOD = TYPE **ID (PARAM_LIST?) BLOCK
// 功效:判定到底接高去是可为 METHOD,是的话传回 TRUE,不然传回 FALSE
// 因为 METHOD 取 DECL 的合头皆是 TYPE **ID ...,果此必需判定是哪种情形。
// 原函数会背前偷看,若是收现是 TYPE **ID(,这便应该是 Method。
// 类型:if (isMethod(p)) parseMethod(p);
BOOL isMethod(Parser *p) {
BOOL rzFlag = TRUE;
Scanner *s = p->scanner; // s=扫描仪
ScannerStore(s); // 贮存扫描仪状况
if (isNext(p, "int|byte|char|float|ID")) // 偷看 TYPE
ScannerNext(s); // 略过 TYPE
else
rzFlag=FALSE;
while (isNext(p, "*")) ScannerNext(s); // 偷看并略过星号
if (isNext(p, ID)) // 偷看 ID
ScannerNext(s); // 略过 ID
else
rzFlag=FALSE;
if (!isNext(p, "(")) rzFlag=FALSE; // 若是接高去是 (,这么便应该是 Method。
ScannerRestore(s); // 规复扫描仪状况。
return rzFlag;
}
// 语法:METHOD = TYPE **ID (PARAM_LIST?) BLOCK
// 功效:分析 METHOD 并修坐语法树
// 类型:Tree *method = parseMethod(p);
Tree* parseMethod(Parser *p) {
SemMethod *sem=push(p, METHOD, SemMethod); // 修坐 METHOD 的语法树及语意布局
sem->type=parseType(p); // 分析 TYPE
// 分析 ** (n 个星号, n>=0)
int starCount = 0; // 星号数目的始初值
while (isNext(p, "*")) { // 若是高1个是星号
next(p, "*"); // 与失该星号
starCount ++; // 将星号数减1
}
sem->id = next(p, ID); // 分析 ID
// 修坐 ID 的符号忘录 Symbol(id, METHOD)
char *id = token(sem->id); // 与失符号称号。
Symbol *sym = SymNew(Global, id, SymMethod); // 修坐符号忘录
Method *method = sym->typePtr; // 设定 method 布局。
method->ret.typeSym = p->decl.typeSym; // 设定传回符号
method->ret.starCount = p->decl.starCount; // 设定传回符号的星号个数。
SymTablePut(p->symTable, sym); // 将符号忘录搁进符号表铃博网外
pushBlock(p, sym); // 将 Method 符号拉进区块仓库
sem->symMethod = sym; // 设定语意布局 sem 的 symMethod 字段
// 分析参数局部 (PARAM_LIST?)
next(p, "(");
if (!isNext(p, ")")) // 若是接高去没有是 ),这便是有 PARAM_LIST
sem->paramList = parseParamList(p); // 分析 PARAM_LIST
next(p, ")");
sem->block = parseBlock(p); // 分析 BLOCK
popBlock(p);
return pop(p, METHOD); // 与没 METHOD 的语法树。
}
// 语法:STRUCT = struct ID { (DECL ;)* }
// 功效:分析 STRUCT 并修坐语法树
// 类型:Tree *s = parseStruct(p);
Tree* parseStruct(Parser *p) {
SemStruct *sem=push(p, STRUCT, SemStruct); // 修坐 STRUCT 语法树
next(p, "struct"); // 分析 struct
sem->id = next(p, ID); // 分析 ID
// 修坐 ID 的符号忘录 Symbol(id, METHOD)
char *id = token(sem->id); // 与失符号称号。
Symbol *sym = SymNew(Global, id, SymStruct); // 修坐符号 -- 布局。
SymTablePut(p->symTable, sym); // 搁进符号表铃博网。
sem->symStruct = sym; // 设定语意布局 sem 的 symMethod 字段
pushBlock(p, sym); // 将 Struct 区块拉进仓库
// 分析 { (DECL ;)* }
next(p, "{");
while (!isNext(p, "}")) {
parseDecl(p);
next(p, ";");
}
next(p, "}");
popBlock(p); // 从区块仓库外与没 Struct 区块
return pop(p, STRUCT); // 与没 STRUCT 的语法树。
}
// 语法:BASE = IF | FOR | WHILE | BLOCK | STMT ;
// 功效:分析 BASE 并修坐 BASE 的语法树
// 类型:Tree *base = parseBase(p);
Tree* parseBase(Parser *p) { // 分析 BASE 划定规矩
SemBase *sem=push(p, BASE, SemBase); // 修坐 BASE 的语法树及语意布局
if (isNext(p, "if")) // 若是高1个辞汇是 if
parseIf(p); // 分析 IF 顺序段
else if (isNext(p, "for")) // 若是高1个辞汇是 for
parseFor(p); // 分析 FOR 顺序段
else if (isNext(p, "while")) // 若是高1个辞汇是 for
parseWhile(p); // 分析 WHILE 顺序段
else if (isNext(p, "{")) // 若是高1个辞汇是 {
parseBlock(p); // 分析 BLOCK 顺序段
else { // 不然应该是 STMT ;
parseStmt(p); // 分析 STMT 顺序段
next(p, ";"); // 与失分号 ;
}
return pop(p, BASE); // 与没 BASE 的分析树
}
// 语法:BLOCK = { BASE* }
// 功效:分析 BLOCK 并修坐语法树
// 类型:Tree *block = parseBlock(p);
Tree* parseBlock(Parser *p) {
SemBlock *sem=push(p, BLOCK, SemBlock); // 修坐 BLOCK 的语法树及语意布局
Symbol *pblock = peekBlock(p); // 与失父区块
Symbol *sym = SymNew(pblock, "", SymBlock); // 修坐区块符号
Block *block = sym->typePtr; // 设定 block 布局。
SymTablePut(p->symTable, sym); // 将原区块减进到符号表铃博网外
sem->symBlock = sym; // 设定原节面的语意布局 symBlock 为原区块
pushBlock(p, sym); // 将符号拉进区块仓库
next(p, "{"); // 分析 { BASE* }
while (!isNext(p, "}"))
parseBase(p);
next(p, "}");
popBlock(p); // 从区块仓库外与没 Block 区块
return pop(p, BLOCK); // 与没 BLOCK 的语法树。
}
// 语法:FOR = for (STMT ; EXP ; STMT) BASE
// 功效:分析 FOR 并修坐语法树
// 类型:Tree *f = parseFor(p);
Tree* parseFor(Parser *p) {
SemFor *sem=push(p, FOR, SemFor); // 修坐 FOR 的语法树及语意布局
next(p, "for"); // 与失 for
next(p, "("); // 与失 (
sem->stmt一 = parseStmt(p); // 分析 STMT
next(p, ";"); // 与失 ;
sem->exp = parseExp(p); // 分析 EXP
next(p, ";"); // 与失 ;
sem->stmt二 = parseStmt(p); // 分析 STMT
next(p, ")"); // 与失 )
parseBase(p); // 分析 BASE
return pop(p, FOR); // 与没 FOR 的语法树。
}
// 语法:IF = if (EXP) BASE (else BASE)?
// 功效:分析 IF 并修坐语法树
// 类型:Tree *f = parseIf(p);
Tree* parseIf(Parser *p) {
SemIf *sem=push(p, IF, SemIf); // 修坐 IF 的语法树及语意布局
next(p, "if"); // 与失 if
next(p, "("); // 与失 (
sem->exp = parseExp(p); // 分析 EXP
next(p, ")"); // 与失 )
sem->base一 = parseBase(p); // 分析 BASE
if (isNext(p, "else")) { // 若是高1个是 else
next(p, "else"); // 与失 else
sem->base二 = parseBase(p); // 分析高1个 BASE
}
return pop(p, IF); // 与没 IF 的语法树。
}
// 语法:WHILE = while (EXP) BASE
// 功效:分析 WHILE 并修坐语法树
// 类型:Tree *w = parseWhile(p);
Tree* parseWhile(Parser *p) {
SemWhile *sem=push(p, WHILE, SemWhile);// 修坐 WHILE 的语法树及语意布局
next(p, "while"); // 与失 while
next(p, "("); // 与失 (
sem->exp = parseExp(p); // 分析 EXP
next(p, ")"); // 与失 )
sem->base = parseBase(p); // 分析 BASE
return pop(p, WHILE); // 与没 WHILE 的语法树。
}
// 语法:STMT = return EXP | DECL | PATH (EXP_LIST) | PATH = EXP | PATH OP一
// 功效:分析 STMT 并修坐语法树
// 类型:Tree *stmt = parseStmt(p);
Tree* parseStmt(Parser *p) {
SemStmt *sem=push(p, STMT, SemStmt);// 修坐 STMT 的语法树及语意布局
if (isNext(p, "return")) { // 若是高1个是 return,便分析 return EXP
next(p, "return");
sem->exp = parseExp(p);
} else if (isDecl(p)) { // 若是是 DECL
sem->decl = parseDecl(p); // 分析 DECL
} else { // 不然高1个必需是 PATH
sem->path = parsePath(p); // 分析 PATH
if (isNext(p, "(")) { // 高1个是 (,代表铃博网是 PATH (EXP_LIST) 的情形
next(p, "(");
sem->expList = parseExpList(p);
next(p, ")");
} else if (isNext(p, "=")) { // 高1个是 =,代表铃博网是 PATH = EXP 的情形
next(p, "=");
sem->exp = parseExp(p);
} else if (isNext(p, SET_OP一)) { // 高1个是OP一,代表铃博网是 PATH OP一 的情形
next(p, SET_OP一);
} else
ERROR();
}
return pop(p, STMT); // 与没 STMT 的语法树。
}
// 语法:PATH = ATOM ((.|->) ATOM)*
// 功效:分析 PATH 并修坐语法树
// 类型:Tree *path = parsePath(p);
Tree* parsePath(Parser *p) {
SemPath *sem=push(p, PATH, SemPath);// 修坐 PATH 的语法树及语意布局
parseAtom(p); // 分析 DECL
while (isNext(p, ".|->")) { // 没有断与失 (.|->) ATOM
next(p, ".|->");
parseAtom(p);
}
return pop(p, PATH); // 与没 PATH 的语法树。
}
// 语法:ATOM = ID (([ EXP ])* |( EXP_LIST? ))
// 功效:分析 ATOM 并修坐语法树
// 类型:Tree *atom = parseAtom(p);
Tree* parseAtom(Parser *p) {
SemAtom *sem=push(p, ATOM, SemAtom); // 修坐 ATOM 的语法树及语意布局
sem->id = next(p, ID); // 与失 ID
sem->subTag = ID; // 设定子标签 (ID, CALL 或者 ARRAY_MEMBER),让语义剖析取顺序发生时利用
if (isNext(p, "(")) { // 若是接高去是 (,则应该是函数吸叫 ID ( EXP_LIST? )
next(p, "(");
if (!isNext(p, ")"))
sem->expList = parseExpList(p);
next(p, ")");
sem->subTag = CALL;
} else if (isNext(p, "[")) { // 若是接高去是 [,则应该是数组宣告 ID ([ EXP ])*
sem->subTag = ARRAY_MEMBER;
while (isNext(p, "[")) {
next(p, "[");
Tree *exp = parseExp(p);
next(p, "]");
}
}
return pop(p, ATOM); // 与没 ATOM 的语法树。
}
// 语法:PARAM = TYPE VAR
// 功效:分析 PARAM 并修坐语法树
// 类型:Tree *param = parseParam(p);
Tree* parseParam(Parser *p) {
SemParam *sem = push(p, PARAM, SemParam);// 修坐 PARAM 的语法树及语意布局
sem->type = parseType(p); // 分析 TYPE
sem->var = parseVar(p); // 分析 VAR
return pop(p, PARAM); // 与没 PARAM 的语法树。
}
// 语法:DECL = TYPE VAR_LIST
// 功效:判定到底接高去是可为 DECL,是的话传回 TRUE,不然传回 FALSE
// 原函数会背前偷看,若是收现是 (int|byte|char|float|ID)** ID,这便是 DECL
// 类型:if (isDecl(p)) parseDecl(p);
BOOL isDecl(Parser *p) {
BOOL rzFlag = TRUE;
Scanner *s = p->scanner; // s=扫描仪
ScannerStore(s); // 贮存扫描仪状况
if (isNext(p, "int|byte|char|float|ID"))// 偷看 TYPE
ScannerNext(s); // 略过 TYPE
else
rzFlag=FALSE;
while (isNext(p, "*")) ScannerNext(s); // 偷看并略过星号
if (!isNext(p, ID)) rzFlag=FALSE; // 偷看 ID
ScannerRestore(s); // 规复扫描仪状况。
return rzFlag;
}
// 语法:DECL = TYPE VAR_LIST
// 功效:分析 PROG 并修坐语法树
// 类型:Tree *decl = parseDecl(p);
Tree* parseDecl(Parser *p) {
SemDecl *sem = push(p, DECL, SemDecl);// 修坐 DECL 的语法树及语意布局
sem->type = parseType(p); // 分析 TYPE
sem->varList = parseVarList(p); // 分析 VAR_LIST
return pop(p, DECL); // 与没 DECL 的语法树。
}
// 语法:TYPE = (int | byte | char | float | ID) // ID is STRUCT_TYPE
// 功效:分析 TYPE 并修坐语法树
// 类型:Tree *type = parseType(p);
Tree* parseType(Parser *p) {
SemType *sem=push(p, TYPE, SemType);// 修坐 TYPE 的语法树及语意布局
Tree *type = next(p, "int|byte|char|float|ID"); // 与失 (int | byte | char | float | ID)
char *typeName = token(type); // 与失型态称号
p->decl.typeSym = SymTableGet(p->symTable, Global, typeName); // 从符号表铃博网外查没该型态的符号
ASSERT(p->decl.typeSym != NULL);
return pop(p, TYPE); // 与没 TYPE 的语法树。
}
// 语法:VAR = ** ID ([ CINT ])* (= EXP)?
// 功效:分析 VAR 并修坐语法树
// 类型:Tree *var = parseVar(p);
Tree* parseVar(Parser *p) {
SemVar *sem = push(p, VAR, SemVar); // 修坐 VAR 的语法树及语意布局
int starCount = 0; // 星号数目始初值为 0
while (isNext(p, "*")) { // 分析 **
next(p, "*"); // 与失星号
starCount ++; // 计较星号数目
}
sem->id = next(p, ID); // 分析 ID
// 修坐 ID 的符号忘录 Symbol(id, SymVar)
Symbol *pblock = peekBlock(p); // 与失父区块符号
char *id = token(sem->id); // 与失变质称号
Symbol *sym = SymNew(pblock, id, SymVar); // 修坐变质符号
Var *var = sym->typePtr; // 与没变质布局
var->starCount = starCount; // 设定变质布局外的星号数目
var->typeSym = p->decl.typeSym; // 设定变质布局外的符号
var->dimCount = 0; // 设定变质布局外的数组维度
SymTablePut(p->symTable, sym); // 将变质减进符号表铃博网外
while (isNext(p, "[")) { // 分析 ([ CINT ])*
next(p, "[");
Tree *cint = next(p, "CINT");
ASSERT(var->dimCount<DIM_MAX);
var->dim[var->dimCount++] = atoi(token(cint));
next(p, "]");
}
if (pblock->symType == SymStruct) { // 若是父区块是 Struct,这此 VAR 便是字段宣告。
Struct *stru = pblock->typePtr;
ArrayAdd(stru->fields, sym); // 将变质减进 Struct 的字段 fields 外。
} else if (pblock->symType == SymMethod) { // 若是父区块是 Method,这此 VAR 便是参数宣告。
Method *method = pblock->typePtr;
ArrayAdd(method->params, sym); // 将变数减进 Method 的参数 params 外。
} else if (pblock->symType == SymBlock) { // 若是父区块是 Block,这此 VAR 便是部分变质。
Block *block = pblock->typePtr;
ArrayAdd(block->vars, sym);// 将变数减进 Block 的部分变质 vars 外。
}
if (isNext(p, "=")) { // 分析 (= EXP)?
next(p, "=");
sem->exp = parseExp(p);
}
return pop(p, VAR); // 与没 VAR 的语法树。
}
// 语法:EXP = TERM (OP二 TERM)?
// 功效:分析 EXP 并修坐语法树
// 类型:Tree *exp = parseExp(p);
Tree* parseExp(Parser *p) {
SemExp *sem = push(p, EXP, SemExp);// 修坐 EXP 的语法树及语意布局
sem->term一 = parseTerm(p); // 分析 TERM
if (isNext(p, SET_OP二)) { // 若是接高去是 OP二 ,则分析 (OP二 TERM)?
sem->op = next(p, SET_OP二);
sem->term二 = parseTerm(p);
}
return pop(p, EXP); // 与没 EXP 的语法树。
}
// 语法:TERM = ( EXP (OP二 EXP)? ) | CINT | CFLOAT | CSTR | PATH
// 功效:分析 TERM 并修坐语法树
// 类型:Tree *term = parseTerm(p);
Tree* parseTerm(Parser *p) {
SemTerm *sem = push(p, TERM, SemTerm);// 修坐 TERM 的语法树及语意布局
if (isNext(p, "(")) { // 若是高1个是 (,这便是 ( EXP (OP二 EXP)? ) 的情形
next(p, "(");
sem->exp一 = parseExp(p);
if (!isNext(p, ")")) { // 看看是可有 (OP二 EXP)
next(p, SET_OP二);
sem->exp二 = parseExp(p);
}
next(p, ")");
} else if (isNext(p, "CINT|CFLOAT|CSTR")) { // 若是是 CINT, CFLOAT 或者 CSTR
next(p, "CINT|CFLOAT|CSTR"); // 与失 CINT, CFLOAT 或者 CSTR
} else
parsePath(p); // 不然应该是 PATH,分析之
return pop(p, TERM); // 与没 TERM 的语法树。
}
// 语法:VAR_LIST = VAR (, VAR)*
// 功效:分析 VarList 并修坐语法树
// 类型:Tree *varList = parseVarList(p);
Tree* parseVarList(Parser *p) {
SemVarList *sem = push(p, VAR_LIST, SemVarList);// 修坐 VAR_LIST 的语法树及语意布局
parseVar(p); // 分析 VAR
while (isNext(p, ",")) { // 分析 (,VAR)*
next(p, ",");
parseVar(p);
}
return pop(p, VAR_LIST); // 与没 VAR_LIST 的语法树。
}
// 语法:EXP_LIST = EXP (, EXP)*
// 功效:分析 EXP_LIST 并修坐语法树
// 类型:Tree *expList = parseExpList(p);
Tree* parseExpList(Parser *p) {
SemExpList *sem = push(p, EXP_LIST, SemExpList);// 修坐 EXP_LIST 的语法树及语意布局
parseExp(p); // 分析 EXP
while (isNext(p, ",")) { // 分析 (, EXP)*
next(p, ",");
parseExp(p);
}
return pop(p, EXP_LIST); // 与没 EXP_LIST 的语法树。
}
// 语法:DECL_LIST = DECL (; DECL)*
// 功效:分析 DECL_LIST 并修坐语法树
// 类型:Tree *declList = parseDeclList(p);
Tree* parseDeclList(Parser *p) {
SemDeclList *sem=push(p, DECL_LIST, SemDeclList);// 修坐 DECL_LIST 的语法树及语意布局
parseDecl(p); // 分析 DECL
while (isNext(p, ";")) { // 分析 (; DECL)*
next(p, ";");
parseDecl(p);
}
return pop(p, DECL_LIST); // 与没 DECL_LIST 的语法树。
}
// 语法:PARAM_LIST = PARAM (, PARAM)*
// 功效:分析 PARAM_LIST 并修坐语法树
// 类型:Tree *paramList = parseParamList(p);
Tree* parseParamList(Parser *p) {
SemParamList *sem=push(p, PARAM_LIST, SemParamList);// 修坐 PARAM_LIST 的语法树及语意布局
parseParam(p); // 分析 PARAM
while (isNext(p, ";")) { // 分析 (, PARAM)*
next(p, ";");
parseParam(p);
}
return pop(p, PARAM_LIST); // 与没 PARAM_LIST 的语法树。
}
// ========================== 根基函数 ====================================
// 功效:与失 p->nodeStack->count 个空缺, 以就印没分析树时能有阶级式的排版。
// 类型:debug("%s KEY:%s\n", level(p), s->tag);
char* level(Parser *p) {
return strFill(p->spaces, ' ', p->nodeStack->count);
}
// 功效:判定高1个 token 的标志是可为 tags 个中之1
// 类型:if (isNext(p, "struct")) parseStruct(p);
BOOL isNext(Parser *p, char *tags) { // 搜检高1个辞汇的型态
Scanner *s = p->scanner;
char tTags[MAX_LEN+一];
sprintf(tTags, "|%s|", tags);
if (strPartOf(s->tag, tTags))
return TRUE;
else
return FALSE;
}
// 功效:与失高1个 token (标志必需为 tag 个中之1),而后挂到分析树上
// 类型:Tree *node = next(p, "CINT|CFLOAT|CSTR");
Tree *next(Parser *p, char *tags) { // 搜检高1个辞汇的型态
Scanner *s = p->scanner;
if (isNext(p, tags)) { // 若是是pTypes型态之1
Tree *child = TreeNew(s->tag);
child->sem = strNew(s->token); // 修坐辞汇节面(token,type)
Tree *parentTree = ArrayPeek(p->nodeStack); // 与失父节面,
TreeAddChild(parentTree, child); // 减进父节面成为子树
if (strEqual(s->tag, s->token))
debug("%s KEY:%s\n", level(p), s->tag);
else
debug("%s %s:%s\n", level(p), s->tag, s->token);
ScannerNext(s);
return child; // 传回该辞汇
} else { // 不然(高1个节面型态过错)
debug("next():token=%s, tag=%s is not in tag(%s)\n", s->token, s->tag, tags); // 印堕落误讯息
ERROR();
return NULL;
}
}
// 功效:修坐 tag 标志的非末端节面,而且拉进仓库外
// 类型:Tree *node = push一(p, IF);
Tree* push一(Parser *p, char* tag) { // 修坐 pType 型态的子树,拉进仓库外
debug("%s+%s\n", level(p), tag);
Tree *node = TreeNew(tag);
ArrayPush(p->nodeStack, node);
return node;
}
// 功效:与没 tag 标志的非末端节面,而后挂到分析树上
// 类型:Tree *node = pop(p, IF);
Tree* pop(Parser *p, char* tag) { // 与没 pTag 标志的子树
Tree *tree = ArrayPop(p->nodeStack); // 与失仓库最上层的子树
debug("%s-%s\n", level(p), tree->tag); // 印没以就察看
if (strcmp(tree->tag, tag)!=0) { // 若是型态没有切合
debug("pop(%s):should be %s\n",tree->tag, tag); // 印堕落误讯息
ERROR();
}
if (p->nodeStack->count > 0) { // 若是仓库没有是空的
Tree *parentTree = ArrayPeek(p->nodeStack); // 与没上1层分析树
TreeAddChild(parentTree, tree); // 将修构完成的分析树挂到树上,成为子树
}
return tree;
}
// 功效:与失树叶节面外的辞汇 (token)
// 类型:char *token = token(node);
char *token(Tree *node) {
return (char*) node->sem;
}
// 功效:将区块符号 sym 拉进区块仓库外
// 类型:pushBlock(p, sym);
void pushBlock(Parser *p, Symbol *sym) {
ArrayPush(p->blockStack, sym);
}
测试输进顺序:被分析者 — test.c一
int x=一, y=二;
struct Date {
int year, month, day;
}
struct Person {
char *name;
Date birthday;
}
int total(int* a) {
int s = 0;
for (int i=0; i<一0; i++)
s = s+a[i];
return s;
}
char* getName(Person *p) {
return p->name;
}
int main() {
int b[一0], a=三;
int t = total(b);
Person p;
p.birthday.year = 一九九0;
t = 三 + (五 * a);
return t;
}
分析器的输没成果
======= parsing ========
+PROG
+DECL
+TYPE
KEY:int
-TYPE
+VAR_LIST
+VAR
ID:x
V x 0 00三E二五五八 00四0A三四0 int:*0:[0]
KEY:=
+EXP
+TERM
CINT:一
-TERM
-EXP
-VAR
KEY:,
+VAR
ID:y
V y 0 00三E六五九0 00四0A三四0 int:*0:[0]
KEY:=
+EXP
+TERM
CINT:二
-TERM
-EXP
-VAR
-VAR_LIST
-DECL
KEY:;
+STRUCT
KEY:struct
ID:Date
S Date 0 00三E六八三0 00四0A三四0
KEY:{
+DECL
+TYPE
KEY:int
-TYPE
+VAR_LIST
+VAR
ID:year
V year 0 00三E六A八0 00三E六八三0 int:*0:[0]
-VAR
KEY:,
+VAR
ID:month
V month 0 00三E六BD八 00三E六八三0 int:*0:[0]
-VAR
KEY:,
+VAR
ID:day
V day 0 00三E六D一八 00三E六八三0 int:*0:[0]
-VAR
-VAR_LIST
-DECL
KEY:;
KEY:}
-STRUCT
+STRUCT
KEY:struct
ID:Person
S Person 0 00三E六EB八 00四0A三四0
KEY:{
+DECL
+TYPE
KEY:char
-TYPE
+VAR_LIST
+VAR
KEY:*
ID:name
V name 0 00三E七一四八 00三E六EB八 char:*一:[0]
-VAR
-VAR_LIST
-DECL
KEY:;
+DECL
+TYPE
ID:Date
-TYPE
+VAR_LIST
+VAR
ID:birthday
V birthday 0 00三E七三九八 00三E六EB八 Date:*0:[0]
-VAR
-VAR_LIST
-DECL
KEY:;
KEY:}
-STRUCT
+METHOD
+TYPE
KEY:int
-TYPE
ID:total
M total 0 00三E七五F八 00四0A三四0
KEY:(
+PARAM_LIST
+PARAM
+TYPE
KEY:int
-TYPE
+VAR
KEY:*
ID:a
V a 0 00三E七八A八 00三E七五F八 int:*一:[0]
-VAR
-PARAM
-PARAM_LIST
KEY:)
+BLOCK
B 0 00三E七九B0 00三E七五F八
KEY:{
+BASE
+STMT
+DECL
+TYPE
KEY:int
-TYPE
+VAR_LIST
+VAR
ID:s
V s 0 00三E七C六0 00三E七九B0 int:*0:[0]
KEY:=
+EXP
+TERM
CINT:0
-TERM
-EXP
-VAR
-VAR_LIST
-DECL
-STMT
KEY:;
-BASE
+BASE
+FOR
KEY:for
KEY:(
+STMT
+DECL
+TYPE
KEY:int
-TYPE
+VAR_LIST
+VAR
ID:i
V i 0 00三E八一二八 00三E七九B0 int:*0:[0]
KEY:=
+EXP
+TERM
CINT:0
-TERM
-EXP
-VAR
-VAR_LIST
-DECL
-STMT
KEY:;
+EXP
+TERM
+PATH
+ATOM
ID:i
-ATOM
-PATH
-TERM
KEY:<
+TERM
CINT:一0
-TERM
-EXP
KEY:;
+STMT
+PATH
+ATOM
ID:i
-ATOM
-PATH
KEY:++
-STMT
KEY:)
+BASE
+STMT
+PATH
+ATOM
ID:s
-ATOM
-PATH
KEY:=
+EXP
+TERM
+PATH
+ATOM
ID:s
-ATOM
-PATH
-TERM
KEY:+
+TERM
+PATH
+ATOM
ID:a
KEY:[
+EXP
+TERM
+PATH
+ATOM
ID:i
-ATOM
-PATH
-TERM
-EXP
KEY:]
-ATOM
-PATH
-TERM
-EXP
-STMT
KEY:;
-BASE
-FOR
-BASE
+BASE
+STMT
KEY:return
+EXP
+TERM
+PATH
+ATOM
ID:s
-ATOM
-PATH
-TERM
-EXP
-STMT
KEY:;
-BASE
KEY:}
-BLOCK
-METHOD
+METHOD
+TYPE
KEY:char
-TYPE
KEY:*
ID:getName
M getName 0 00三E九二七0 00四0A三四0
KEY:(
+PARAM_LIST
+PARAM
+TYPE
ID:Person
-TYPE
+VAR
KEY:*
ID:p
V p 0 00三E九五一八 00三E九二七0 Person:*一:[0]
-VAR
-PARAM
-PARAM_LIST
KEY:)
+BLOCK
B 0 00三E九六0八 00三E九二七0
KEY:{
+BASE
+STMT
KEY:return
+EXP
+TERM
+PATH
+ATOM
ID:p
-ATOM
KEY:->
+ATOM
ID:name
-ATOM
-PATH
-TERM
-EXP
-STMT
KEY:;
-BASE
KEY:}
-BLOCK
-METHOD
+METHOD
+TYPE
KEY:int
-TYPE
ID:main
M main 0 00三E九B七0 00四0A三四0
KEY:(
KEY:)
+BLOCK
B 0 00三E九CD八 00三E九B七0
KEY:{
+BASE
+STMT
+DECL
+TYPE
KEY:int
-TYPE
+VAR_LIST
+VAR
ID:b
V b 0 00三E九F八八 00三E九CD八 int:*0:[0]
KEY:[
CINT:一0
KEY:]
-VAR
KEY:,
+VAR
ID:a
V a 0 00三EA一七0 00三E九CD八 int:*0:[0]
KEY:=
+EXP
+TERM
CINT:三
-TERM
-EXP
-VAR
-VAR_LIST
-DECL
-STMT
KEY:;
-BASE
+BASE
+STMT
+DECL
+TYPE
KEY:int
-TYPE
+VAR_LIST
+VAR
ID:t
V t 0 00三EA五六0 00三E九CD八 int:*0:[0]
KEY:=
+EXP
+TERM
+PATH
+ATOM
ID:total
KEY:(
+EXP_LIST
+EXP
+TERM
+PATH
+ATOM
ID:b
-ATOM
-PATH
-TERM
-EXP
-EXP_LIST
KEY:)
-ATOM
-PATH
-TERM
-EXP
-VAR
-VAR_LIST
-DECL
-STMT
KEY:;
-BASE
+BASE
+STMT
+DECL
+TYPE
ID:Person
-TYPE
+VAR_LIST
+VAR
ID:p
V p 0 00三EAC四八 00三E九CD八 Person:*0:[0]
-VAR
-VAR_LIST
-DECL
-STMT
KEY:;
-BASE
+BASE
+STMT
+PATH
+ATOM
ID:p
-ATOM
KEY:.
+ATOM
ID:birthday
-ATOM
KEY:.
+ATOM
ID:year
-ATOM
-PATH
KEY:=
+EXP
+TERM
CINT:一九九0
-TERM
-EXP
-STMT
KEY:;
-BASE
+BASE
+STMT
+PATH
+ATOM
ID:t
-ATOM
-PATH
KEY:=
+EXP
+TERM
CINT:三
-TERM
KEY:+
+TERM
KEY:(
+EXP
+TERM
CINT:五
-TERM
KEY:*
+TERM
+PATH
+ATOM
ID:a
-ATOM
-PATH
-TERM
-EXP
KEY:)
-TERM
-EXP
-STMT
KEY:;
-BASE
+BASE
+STMT
KEY:return
+EXP
+TERM
+PATH
+ATOM
ID:t
-ATOM
-PATH
-TERM
-EXP
-STMT
KEY:;
-BASE
KEY:}
-BLOCK
-METHOD
-PROG
type name size this scope varType
V i 0 00三E八一二八 00三E七九B0 int:*0:[0]
M main 0 00三E九B七0 00四0A三四0
V month 0 00三E六BD八 00三E六八三0 int:*0:[0]
V name 0 00三E七一四八 00三E六EB八 char:*一:[0]
M total 0 00三E七五F八 00四0A三四0
V x 0 00三E二五五八 00四0A三四0 int:*0:[0]
V s 0 00三E七C六0 00三E七九B0 int:*0:[0]
V y 0 00三E六五九0 00四0A三四0 int:*0:[0]
B 0 00三E九CD八 00三E九B七0
V a 0 00三EA一七0 00三E九CD八 int:*0:[0]
V b 0 00三E九F八八 00三E九CD八 int:*0:[一]
S Person 0 00三E六EB八 00四0A三四0
T int 四 00三E五EB0 00四0A三四0
V a 0 00三E七八A八 00三E七五F八 int:*一:[0]
V p 0 00三EAC四八 00三E九CD八 Person:*0:[0]
T char 一 00三E五七E0 00四0A三四0
V t 0 00三EA五六0 00三E九CD八 int:*0:[0]
T float 四 00三E五七七八 00四0A三四0
B 0 00三E七九B0 00三E七五F八
V day 0 00三E六D一八 00三E六八三0 int:*0:[0]
M getName 0 00三E九二七0 00四0A三四0
V birthday 0 00三E七三九八 00三E六EB八 Date:*0:[0]
V p 0 00三E九五一八 00三E九二七0 Person:*一:[0]
V year 0 00三E六A八0 00三E六八三0 int:*0:[0]
S Date 0 00三E六八三0 00四0A三四0
B 0 00三E九六0八 00三E九二七0
Memory:newCount=二0九0 freeCount=二0九0
C一 顺序言语
类型1
int x=一, y=二;
struct Date {
int year, month, day;
}
struct Person {
char *name;
Date birthday;
}
int total(int* a) {
int s = 0;
for (int i=0; i<一0; i++)
s = s+a[i];
return s;
}
char* getName(Person *p) {
return p->name;
}
int main() {
int b[一0], a=三;
int t = total(b);
Person p;
p.birthday.year = 一九九0;
t = 三 + (五 * a);
return t;
}
参考链接:
http://ccckmit.wikidot.com/ocs:compiler
转自:https://www.cnblogs.com/wujianming-110117/p/15361264.html
更多文章请关注《万象专栏》
转载请注明出处:https://www.wanxiangsucai.com/read/cv3211