CPU0 处理器的架构及应用
简介
CPU0 是一个 32 位的处理器,包含 R0…R15, IR, MAR, MDR 等缓存器,结构如下图所示。

图 1 :CPU0 处理器的结构
其中各个缓存器的用途如下所示:
IR 指令缓存器
R0 常数缓存器, 值永远为 0。
R1~R11 通用型缓存器。
R12 状态缓存器 (Status Word : SW)
R13 堆栈指针缓存器 (Stack Pointer : SP)
R14 链接缓存器 (Link Register : LR)
R15 程序计数器 (Program Counter : PC)
MAR 地址缓存器 (Memory Address Register)
MDR 数据缓存器 (Memory Data Register)
CPU0 的指令集
CPU0 的指令分为三种类型,L 型通常为加载储存指令、A 型以算术指令为主、J 型则通常为跳跃指令,下图显示了这三种类型指令的编码格式。

图 2:CPU0 的三种指令格式
以下是 CPU0 处理器的指令表格式
表 1 :CPU0 的指令表

在第二版的 CPU0_v2 中,补上了以下指令:
类型 格式 指令 OP 说明 语法 语意
浮点运算 A FADD 41 浮点加法 FADD Ra, Rb, Rc Ra = Rb + Rc
浮点运算 A FSUB 42 浮点减法 FSUB Ra, Rb, Rc Ra = Rb + Rc
浮点运算 A FMUL 43 浮点乘法 FMUL Ra, Rb, Rc Ra = Rb * Rc
浮点运算 A FADD 44 浮点除法 FDIV Ra, Rb, Rc Ra = Rb / Rc
中断处理 J IRET 2D 中断返回 IRET PC = LR; INT 0
状态缓存器
CPU0 的状态缓存器,包含 N, Z, C, V 等状态,以及 I, T 等中断模式位。结构如下图所示。

图 3:CPU0 的状态缓存器
当 CMP Ra, Rb 指令执行时,状态标志会因而改变。
假如 Ra > Rb, 则会设定状态 N=0, Z=0
假如 Ra < Rb, 则会设定状态 N=1, Z=0
假如 Ra = Rb, 则会设定状态 N=0, Z=1
于是条件式跳跃的 JGT, JLT, JGE, JLE, JEQ, JNE 等指令,就可以根据状态缓存器中的 N, Z 标志进行跳跃操作。
指令的执行步骤
CPU0在执行一个指令时,必须经过取指、译码与执行等三大阶段。

  1. 提取阶段
    o 操作1、提取指令 :IR = [PC]
    o 操作2、更新计数器 :PC = PC + 4
  2. 解碼阶段
    o 操作3、解碼 :控制单元对IR进行译码后,设定数据流向开关与 ALU 的运算模式
  3. 运行时间
    o 操作4、执行 :数据流入 ALU,经过运算后,流回指定的缓存器
    V-OS: 横跨操作系统与硬件的虚拟机系统
  4. 设计一个虚拟机系统,可以将 CPU A, B, C, D, E … 模拟成另外任何一种 CPU,这样是否能解决所有的跨平台问题呢?
    o QEMU 其实可以做到类似的操作,想法与 QEMU 不同点在于 QEMU 是在操作系统层次之上的,做法是在操作系统层次之下的。
    o 这样子就可以将在任何一个 CPU 上,跑另一个操作系统的程序,但是,不知速度会比 QEMU 快还是慢呢?
    o 这种做法姑且可以想象为「云端虚拟机」!
    o 不知大家觉得可能吗?有用吗?

