Cc0psem2

輸入檔：test.c0

``````int x=3, y=5, z;
if ((x+y)>6)
z = 0;
else
z = 1;

int i=0, s=0;
while (i<100) {
s = s + i;
i++;
}

def sum(int n) {
for (i=0; i<n; i++)
s = s + i;
return s;
}

def swap(int a, int b) {
t = a;
a = b;
b = t;
}

int total=sum(10);

=swap(x, y);```
```

執行結果

``````D:\ccc101\oc\cc0>gcc cc0psem2.c -o cc0psem2

D:\ccc101\oc\cc0>cc0psem2 test.c0
==== compile file:test.c0 ========
=        x        3
=        y        5
+        t1       x        y
>        t2       t1       6
if0      t2       _L0
=        z        0
_L0
=        z        1
=        i        0
=        s        0
_L1
<        t3       i        100
if0      t3       _L2
+        t4       s        i
=        s        t4
++       i
goto     _L1
_L2
_sum:    function
param    n
=        i        0
_L4
<        t5       i        n
if0      t5       _L5
redirect :          ++       i
dump:         ++       i
+        t6       s        i
=        s        t6
goto     _L4
_L5
ret      s
_swap:   function
param    a
param    b
=        t        a
=        a        b
=        b        t
arg      10
call     sum      t7
=        total    t7
arg      y
call     swap     t8
======= symTable ========
sym[1]=x:int
sym[2]=3:int
sym[3]=y:int
sym[4]=5:int
sym[5]=z:int
sym[6]=t1:int
sym[7]=6:int
sym[8]=t2:int
sym[9]=_L0:\$label
sym[10]=0:int
sym[11]=1:int
sym[12]=i:int
sym[13]=s:int
sym[14]=_L1:\$label
sym[15]=_L2:\$label
sym[16]=100:int
sym[17]=t3:int
sym[18]=t4:int
sym[19]=_L3:\$label
sym[20]=_sum::\$fcall
sym[21]=n:int
sym[22]=_L4:\$label
sym[23]=_L5:\$label
sym[24]=t5:int
sym[25]=t6:int
sym[26]=_L6:\$label
sym[27]=_swap::\$fcall
sym[28]=a:int
sym[29]=b:int
sym[30]=t:int
sym[31]=total:int
sym[32]=sum:\$fcall
sym[33]=10:int
sym[34]=t7:void
sym[35]=swap:\$fcall
sym[36]=t8:void
======= strTable ========
x.3.y.5.z.t1.6.t2._L0.0.1.i.s._L1._L2.100.t3.t4._L3._sum:.n._L4._L5.t5.t6._L6._s
wap:.a.b.t.total.sum.10.t7.swap.t8.

D:\ccc101\oc\cc0>gcc cc0psem2.c -o cc0psem2

D:\ccc101\oc\cc0>cc0psem2 test.c0
==== compile file:test.c0 ========
=        x        3
=        y        5
+        t1       x        y
>        t2       t1       6
if0      t2       _L0
=        z        0
_L0
=        z        1
=        i        0
=        s        0
_L1
<        t3       i        100
if0      t3       _L2
+        t4       s        i
=        s        t4
++       i
goto     _L1
_L2
_sum:    function
param    n
=        i        0
_L4
<        t5       i        n
if0      t5       _L5
redirect :          ++       i
dump:         ++       i
+        t6       s        i
=        s        t6
goto     _L4
_L5
ret      s
_swap:   function
param    a
param    b
=        t        a
=        a        b
=        b        t
arg      10
call     sum      t7
=        total    t7
arg      y
call     swap     t8
======= symTable ========
sym[1]=x:int
sym[2]=3:int
sym[3]=y:int
sym[4]=5:int
sym[5]=z:int
sym[6]=t1:int
sym[7]=6:int
sym[8]=t2:int
sym[9]=_L0:\$label
sym[10]=0:int
sym[11]=1:int
sym[12]=i:int
sym[13]=s:int
sym[14]=_L1:\$label
sym[15]=_L2:\$label
sym[16]=100:int
sym[17]=t3:int
sym[18]=t4:int
sym[19]=_L3:\$label
sym[20]=_sum::\$fcall
sym[21]=n:int
sym[22]=_L4:\$label
sym[23]=_L5:\$label
sym[24]=t5:int
sym[25]=t6:int
sym[26]=_L6:\$label
sym[27]=_swap::\$fcall
sym[28]=a:int
sym[29]=b:int
sym[30]=t:int
sym[31]=total:int
sym[32]=sum:\$fcall
sym[33]=10:int
sym[34]=t7:void
sym[35]=swap:\$fcall
sym[36]=t8:void
======= strTable ========
x.3.y.5.z.t1.6.t2._L0.0.1.i.s._L1._L2.100.t3.t4._L3._sum:.n._L4._L5.t5.t6._L6._s
wap:.a.b.t.total.sum.10.t7.swap.t8.```
```

