日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

CPU0 处理器的架构及应用

發布時間:2023/11/28 生活经验 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 CPU0 处理器的架构及应用 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

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 😉* }
// 功能:剖析 STRUCT 并建立語法樹
// 范例:Tree s = parseStruct§;
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§;
Tree
parseBase(Parser *p) { // 剖析 BASE 規則
SemBase *sem=push(p, BASE, SemBase); // 建立 BASE 的語法樹及語意結構
if (isNext(p, “if”)) // 如果下一個詞匯是 if
parseIf§; // 剖析 IF 程序段
else if (isNext(p, “for”)) // 如果下一個詞匯是 for
parseFor§; // 剖析 FOR 程序段
else if (isNext(p, “while”)) // 如果下一個詞匯是 for
parseWhile§; // 剖析 WHILE 程序段
else if (isNext(p, “{”)) // 如果下一個詞匯是 {
parseBlock§; // 剖析 BLOCK 程序段
else { // 否則應該是 STMT ;
parseStmt§; // 剖析 STMT 程序段
next(p, “;”); // 取得分號 ;
}
return pop(p, BASE); // 取出 BASE 的剖析樹
}

// 語法:BLOCK = { BASE* }
// 功能:剖析 BLOCK 并建立語法樹
// 范例:Tree block = parseBlock§;
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§;
Tree
parseFor(Parser *p) {
SemFor *sem=push(p, FOR, SemFor); // 建立 FOR 的語法樹及語意結構
next(p, “for”); // 取得 for
next(p, “(”); // 取得 (
sem->stmt1 = parseStmt§; // 剖析 STMT
next(p, “;”); // 取得 ;
sem->exp = parseExp§; // 剖析 EXP
next(p, “;”); // 取得 ;
sem->stmt2 = parseStmt§; // 剖析 STMT
next(p, “)”); // 取得 )
parseBase§; // 剖析 BASE
return pop(p, FOR); // 取出 FOR 的語法樹。
}

// 語法:IF = if (EXP) BASE (else BASE)?
// 功能:剖析 IF 并建立語法樹
// 范例:Tree f = parseIf§;
Tree
parseIf(Parser *p) {
SemIf *sem=push(p, IF, SemIf); // 建立 IF 的語法樹及語意結構
next(p, “if”); // 取得 if
next(p, “(”); // 取得 (
sem->exp = parseExp§; // 剖析 EXP
next(p, “)”); // 取得 )
sem->base1 = parseBase§; // 剖析 BASE
if (isNext(p, “else”)) { // 如果下一個是 else
next(p, “else”); // 取得 else
sem->base2 = parseBase§; // 剖析下一個 BASE
}
return pop(p, IF); // 取出 IF 的語法樹。
}

// 語法:WHILE = while (EXP) BASE
// 功能:剖析 WHILE 并建立語法樹
// 范例:Tree w = parseWhile§;
Tree
parseWhile(Parser *p) {
SemWhile *sem=push(p, WHILE, SemWhile);// 建立 WHILE 的語法樹及語意結構
next(p, “while”); // 取得 while
next(p, “(”); // 取得 (
sem->exp = parseExp§; // 剖析 EXP
next(p, “)”); // 取得 )
sem->base = parseBase§; // 剖析 BASE
return pop(p, WHILE); // 取出 WHILE 的語法樹。
}

// 語法:STMT = return EXP | DECL | PATH (EXP_LIST) | PATH = EXP | PATH OP1
// 功能:剖析 STMT 并建立語法樹
// 范例:Tree stmt = parseStmt§;
Tree
parseStmt(Parser *p) {
SemStmt *sem=push(p, STMT, SemStmt);// 建立 STMT 的語法樹及語意結構
if (isNext(p, “return”)) { // 如果下一個是 return,就剖析 return EXP
next(p, “return”);
sem->exp = parseExp§;
} else if (isDecl§) { // 如果是 DECL
sem->decl = parseDecl§; // 剖析 DECL
} else { // 否則下一個必須是 PATH
sem->path = parsePath§; // 剖析 PATH
if (isNext(p, “(”)) { // 下一個是 (,代表是 PATH (EXP_LIST) 的情況
next(p, “(”);
sem->expList = parseExpList§;
next(p, “)”);
} else if (isNext(p, “=”)) { // 下一個是 =,代表是 PATH = EXP 的情況
next(p, “=”);
sem->exp = parseExp§;
} else if (isNext(p, SET_OP1)) { // 下一個是OP1,代表是 PATH OP1 的情況
next(p, SET_OP1);
} else
ERROR();
}
return pop(p, STMT); // 取出 STMT 的語法樹。
}

// 語法:PATH = ATOM ((.|->) ATOM)*
// 功能:剖析 PATH 并建立語法樹
// 范例:Tree path = parsePath§;
Tree
parsePath(Parser *p) {
SemPath *sem=push(p, PATH, SemPath);// 建立 PATH 的語法樹及語意結構
parseAtom§; // 剖析 DECL
while (isNext(p, “.|->”)) { // 不斷取得 (.|->) ATOM
next(p, “.|->”);
parseAtom§;
}
return pop(p, PATH); // 取出 PATH 的語法樹。
}

// 語法:ATOM = ID (([ EXP ])* |( EXP_LIST? ))
// 功能:剖析 ATOM 并建立語法樹
// 范例:Tree atom = parseAtom§;
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§;
next(p, “)”);
sem->subTag = CALL;
} else if (isNext(p, “[”)) { // 如果接下來是 [,則應該是數組宣告 ID ([ EXP ])

sem->subTag = ARRAY_MEMBER;
while (isNext(p, “[”)) {
next(p, “[”);
Tree *exp = parseExp§;
next(p, “]”);
}
}
return pop(p, ATOM); // 取出 ATOM 的語法樹。
}

// 語法:PARAM = TYPE VAR
// 功能:剖析 PARAM 并建立語法樹
// 范例:Tree param = parseParam§;
Tree
parseParam(Parser *p) {
SemParam *sem = push(p, PARAM, SemParam);// 建立 PARAM 的語法樹及語意結構
sem->type = parseType§; // 剖析 TYPE
sem->var = parseVar§; // 剖析 VAR
return pop(p, PARAM); // 取出 PARAM 的語法樹。
}

// 語法:DECL = TYPE VAR_LIST
// 功能:判斷到底接下來是否為 DECL,是的話傳回 TRUE,否則傳回 FALSE
// 本函數會向前偷看,如果發現是 (int|byte|char|float|ID)** ID,那就是 DECL
// 范例:if (isDecl§) parseDecl§;
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§;
Tree
parseDecl(Parser *p) {
SemDecl *sem = push(p, DECL, SemDecl);// 建立 DECL 的語法樹及語意結構
sem->type = parseType§; // 剖析 TYPE
sem->varList = parseVarList§; // 剖析 VAR_LIST
return pop(p, DECL); // 取出 DECL 的語法樹。
}

// 語法:TYPE = (int | byte | char | float | ID) // ID is STRUCT_TYPE
// 功能:剖析 TYPE 并建立語法樹
// 范例:Tree type = parseType§;
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§;
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 (OP2 TERM)?
// 功能:剖析 EXP 并建立語法樹
// 范例:Tree exp = parseExp§;
Tree
parseExp(Parser *p) {
SemExp *sem = push(p, EXP, SemExp);// 建立 EXP 的語法樹及語意結構
sem->term1 = parseTerm§; // 剖析 TERM
if (isNext(p, SET_OP2)) { // 如果接下來是 OP2 ,則剖析 (OP2 TERM)?
sem->op = next(p, SET_OP2);
sem->term2 = parseTerm§;
}
return pop(p, EXP); // 取出 EXP 的語法樹。
}

// 語法:TERM = ( EXP (OP2 EXP)? ) | CINT | CFLOAT | CSTR | PATH
// 功能:剖析 TERM 并建立語法樹
// 范例:Tree term = parseTerm§;
Tree
parseTerm(Parser *p) {
SemTerm *sem = push(p, TERM, SemTerm);// 建立 TERM 的語法樹及語意結構
if (isNext(p, “(”)) { // 如果下一個是 (,那就是 ( EXP (OP2 EXP)? ) 的情況
next(p, “(”);
sem->exp1 = parseExp§;
if (!isNext(p, “)”)) { // 看看是否有 (OP2 EXP)
next(p, SET_OP2);
sem->exp2 = parseExp§;
}
next(p, “)”);
} else if (isNext(p, “CINT|CFLOAT|CSTR”)) { // 如果是 CINT, CFLOAT 或 CSTR
next(p, “CINT|CFLOAT|CSTR”); // 取得 CINT, CFLOAT 或 CSTR
} else
parsePath§; // 否則應該是 PATH,剖析之
return pop(p, TERM); // 取出 TERM 的語法樹。
}

// 語法:VAR_LIST = VAR (, VAR)*
// 功能:剖析 VarList 并建立語法樹
// 范例:Tree varList = parseVarList§;
Tree
parseVarList(Parser *p) {
SemVarList sem = push(p, VAR_LIST, SemVarList);// 建立 VAR_LIST 的語法樹及語意結構
parseVar§; // 剖析 VAR
while (isNext(p, “,”)) { // 剖析 (,VAR)

next(p, “,”);
parseVar§;
}
return pop(p, VAR_LIST); // 取出 VAR_LIST 的語法樹。
}

// 語法:EXP_LIST = EXP (, EXP)*
// 功能:剖析 EXP_LIST 并建立語法樹
// 范例:Tree expList = parseExpList§;
Tree
parseExpList(Parser *p) {
SemExpList sem = push(p, EXP_LIST, SemExpList);// 建立 EXP_LIST 的語法樹及語意結構
parseExp§; // 剖析 EXP
while (isNext(p, “,”)) { // 剖析 (, EXP)

next(p, “,”);
parseExp§;
}
return pop(p, EXP_LIST); // 取出 EXP_LIST 的語法樹。
}

// 語法:DECL_LIST = DECL (; DECL)*
// 功能:剖析 DECL_LIST 并建立語法樹
// 范例:Tree declList = parseDeclList§;
Tree
parseDeclList(Parser *p) {
SemDeclList sem=push(p, DECL_LIST, SemDeclList);// 建立 DECL_LIST 的語法樹及語意結構
parseDecl§; // 剖析 DECL
while (isNext(p, “;”)) { // 剖析 (; DECL)

next(p, “;”);
parseDecl§;
}
return pop(p, DECL_LIST); // 取出 DECL_LIST 的語法樹。
}

// 語法:PARAM_LIST = PARAM (, PARAM)*
// 功能:剖析 PARAM_LIST 并建立語法樹
// 范例:Tree paramList = parseParamList§;
Tree
parseParamList(Parser *p) {
SemParamList sem=push(p, PARAM_LIST, SemParamList);// 建立 PARAM_LIST 的語法樹及語意結構
parseParam§; // 剖析 PARAM
while (isNext(p, “;”)) { // 剖析 (, PARAM)

next(p, “;”);
parseParam§;
}
return pop(p, PARAM_LIST); // 取出 PARAM_LIST 的語法樹。
}

// ========================== 基本函數 ====================================
// 功能:取得 p->nodeStack->count 個空白, 以便印出剖析樹時能有階層式的排版。
// 范例:debug("%s KEY:%s\n", level§, s->tag);
char* level(Parser *p) {
return strFill(p->spaces, ’ ', p->nodeStack->count);
}

// 功能:判斷下一個 token 的標記是否為 tags 其中之一
// 范例:if (isNext(p, “struct”)) parseStruct§;
BOOL isNext(Parser *p, char *tags) { // 檢查下一個詞匯的型態
Scanner *s = p->scanner;
char tTags[MAX_LEN+1];
sprintf(tTags, “|%s|”, tags);
if (strPartOf(s->tag, tTags))
return TRUE;
else
return FALSE;
}

// 功能:取得下一個 token (標記必須為 tag 其中之一),然后掛到剖析樹上
// 范例:Tree *node = next(p, “CINT|CFLOAT|CSTR”);
Tree *next(Parser *p, char *tags) { // 檢查下一個詞匯的型態
Scanner *s = p->scanner;
if (isNext(p, tags)) { // 如果是pTypes型態之一
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§, s->tag);
else
debug("%s %s:%s\n", level§, s->tag, s->token);
ScannerNext(s);
return child; // 傳回該詞匯
} else { // 否則(下一個節點型態錯誤)
debug(“next():token=%s, tag=%s is not in tag(%s)\n”, s->token, s->tag, tags); // 印出錯誤訊息
ERROR();
return NULL;
}
}

// 功能:建立 tag 標記的非終端節點,并且推入堆棧中
// 范例:Tree node = push1(p, IF);
Tree
push1(Parser p, char tag) { // 建立 pType 型態的子樹,推入堆棧中
debug("%s+%s\n", level§, 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§, 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); // 取出上一層剖析樹
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.c1
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;
}
剖析器的輸出結果
======= parsing ========
+PROG
+DECL
+TYPE
KEY:int
-TYPE
+VAR_LIST
+VAR
ID:x
V x 0 003E2558 0040A340 int:*0:[0]
KEY:=
+EXP
+TERM
CINT:1
-TERM
-EXP
-VAR
KEY:,
+VAR
ID:y
V y 0 003E6590 0040A340 int:*0:[0]
KEY:=
+EXP
+TERM
CINT:2
-TERM
-EXP
-VAR
-VAR_LIST
-DECL
KEY:;
+STRUCT
KEY:struct
ID:Date
S Date 0 003E6830 0040A340
KEY:{
+DECL
+TYPE
KEY:int
-TYPE
+VAR_LIST
+VAR
ID:year
V year 0 003E6A80 003E6830 int:*0:[0]
-VAR
KEY:,
+VAR
ID:month
V month 0 003E6BD8 003E6830 int:*0:[0]
-VAR
KEY:,
+VAR
ID:day
V day 0 003E6D18 003E6830 int:0:[0]
-VAR
-VAR_LIST
-DECL
KEY:;
KEY:}
-STRUCT
+STRUCT
KEY:struct
ID:Person
S Person 0 003E6EB8 0040A340
KEY:{
+DECL
+TYPE
KEY:char
-TYPE
+VAR_LIST
+VAR
KEY:

ID:name
V name 0 003E7148 003E6EB8 char:*1:[0]
-VAR
-VAR_LIST
-DECL
KEY:;
+DECL
+TYPE
ID:Date
-TYPE
+VAR_LIST
+VAR
ID:birthday
V birthday 0 003E7398 003E6EB8 Date:0:[0]
-VAR
-VAR_LIST
-DECL
KEY:;
KEY:}
-STRUCT
+METHOD
+TYPE
KEY:int
-TYPE
ID:total
M total 0 003E75F8 0040A340
KEY:(
+PARAM_LIST
+PARAM
+TYPE
KEY:int
-TYPE
+VAR
KEY:

ID:a
V a 0 003E78A8 003E75F8 int:*1:[0]
-VAR
-PARAM
-PARAM_LIST
KEY:)
+BLOCK
B 0 003E79B0 003E75F8
KEY:{
+BASE
+STMT
+DECL
+TYPE
KEY:int
-TYPE
+VAR_LIST
+VAR
ID:s
V s 0 003E7C60 003E79B0 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 003E8128 003E79B0 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:10
-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 003E9270 0040A340
KEY:(
+PARAM_LIST
+PARAM
+TYPE
ID:Person
-TYPE
+VAR
KEY:

ID:p
V p 0 003E9518 003E9270 Person:*1:[0]
-VAR
-PARAM
-PARAM_LIST
KEY:)
+BLOCK
B 0 003E9608 003E9270
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 003E9B70 0040A340
KEY:(
KEY:)
+BLOCK
B 0 003E9CD8 003E9B70
KEY:{
+BASE
+STMT
+DECL
+TYPE
KEY:int
-TYPE
+VAR_LIST
+VAR
ID:b
V b 0 003E9F88 003E9CD8 int:*0:[0]
KEY:[
CINT:10
KEY:]
-VAR
KEY:,
+VAR
ID:a
V a 0 003EA170 003E9CD8 int:*0:[0]
KEY:=
+EXP
+TERM
CINT:3
-TERM
-EXP
-VAR
-VAR_LIST
-DECL
-STMT
KEY:;
-BASE
+BASE
+STMT
+DECL
+TYPE
KEY:int
-TYPE
+VAR_LIST
+VAR
ID:t
V t 0 003EA560 003E9CD8 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 003EAC48 003E9CD8 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:1990
-TERM
-EXP
-STMT
KEY:;
-BASE
+BASE
+STMT
+PATH
+ATOM
ID:t
-ATOM
-PATH
KEY:=
+EXP
+TERM
CINT:3
-TERM
KEY:+
+TERM
KEY:(
+EXP
+TERM
CINT:5
-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 003E8128 003E79B0 int:*0:[0]
M main 0 003E9B70 0040A340
V month 0 003E6BD8 003E6830 int:*0:[0]
V name 0 003E7148 003E6EB8 char:*1:[0]
M total 0 003E75F8 0040A340
V x 0 003E2558 0040A340 int:*0:[0]
V s 0 003E7C60 003E79B0 int:*0:[0]
V y 0 003E6590 0040A340 int:*0:[0]
B 0 003E9CD8 003E9B70
V a 0 003EA170 003E9CD8 int:*0:[0]
V b 0 003E9F88 003E9CD8 int:*0:[1]
S Person 0 003E6EB8 0040A340
T int 4 003E5EB0 0040A340
V a 0 003E78A8 003E75F8 int:*1:[0]
V p 0 003EAC48 003E9CD8 Person:*0:[0]
T char 1 003E57E0 0040A340
V t 0 003EA560 003E9CD8 int:*0:[0]
T float 4 003E5778 0040A340
B 0 003E79B0 003E75F8
V day 0 003E6D18 003E6830 int:*0:[0]
M getName 0 003E9270 0040A340
V birthday 0 003E7398 003E6EB8 Date:*0:[0]
V p 0 003E9518 003E9270 Person:*1:[0]
V year 0 003E6A80 003E6830 int:*0:[0]
S Date 0 003E6830 0040A340
B 0 003E9608 003E9270
Memory:newCount=2090 freeCount=2090
C1 程序語言
范例一
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;
}

參考鏈接:
http://ccckmit.wikidot.com/ocs:compiler

總結

以上是生活随笔為你收集整理的CPU0 处理器的架构及应用的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。