图一:V-OS 系统的架构图
CC1 编译程序
为了说明编译程序是如何设计出来的,在开放计算机计划中,设计了一个功能完备,简化过的 C 语言,这个语言称为 C1 语言,是 C0 语言的扩充版。
CC1 编译程序是一个 C1 语言的编译程序,具有完成的编译程序功能。在程序设计上,CC1 又被进一步拆解为 1. 词汇分析 2. 语法分析 3. 语意分析 4. 中间码产生 5. 汇编语言产生 等阶段,这所有的阶段,都会存取一个共同的数据结构,就是符号表。
因此,整个 CC1 编译程序,进一步分解为下列程序模块。
模块 核心对象 程序
词汇分析 (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

  1. 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 |

  2. Lua 5.1 Reference Manual — http://www.lua.org/manual/5.1/manual.html
    o 最后有 Lua 的 BNF。

  3. Lua Interpreter in C — http://www.lua.org/source/5.1/lua.c.html

  4. Lua Compiler in Lua — http://lua-users.org/wiki/LuaCompilerInLua

  5. Lua Interpreter in Lua — http://lua-users.org/wiki/LuaInterpreterInLua

  6. http://luajit.org/ — The LuaJIT Project
    CC1 编译程序的符号表
    #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
CC1 的词汇分析 (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[100], tokenSave[100]; // 目前的词汇
} 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); // 检查下一个词汇是否符合 tag 标记。
void ScannerNext(Scanner *s); // 取得下一个词汇 (token)
char ch(Scanner *s); // 取得目前字符
void cnext(Scanner *s); // 前进到下一个字符
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.c1”);
void ScannerTest(char *fileName) {
debug(“ScannerTest()===\n”);
char *text = fileToStr(fileName); // 读取整个程序文件,成为一个字符串 text
Scanner *s = ScannerNew(text); // 建立 Scanner 对象
while (TRUE) { // 不断扫描词汇,直到档案结束
ScannerNext(s); // 取得下一个词汇
debug(“token=%-10s tag=%-10s line=%-4d pos=%-3d\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, 1);
s->text = pText;
s->len = strlen(pText);
s->i = 0;
s->line = 1;
s->pos = 1;
// 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);
}

// 功能:检查下一个词汇是否符合 tag 标记。
// 范例:if (ScannerIsNext(s, “+|-|*|/”)) ScannerNext(s);
BOOL ScannerIsNext(Scanner *s, char *pTags) { // 检查下一个词汇的型态
char tTags[MAX_LEN+1];
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];
}

// 功能:前进到下一个字符
// 范例:while (strMember(ch(s), DIGIT)) cnext(s);
void cnext(Scanner *s) {
s->i++;s->pos++;
}

#define OP "±/%<=>!&|" // 运算符号字符集 (用来取得 +,-,,/, ++, …)

// 功能:Scanner 词汇分析阶段的测试程序。
// 范例:ScannerTest(“test.c1”);
void ScannerNext(Scanner s) { // 扫描下一个词汇
while (strMember(ch(s), SPACE)) { // 忽略空白
if (ch(s)==’\n’) {
s->line++;
s->pos = 1;
}
cnext(s);
}
if (s->i >= s->len) { // 如果超过程序结尾
s->tag = kEND; // 传回 tag = kEND
s->token[0] = ‘\0’; // 传回 token = 空字符串
return;
}
char c = ch(s); // 取得下一个字符
int begin = s->i; // 记住词汇开始点
if (c == ‘"’) { // 如果是 " 代表字符串开头
// 字符串常数 : string = “…”
cnext(s); // 跳过 "
while (ch(s) != ‘"’) cnext(s); // 一直读到下一个 " 符号为止。
cnext(s); // 跳过 "
} else if (strMember(c, OP)) { // 如果是OP(±
/<=>!等符号)
// 运算符号 : OP = ++, --, <=, >=, …
while (strMember(ch(s), OP)) cnext(s); // 一直读到不是OP为止
} else if (strMember(c, DIGIT)) { // 如果是数字
// 数字常数 : number = 312, 77568, …
while (strMember(ch(s), DIGIT)) cnext(s); // 一直读到不是数字为止
// 浮点常数 : float = 3.14, …
if (ch(s) == ‘.’) cnext(s); // 取得小数点
while (strMember(ch(s), DIGIT)) cnext(s); // 取得小数部分
} else if (strMember(c, ALPHA)) { // 如果是英文字母
// 基本词汇 : token = int, sum, i, for, if, x1y2z, …
while (strMember(ch(s), ALPHA) || strMember(ch(s), DIGIT))
cnext(s); // 一直读到不是英文字母 (或数字)为止
} else // 其他符号,都解读为单一字符
cnext(s); // 传回单一字符

// 字符串扫描完了,设定 token 为(begin…textIdx) 之间的子字符串
strSubstr(s->token, s->text, begin, (s->i) - begin); // 设定 token 的标记 tag
s->tag = tokenToTag(s->token);

}

// 功能:Scanner 词汇分析阶段的测试程序。
// 范例:ScannerTest(“test.c1”);
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=1, y=2;

struct Date {
int year, month, day;
}

struct Person {
char *name;
Date birthday;
}

int total(int* a) {
int s = 0;
for (int i=0; i<10; i++)
s = s+a[i];
return s;
}