程式：cc0pcode.c

``````#include <stdio.h>
#include <assert.h>
#include <stdarg.h>

// ================== 基本常數 ===================
#define FALSE   0
#define TRUE    1
#define BOOL    unsigned char
#define NIL        -1

#define LEN 256

#define SPACE " \t\n\r"         // 空白字元
#define ALPHA "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" // 英文字母
#define DIGIT "0123456789"        // 數字字元
#define OPERATOR "+-*/%<=>!&|"        // 運算符號字元集 (用來取得 +,-,*,/, ++, ...)

char *keys[] = {"if", "else", "for", "while", "def", "return", NULL};

typedef enum Type { VOID,   BYTE,   I32,   F32,     STR,    FCALL,    OBJ ,   LABEL} Type; // 語意形態
char *types[]  =  { "void", "byte", "int", "float", "\$str", "\$fcall", "\$obj", "\$label", NULL };

typedef enum Tag { STRING, INTEGER, FLOAT, ID, OP, END } Tag; // 標記 tag 的選項
char *tags[] = {"STRING", "INTEGER", "FLOAT", "ID", "OP", "END" };
typedef enum Kind { KEY, TYPE, FUNC, VAR, NONE } Kind; // 種類 kind 的選項
char *kinds[] = {"KEY", "TYPE", "FUNC", "VAR", "NONE" };
typedef enum Op { NOP, SET, ADD, SUB, MUL, DIV, MOD, GOTO,   FUNCTION,   PARAM,   RET,   CALL,   ARG,   IF1,   IF0  , PLUS, MINUS, LAND, LOR , AND, OR,  XOR, NOT, GT,  LT,  GE,   LE,   EQ,   NE} Op;
char *ops[]   = { "",  "=", "+", "-", "*", "/", "%", "goto", "function", "param", "ret", "call", "arg", "if1", "if0", "++", "--",  "&&", "||", "&", "|", "^", "!", ">", "<", ">=", "<=", "==", "!=", NULL };

#define cmember(ch, set) (strchr(set, ch) != NULL)// 測試字元 ch 是否在 set 當中
#define NEXT(var, tag)   char var[LEN];strcpy(var, token);nextTag(tag)
#define NEXT_TOKEN(var, tokens)  char var[LEN];strcpy(var, token);next(tokens)
#define SYMBOL(var, id)  char var[LEN];strcpy(var, symName(id))
#define OP(var, id)      char var[LEN];strcpy(var, ops[id])
#define ASSERT(cond)     if (!(cond)) { ERROR(); }  // 要求條件要成立，否則就算錯

// 錯誤報告巨集函數，會印出哪一行呼叫了 ERROR()
#define ERROR() printf("ERROR => file:%s, line: %d\n", __FILE__, __LINE__);printStack();exit(1)

FILE *file;
char ch;
int line=1, pos=0;
char token[LEN];
int  tokenIdx = 0;
Tag tag;
Kind kind;
Type type;

typedef struct Obj {
} Obj;

typedef struct Sym {
int strIdx;
Type type;
union {
float f;
int      i;
Obj      *o;
} val;
} Sym;

int symTop = 1;
int strTop = 0;

#define SYM_TABLE_MAX 1000
Sym symTable[SYM_TABLE_MAX];
#define TMP_TABLE_MAX 1000
Sym tmpTable[TMP_TABLE_MAX];
#define STR_TABLE_MAX 10000
char strTable[STR_TABLE_MAX];