char* getName(Person *p) {
return p->name;
}

int main() {
int b[10], a=3;
int t = total(b);
Person p;
p.birthday.year = 1990;
t = 3 + (5 * a);
return t;
}
测试程序 ScannerTest() 的执行结果
ScannerTest()=
token=int tag=int line=1 pos=4
token=x tag=ID line=1 pos=6
token tag line=1 pos=7
token=1 tag=CINT line=1 pos=8
token=, tag=, line=1 pos=9
token=y tag=ID line=1 pos=11
token== tag== line=1 pos=12
token=2 tag=CINT line=1 pos=13
token=; tag=; line=1 pos=14
token=struct tag=struct line=3 pos=8
token=Date tag=ID line=3 pos=13
token={ tag={ line=3 pos=15
token=int tag=int line=4 pos=9
token=year tag=ID line=4 pos=14
token=, tag=, line=4 pos=15
token=month tag=ID line=4 pos=21
token=, tag=, line=4 pos=22
token=day tag=ID line=4 pos=26
token=; tag=; line=4 pos=27
token=} tag=} line=5 pos=3
token=struct tag=struct line=7 pos=8
token=Person tag=ID line=7 pos=15
token={ tag={ line=7 pos=17
token=char tag=char line=8 pos=7
token=* tag=* line=8 pos=9
token=name tag=ID line=8 pos=13
token=; tag=; line=8 pos=14
token=Date tag=ID line=9 pos=7
token=birthday tag=ID line=9 pos=16
token=; tag=; line=9 pos=17
token=} tag=} line=10 pos=3
token=int tag=int line=12 pos=5
token=total tag=ID line=12 pos=11
token=( tag=( line=12 pos=12
token=int tag=int line=12 pos=15
token=* tag=* line=12 pos=16
token=a tag=ID line=12 pos=18
token=) tag=) line=12 pos=19
token={ tag={ line=12 pos=21
token=int tag=int line=13 pos=6
token=s tag=ID line=13 pos=8
token== tag== line=13 pos=10
token=0 tag=CINT line=13 pos=12
token=; tag=; line=13 pos=13
token=for tag=for line=14 pos=6
token=( tag=( line=14 pos=8
token=int tag=int line=14 pos=11
token=i tag=ID line=14 pos=13
token== tag== line=14 pos=14
token=0 tag=CINT line=14 pos=15
token=; tag=; line=14 pos=16
token=i tag=ID line=14 pos=18
token=< tag=< line=14 pos=19
token=10 tag=CINT line=14 pos=21
token=; tag=; line=14 pos=22
token=i tag=ID line=14 pos=24
token=++ tag=++ line=14 pos=26
token=) tag=) line=14 pos=27
token=s tag=ID line=15 pos=5
token== tag== line=15 pos=7
token=s tag=ID line=15 pos=9
token=+ tag=+ line=15 pos=10
token=a tag=ID line=15 pos=11
token=[ tag=[ line=15 pos=12
token=i tag=ID line=15 pos=13
token=] tag=] line=15 pos=14
token=; tag=; line=15 pos=15
token=return tag=return line=16 pos=9
token=s tag=ID line=16 pos=11
token=; tag=; line=16 pos=12
token=} tag=} line=17 pos=3
token=char tag=char line=19 pos=6
token=* tag=* line=19 pos=7
token=getName tag=ID line=19 pos=15
token=( tag=( line=19 pos=16
token=Person tag=ID line=19 pos=22
token=* tag=* line=19 pos=24
token=p tag=ID line=19 pos=25
token=) tag=) line=19 pos=26
token={ tag={ line=19 pos=28
token=return tag=return line=20 pos=9
token=p tag=ID line=20 pos=11
token=-> tag=-> line=20 pos=13
token=name tag=ID line=20 pos=17
token=; tag=; line=20 pos=18
token=} tag=} line=21 pos=3
token=int tag=int line=23 pos=5
token=main tag=ID line=23 pos=10
token=( tag=( line=23 pos=11
token=) tag=) line=23 pos=12
token={ tag={ line=23 pos=14
token=int tag=int line=24 pos=6
token=b tag=ID line=24 pos=8
token=[ tag=[ line=24 pos=9
token=10 tag=CINT line=24 pos=11
token=] tag=] line=24 pos=12
token=, tag=, line=24 pos=13
token=a tag=ID line=24 pos=15
token== tag== line=24 pos=16
token=3 tag=CINT line=24 pos=17
token=; tag=; line=24 pos=18
token=int tag=int line=25 pos=6
token=t tag=ID line=25 pos=8
token== tag== line=25 pos=10
token=total tag=ID line=25 pos=16
token=( tag=( line=25 pos=17
token=b tag=ID line=25 pos=18
token=) tag=) line=25 pos=19
token=; tag=; line=25 pos=20
token=Person tag=ID line=26 pos=9
token=p tag=ID line=26 pos=11
token=; tag=; line=26 pos=12
token=p tag=ID line=27 pos=4
token=. tag=. line=27 pos=5
token=birthday tag=ID line=27 pos=13
token=. tag=. line=27 pos=14
token=year tag=ID line=27 pos=18
token== tag== line=27 pos=20
token=1990 tag=CINT line=27 pos=25
token=; tag=; line=27 pos=26
token=t tag=ID line=28 pos=4
token== tag== line=28 pos=6
token=3 tag=CINT line=28 pos=8
token=+ tag=+ line=28 pos=10
token=( tag=( line=28 pos=12
token=5 tag=CINT line=28 pos=13
token=* tag=* line=28 pos=15
token=a tag=ID line=28 pos=17
token=) tag=) line=28 pos=18
token=; tag=; line=28 pos=19
token=return tag=return line=29 pos=9
token=t tag=ID line=29 pos=11
token=; tag=; line=29 pos=12
token=} tag=} line=30 pos=3
token= tag=?END? line=32 pos=3
Memory:newCount=438 freeCount=438
程序语言 C1 的语法规则
EBNF 语法
// =============== C1 语言的 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 OP1
// VAR = ** ID ([ integer ])* (= EXP)?
// EXP = TERM (OP2 TERM)?
// TERM = ( EXP (OP2 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) // 最后一个 ID 必须是 TYPE [STRUCT]
// ID = [A-Za-z_][0-9A-Za-z_]*
// CINT = [0-9]+
// CFLOAT = [0-9]+.[0-9]+
// CSTR = "."
// OP2 = +|-|/|
|%|&|&&|^|<<|>>|<|>|<=|>=|==|!=| 与 | , ||
// OP1 = ++ | –
C1 语言的剖析器 – CC1
开放计算机计划 — 最新版本下载

  1. ss1v0.50.zip — 包含虚拟机 VM1, 组译器 AS1, 编译程序 CC1 (剖析器完成,符号表完成,程序代码产生修改中)
    档案:Parser.h
    // =============== C1 语言的 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 OP1
    // VAR = ** ID ([ integer ])* (= EXP)?
    // EXP = TERM (OP2 TERM)?
    // TERM = ( EXP (OP2 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) // 最后一个 ID 必须是 TYPE [STRUCT]
    // ID = [A-Za-z_][0-9A-Za-z_]*
    // CINT = [0-9]+
    // CFLOAT = [0-9]+.[0-9]+
    // CSTR = "."
    // OP2 = +|-|/|
    |%|&|&&|^|<<|>>|<|>|<=|>=|==|!=| 与 | , ||
    // OP1 = ++ | –

#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 OP1
Tree
parseBlock(Parser p); // BLOCK = { BASE }
Tree* parseVar(Parser p); // VAR = ** ID ([ integer ]) (= EXP)?
Tree* parseExp(Parser p); // EXP = TERM (OP2 TERM)?
Tree
parseTerm(Parser p); // TERM = ( EXP (OP2 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-9A-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, 1);Tree *node=push1(p, tag);node->sem=sem;
Tree *push1(Parser p, char tag); // 建立标记为 tag 的新子树。
Tree *pop(Parser p, char tag); // 从堆栈中取出剖析完成的子树,并检查标记是否为 tag。
BOOL isNext(Parser *p, char *tags); // 检查下一个 token 的 tag 是否属于 tags 标记之一。
Tree *next(Parser *p, char *tags); // 取得下一个 token,并确认其 tag 为 tags 标记之一。
char *token(Tree *node); // 取得树叶节点 node 的 token。

void pushBlock(Parser *p, Symbol *sym); // 将区块符号推入堆栈
#define popBlock§ ArrayPop(p->blockStack) // 从堆栈取出区块符号
#define peekBlock§ ArrayPeek(p->blockStack) // 取得最上面的区块符号

// Token 的集合,用来检查是关键词,操作数,基本型态,或者只是变量 ID。
#define SET_KEYWORDS “|if|else|for|while|return|def|int|byte|char|float|struct|”
#define SET_OP1 “|++|–|”
#define SET_OP2 “|+|-|*|/|%|^|&|<<|>>|==|!=|<=|>=|<|>|&&||||”
#define SET_BTYPE “|int|byte|char|float|”