int strFind(char *strList[], char *key) {
int i;
for (i=0; strList[i] != NULL; i++) {
if (strcmp(strList[i], key)==0)
return i;
}
return NIL;
}

void debug(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
}

char *symName(int s) {
if (s <=0) return "";
return &strTable[symTable[s].strIdx];
}

Type symType(int s) {
return symTable[s].type;
}

int symFind(char *sym) {
int i;
for (i=1; i<symTop; i++) {
if (strcmp(sym, symName(i))==0)
return i;
}
return NIL;
}

int symPut(char *sym, Type type) {
int s = symFind(sym);
if (s == NIL) {
sprintf(&strTable[strTop], "%s", sym);
s = symTop++;
symTable[s].strIdx = strTop;
symTable[s].type = type;
strTop += strlen(sym) + 1;
}
return s;
}

void symTableDump() {
int i;
printf("======= symTable ========\n");
for (i=1; i<symTop; i++) {
Sym *sym = &symTable[i];
printf("sym[%d]=%s:%s\n", i, symName(i), types[sym->type]);
}
}

void strTableDump() {
int i;
printf("======= strTable ========\n");
for (i=0; i<strTop; i++) {
char c = strTable[i];
if (c == '\0')
printf(".");
else
printf("%c", c);
}
printf("\n");
}

int labelIdx = 0;

int nextLabel() {
char label[LEN];
sprintf(label, "_L%d", labelIdx++);
return symPut(label, LABEL);
}

int tempIdx = 1;

int nextTemp(Type type) {
char tempName[LEN];
sprintf(tempName, "t%d", tempIdx++);
return symPut(tempName, type);
}

char *nameStack[100];
void *objStack[100];
int top = 0;

void printStack() {
int i;
for (i=0; i<top; i++)
printf("/%s", nameStack[i]);
printf("\n");
}

int push(char *name) {
nameStack[top] = name;
top ++;
}

char *pop(char *name) {
top--;
char *nameTop = nameStack[top];
ASSERT(strcmp(nameTop, name)==0);
return nameTop;
}

// 功能：檢查 token 是否為集合字串 set 中的元素
// 範例：strPartOf("int", "byte|int|float") 會傳回 TRUE
BOOL strPartOf(char *token, char *set) {
ASSERT(token != NULL && set != NULL);
ASSERT(strlen(token) < LEN);
char ttoken[LEN+2];
sprintf(ttoken, "|%s|", token);
return (strstr(set, ttoken)!=NULL);
}

BOOL isNext(char *tokens) { // 檢查下一個詞彙是否為 tokens 其中之一
char tTokens[LEN+1];
sprintf(tTokens, "|%s|", tokens);
if (strPartOf(token, tTokens))
return TRUE;
else
return FALSE;
}

BOOL isNextTag(Tag pTag) { // 檢查下一個 tag 是否為 pTag
return (tag == pTag);
}

BOOL isNextKind(Kind pKind) { // 檢查下一個 kind 是否為 pKind
return (kind == pKind);
}

char cnext() {
token[tokenIdx++]=ch;
pos++;
ch=fgetc(file);
return ch;
}

void tnext() {
while (cmember(ch, SPACE)) { // 忽略空白
tokenIdx = 0;
if (ch=='\n') {
line++;
pos = 1;
}
cnext();
}
if (feof(file)) {
strcpy(token, "\$END\$");
tag = END;
return;
}
tokenIdx = 0;
if (ch == '\"') { // 如果是 " 代表字串開頭
// 字串常數 : string = ".."
cnext(); // 跳過 "
while (ch != '\"') cnext(); // 一直讀到下一個 " 符號為止。
cnext(); // 跳過 "
tag=STRING;
} else if (cmember(ch, OPERATOR)) { // 如果是OP(+-*/<=>!等符號)
// 運算符號 : OP = ++, --, <=, >=, ...
while (cmember(ch, OPERATOR)) cnext(); // 一直讀到不是OP為止
token[tokenIdx] = '\0';
tag=OP;
} else if (cmember(ch, DIGIT)) { // 如果是數字
// 數字常數 : INTEGER = 312, 77568, ...
while (cmember(ch, DIGIT)) cnext(); // 一直讀到不是數字為止
tag=INTEGER;
// 實數 : real = 3.14, ...
if (ch == '.') {
cnext(); // 取得小數點
tag = FLOAT;
}
while (cmember(ch, DIGIT)) cnext(); // 取得小數部分
} else if (cmember(ch, ALPHA)) { // 如果是英文字母
// 基本詞彙 : token = int, sum, i, for, if, x1y2z, ....
while (cmember(ch, ALPHA) || cmember(ch, DIGIT))
cnext(); // 一直讀到不是英文字母 (或數字)為止
token[tokenIdx] = '\0';
tag=ID;
} else { // 其他符號，都解讀為單一字元
tag = OP;
cnext(); // 傳回單一字元
}
token[tokenIdx] = '\0';
if (strFind(keys, token)!=NIL)
kind = KEY;
else if (strFind(types, token)!=NIL)
kind = TYPE;
else if (tag == ID)
kind = VAR;
else
kind = NONE;
//    printf("token=%s tag=%s kind=%s\n", token, tags[tag], kinds[kind]);
}

void next(char *tokens) { // 檢查下一個詞彙的型態
if (isNext(tokens)) { // 如果是pTags型態之一
tnext();
} else { // 否則，印出錯誤訊息
debug("next():line=%d pos=%d token=%s expect(%s)\n",
line, pos, token, tokens);
ERROR();
}
}

void nextTag(Tag eTag) { // 檢查下一個 tag 的型態
if (isNextTag(eTag)) {
tnext();
} else {
debug("nextTag():line=%d pos=%d token=%s tag=%s expect(tag=%s)\n",
line, pos, token, tags[tag], tags[eTag]);
ERROR();
}
}

void nextKind(Kind eKind) { // 檢查下一個 tag 的型態
if (isNextKind(eKind)) {
tnext();
} else {
debug("nextKind():line=%d pos=%d token=%s kind=%s expect(kind=%s)\n",
line, pos, token, kinds[kind], kinds[eKind]);
ERROR();
}
}

typedef struct PCode {
int lab, op, s, s1, s2;
} PCode;

#define MAX_PCODE 10000
PCode pcodeList[MAX_PCODE];

#define MAX_PCODE_TEMP 1000
PCode pcodeTempList[MAX_PCODE_TEMP];

int pcodeTop = 0, pcodeTempTop = 0;

PCode *pcodeListNow = pcodeList;

void pcodePrint(PCode *pcode) {
SYMBOL(label, pcode->lab); SYMBOL(p, pcode->s); SYMBOL(p1, pcode->s1); SYMBOL(p2, pcode->s2);
OP(opName, pcode->op);
//    printf("%-8d %-8d %-8d %-8d %-8d\n", pcode->lab, pcode->op, pcode->s, pcode->s1, pcode->s2);
printf("%-8s %-8s %-8s %-8s %-8s\n", label, opName, p, p1, p2);
}

void pcode(int lab, int op, int s, int s1, int s2) {
PCode *pcode = NULL;

if (pcodeListNow == pcodeTempList)
pcode = &pcodeTempList[pcodeTempTop++];
else
pcode = &pcodeList[pcodeTop++];

pcode->lab = lab;
pcode->op  = op;
pcode->s   = s;
pcode->s1  = s1;
pcode->s2  = s2;

if (pcodeListNow == pcodeTempList) {
printf("redirect : ");
pcodePrint(pcode);
} else
pcodePrint(pcode);
}

void pcodeDump(PCode *list, int top) {
int i;
for (i=0; i<top; i++) {
printf("dump:");
pcodePrint(&list[i]);
}
}

void pcodeRedirect() {
pcodeListNow = pcodeTempList;
pcodeTempTop = 0;
}

void pcodeRedirectEnd() {
memcpy(&pcodeList[pcodeTop], &pcodeTempList[0], sizeof(PCode)*pcodeTempTop);
pcodeTop += pcodeTempTop;
pcodeDump(pcodeTempList, pcodeTempTop);
pcodeListNow = pcodeList;
}

int pcodeRun() {
int pc=0;
}