#endif
档案:Parser.c
#include “Parser.h”

// 功能:Parser 剖析阶段的测试程序。
// 范例:ParserTest(“test.c1”);
void ParserTest(char *fileName) {
debug("=ParserTest()====\n");
SymTable *symTable = SymTableNew(); // 建立符号表
char *text = fileToStr(fileName); // 读入 C1 语言程序代码,成为一字符串
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§; // 释放颇析树
ScannerFree(scanner); // 释放扫描仪
return tree; // 传回剖析器
}

// 功能:建立新的剖析器 Parser 对象
// 范例:Parser *p = ParserNew(scanner, symTable);
Parser *ParserNew(Scanner *scanner, SymTable *symTable) {
Parser *p = ObjNew(Parser, 1); // 分配剖析器空间
p->nodeStack = ArrayNew(10); // 分配 nodeStack 堆栈空间
p->blockStack = ArrayNew(10); // 分配 blockStack 堆栈空间
p->scanner = scanner; // 设定扫瞄器
p->symTable = symTable; // 设定符号表
ScannerNext(scanner); // 本剖析器总是先取得下一个 token,以便 isNext() 进行判断。
return p;
}

// 功能:释放剖析器对象的内存
// 范例:ParserFree§;
void ParserFree(Parser *p) {
ArrayFree(p->blockStack, (FuncPtr1) BlockFree); // 释放 blockStack 堆栈空间
ArrayFree(p->nodeStack, NULL); // 释放 nodeStack 堆栈空间
ObjFree§; // 释放剖析器空间
}

// 功能:剖析整个程序代码 (text)。
// 范例:ParserParse(p, text);
Tree *ParserParse(Parser *p, char *text) { // 剖析对象的主函数
debug("======= parsing ========\n");
Tree *tree = parseProg§; // 开始剖析整个程序 (PROG),并建立语法树 p->tree
if (p->nodeStack->count != 0) { // 如果剖析完成后堆栈是空的,那就是剖析成功
ERROR();// 否则就是剖析失败,有语法错误
}
return tree;
}

// 语法:PROG = (STRUCT | METHOD | DECL ; )*
// 功能:剖析 PROG 并建立语法树
// 范例:Tree *prog = parseProg§;
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§;
else { // 由于 METHOD 与 DECL 的开头都是 TYPE **ID …,因此必须判断是哪一种情况。
if (isMethod§) { // 向前偷看后发现是 TYPE **ID(,所以是 Method
parseMethod§;
} else { // 否则就必须是 DECL ;
parseDecl§;
next(p, “;”);
}
}
}
popBlock§; // 取出全局区块
return pop(p, PROG); // 取出 PROG 的整棵语法树
}

// 语法:METHOD = TYPE **ID (PARAM_LIST?) BLOCK
// 功能:判断到底接下来是否为 METHOD,是的话传回 TRUE,否则传回 FALSE
// 由于 METHOD 与 DECL 的开头都是 TYPE **ID …,因此必须判断是哪一种情况。
// 本函数会向前偷看,如果发现是 TYPE **ID(,那就应该是 Method。
// 范例:if (isMethod§) parseMethod§;
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§;
Tree
parseMethod(Parser *p) {
SemMethod *sem=push(p, METHOD, SemMethod); // 建立 METHOD 的语法树及语意结构
sem->type=parseType§; // 剖析 TYPE

// 剖析 ** (n 个星号, n>=0)
int starCount = 0; // 星号数量的初始值
while (isNext(p, "*")) { // 如果下一个是星号 next(p, "*"); // 取得该星号 starCount ++; // 将星号数加一
}
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); // 剖析 BLOCKpopBlock(p);
return pop(p, METHOD); // 取出 METHOD 的语法树。

}

// 语法:STRUCT = struct ID { (DECL