int pcodeExec(PCode *pcode) {
int op = pcode->op;
switch (op) {
case NOP: break;
case SET: break;
case SUB: break;
case MUL: break;
case DIV: break;
case MOD: break;
case GOTO: break;
case FUNCTION: break;
case PARAM: break;
case RET: break;
case CALL: break;
case ARG: break;
case IF1: break;
case IF0: break;
case PLUS: break;
case MINUS: break;
case LAND: break;
case LOR: break;
case AND: break;
case OR: break;
case XOR: break;
case NOT: break;
case GT: break;
case LT: break;
case GE: break;
case LE: break;
case EQ: break;
case NE: break;
}
}

#define MAX_ARGS 100
int argList[MAX_ARGS];
int argTop = 0;

int argPush(int a) { argList[argTop++] = a; }
int argPop() { return argList[--argTop]; }

// EBNF : ARGS = E? {,E}*
// BNF  : ARGS = {} | E {, ARGS}?
// 用在 ID(ARGS) 中，follow 為 )
int ARGS() { // BNF
push("ARGS");
argTop = 0;
if (!isNext(")")) {
argPush(E());
if (isNext(",")) {
next(",");
ARGS();
}
}
pop("ARGS");
}

// F=STRING | INTEGER | FLOAT | '(' E ')' | ID ('('ARGS')')?
int F() {
int f;
push("F");
if (isNext("(")) {
next("(");
f = E();
next(")");
} else if (isNextTag(INTEGER)) {
NEXT(iStr, INTEGER);
f = symPut(iStr, I32);
} else if (isNextTag(FLOAT)) {
NEXT(fStr, FLOAT);
f = symPut(fStr, F32);
} else if (isNextTag(STRING)) {
NEXT(str, STRING);
f=symPut(str, STR);
} else { // if (isNextTag(ID))
NEXT(id, ID);
f=symPut(id, FCALL);
if (isNext("(")) { // function call
next("(");
ARGS();
next(")");
int i;
for (i=0; i<argTop; i++) {
pcode(0, ARG, argList[i], 0, 0);
}
int t = nextTemp(VOID); // 需修改
pcode(0, CALL, f, t, 0);
f = t;
}
}
pop("F");
return f;
}

#define E_OP "+|-|*|/|%|&|^|||&&||||>>|<<|==|<=|>=|<|>"
// E=F (E_OP F)?
int E() {
push("E");
int f1 = F();
if (isNext(E_OP)) {
NEXT_TOKEN(op, E_OP);
int f2 = F();
int e = nextTemp(symType(f1));
int iop = strFind(ops, op);
pcode(0, iop, e, f1, f2);
f1 = e;
}
pop("E");
return f1;
}

// ASSIGN = (ID[++|--]?)?(=E)?
int ASSIGN() {
push("ASSIGN");
int var = NIL;
if (isNextTag(ID)) {
NEXT(id, ID);
var = symPut(id, type);
if (isNext("++|--")) {
NEXT_TOKEN(op1, "++|--");
ASSERT(var != NIL);
int iop1 = strFind(ops, op1);
pcode(0, iop1, var, 0, 0);
}
}
if (isNext("=")) {
next("=");
int e = E();
if (var != NIL)
pcode(0, SET, var, e, 0);
}
pop("ASSIGN");
}

// EBNF : DECLS = TYPE? ASSIGN {, ASSIGN}*
// BNF  : DECLS = TYPE? ASSIGN_LIST

int DECLS() {
push("DECLS");
if (isNextKind(TYPE)) {
type = strFind(types, token);
ASSERT(type != NIL);
nextKind(TYPE);
}
ASSIGN_LIST();
pop("DECLS");
}

// BNF  : ASSIGN_LIST = {} | ASSIGN {, ASSIGN_LIST}?
int ASSIGN_LIST() {
push("ASSIGN_LIST");
if (!isNext(";")) {
ASSIGN();
if (isNext(",")) {
next(",");
ASSIGN_LIST();
}
}
pop("ASSIGN_LIST");
}

// STMT=return E | DECLS
int STMT() {
push("STMT");
if (isNext("return")) {
next("return");
int e = E();
pcode(0, RET, e, 0, 0);
} else {
DECLS();
}
pop("STMT");
}