CPU0 处理器的架构及应用相关推荐

  1. ARM系列处理器和架构

    从一只ARM到另一只ARM! ARM处理器和架构 当前可用的处理器 ARM1 ARM2 ARM3 ARM4和5 ARM6 ARM7 ARM8 强壮有力的ARM ARM9 ARM10 ARM架构 v1 ...

  2. Qualcomm 处理器 Krait架构

    Krait是美国高通公司基于ARMv7-A指令集.自主设计的采用28纳米工艺的全新处理器微架构.能够实现每个内核最高运行速度可达2.5GHz,较高通第一代的Scorpion CPU微架构在性能上提高6 ...

  3. 图像信号处理器及其架构演进

    图像信号处理器及其架构演进 对于一个成像系统,其图像信号采集部分包括光学器件的镜头组和光电器件的CMOS/CCD成像传感器,由于其在设计和制造阶段的缺陷,在按下快门采集得到的图像信号上有各种各样的缺陷 ...

  4. FPGA||ZYNQ概念理解之: Cortex-A9 处理器及架构

    源起 Zynq系列的亮点在于FPGA里包含了完整的ARM处理子系统(PS),每一颗Zynq系列的处理器都包含了Cortex-A9处理器,整个处理器的搭建都以处理器为重心,而且处理器子系统中继承了内存控 ...

  5. 科普:什么是处理器微架构?

    本次来分享一些芯片相关的小科普文.作为嵌入式开发工程师,我们对芯片都需要有一定的了解. 指令集 1.指令集的体现 指令集,就是CPU中用来计算和控制计算机系统的一套指令的集合.而指令集的先进与否,也关 ...

  6. 知识补给站:处理器微架构

    前言: 在这个补给站,我稍微简单介绍一下处理器中的一些架构(设计上的一些小trick),顺便再来讲讲保护模式到底保护了哪些东西 一,处理器微架构 ①,流水线 流水线大家肯定经常听说过,富士康工厂经常就 ...

  7. 查看安卓(Android)设备处理器(CPU)架构(Architecture)信息

    查看安卓(Android)设备处理器(CPU)架构(Architecture)信息 $ adb shell $ cat /proc/cpuinfo 输出以下信息: $ cat /proc/cpuinf ...

  8. Linux Arch目录下处理器体系架构介绍

    alpha 处理器 Alpha 处理器最早由美国DEC 公司设计制造,在Compaq (康柏)公司收购DEC 之后,Alpha 处理器继续得到发展,并且应用于许多高档的Compaq 服务器上,HP ( ...

  9. 一步步编写操作系统 27 处理器微架构之流水线简介

    了解处理器内部硬件架构,有助于理解软件运行原理,因为这两者本身相辅相成,相互依存.就像枪和狙击手,枪的操作和外形设计都是要根据人体工学,让人不仅操作容易,而且携带也要轻便,做到能随时射出子弹击中目标, ...

最新文章

  1. [转] Logistic函数
  2. 20应用统计考研复试要点(part13)--应用多元分析
  3. 利用ABAP调试模式修改SE16里数据库表的内容
  4. 微信小程序循环不同列表实现动态点击隐藏
  5. jq查找字段忽略html标签,jQuery过滤HTML标签并高亮显示关键字的方法
  6. python高级-异常(13)
  7. Mybatis Plus分页Page total始终为0
  8. 为大众而写的程序员小说——从《简单易懂的现代魔法》说开去。
  9. stm32 BKP 擦除后备寄存器存储的数据
  10. 浏览器英文快捷翻译工具~~有道词典
  11. unity-摄像机跟随
  12. Pytorch深度学习笔记(四)梯度向下算法
  13. 安装深度linux系统卡住不动,Linux安装系统卡住
  14. 苹果手机打字换行怎么换_苹果id怎么换
  15. css针对IE单独设置样式
  16. linux vi 选中某一列,在 Vim 中进行文本选择操作和使用标志
  17. 聆思CSK6视觉AI开发套件使用——AI手势识别+头肩识别+编译helloworld
  18. 【学习打卡】GradCAM可解释性分析
  19. 事业单位计算机岗位职业职责,事业单位的四个岗位,都有哪些?具体工作职责是什么?...
  20. CAD文件解析后按照特定规则将图形切割

热门文章

  1. 2022-2028年中国数字电视产业投资分析及前景预测报告(全卷)
  2. kali安装vscode和无法启动解决方法
  3. 外包工作经历暨2021年终总结
  4. 【VS实践】VS解决方案中出现无法生成DLL文件
  5. python 过滤出某后缀名文件
  6. 2021年大数据常用语言Scala(二十四):函数式编程 过滤  filter
  7. CSS grid 的用法
  8. HarmonyOS UI开发 match_parent与match_content
  9. python 读取excel 表格的数据
  10. 025批量删除mac文件名中的空格