// BASE=STMT;|IF|WHILE|FOR|BLOCK|DEF
int BASE() {
push("BASE");
if (isNext("{"))
BLOCK();
else if (isNext("if"))
IF();
else if (isNext("while"))
WHILE();
else if (isNext("for"))
FOR();
else if (isNext("def"))
DEF();
else {
STMT();
next(";");
}
pop("BASE");
}

// EBNF : BASE_LIST = BASE*
// BNF : BASE_LIST = {} | BASE BASE_LIST?
int BASE_LIST() {
push("BASE_LIST");
if (!isNext("}|\$END\$")) {
BASE();
BASE_LIST();
}
pop("BASE_LIST");
}

// EBNF : BLOCK={ BASE* }
// BNF : BLOCK={ BASE_LIST }
int BLOCK() {
push("BLOCK");
next("{");
BASE_LIST();
next("}");
pop("BLOCK");
}

// IF=if (E) BASE else BASE
int IF() {
push("IF");
next("if");
next("(");
int e = E();
next(")");
int elseLabel = nextLabel();
pcode(0, IF0, e, elseLabel, 0);
BASE();
if (isNext("else")) {
next("else");
pcode(elseLabel, NOP, 0, 0, 0);
BASE();
}
pop("IF");
}

// WHILE=while (E) BASE
int WHILE() {
push("WHILE");
int startLabel = nextLabel();
int exitLabel = nextLabel();
pcode(startLabel, NOP, 0, 0, 0);
next("while");
next("(");
int e = E();
next(")");
pcode(0, IF0, e, exitLabel, 0);
BASE();
pcode(0, GOTO, startLabel, 0, 0);
pcode(exitLabel, NOP, 0, 0, 0);
pop("WHILE");
}

// FOR=for (STMT;E;STMT) BASE
int FOR() {
push("FOR");
int startLabel = nextLabel();
int exitLabel = nextLabel();
next("for");
next("(");
STMT();
next(";");
pcode(startLabel, NOP, 0, 0, 0);
int e = E();
pcode(0, IF0, e, exitLabel, 0);
next(";");
pcodeRedirect();
STMT(); // ? 這個不能邊比對邊編譯，怎麼辦？用 pipe 先轉向某 setPCode，然後在將結果補在下面。
next(")");
pcodeRedirectEnd();
BASE();
pcode(0, GOTO, startLabel, 0, 0);
pcode(exitLabel, NOP, 0, 0, 0);
pop("FOR");
}

// EBNF : PARAMS = ID? {, ID}*
// BNF  : PARAMS = {} | TYPE ID {, PARAMS}?
int PARAMS() {
push("PARAMS");
if (isNextKind(TYPE)) {
type = strFind(types, token);
ASSERT(type != NIL);
nextKind(TYPE);
NEXT(p1, ID);
pcode(0, PARAM, symPut(p1, type), 0, 0);
if (isNext(",")) {
next(",");
PARAMS();
}
}
pop("PARAMS");
}

// DEF=def ID(PARAMS) BLOCK
int DEF() {
push("DEF");
int exitLabel = nextLabel();
next("def");
NEXT(id, ID);
char fname[LEN];
sprintf(fname, "_%s:", id);
int f = symPut(fname, FCALL);
pcode(f, FUNCTION, 0, 0, 0);
next("(");
PARAMS();
next(")");
BLOCK();
pop("DEF");
}

// PROG=BASE*
int PROG() {
push("PROG");
BASE_LIST();
pop("PROG");
}

int init() {
fseek(file, 0, SEEK_SET);
tokenIdx = 0;
tnext();
}

int scan() {
init();
while (TRUE) {
tnext();
if (tag == END)
break;
printf("token=%-8s tag=%-8s kind=%d,%-8s\n", token, tags[tag], kind, kinds[kind]);
}
}

int compile(char *fname) {
printf("==== compile file:%s ========\n", fname);
file = fopen(fname, "r");
//  init(); scan();
init();
PROG();
symTableDump();
strTableDump();
fclose(file);
}

int main(int argc, char * argv[]) {
char *fname = argv[1];
compile(fname);
}```
```