If 編譯器

編譯器設計

編譯器簡介

高階語言

語法理論

剖析器

語意理論

符號表

直譯器

型態系統

中間碼

目標語言

最佳化

錯誤處理

進階議題

原始碼下載

程式實作

C 語言

案例研究

JavaScript

V8

Lua

Oberon

NeoPascal

pcc

tcc

gcc

C--

Lex

YACC

AntLR

LLVM

CLang

訊息

相關網站

參考文獻

最新修改

簡體版

English

輸入檔案:ifc.c0

str = "Hello!";
x = 3;
y=5;
if ((x+y)>6)
  z = 0;
else
  z = 1;

編譯執行結果

D:\oc\compiler>gcc ifc.c -o ifc

D:\oc\compiler>ifc ifc.c0
==== compile file:ifc.c0 ========
pcode:= str "Hello!"
pcode:= t1 3
pcode:= x t1
pcode:= t2 5
pcode:= y t2
pcode:+ t3 x y
pcode:= t4 6
pcode:> t5 t3 t4
pcode:= t6 0
pcode:= z t6
pcode:= t7 1
pcode:= z t7
======= symTable ========
sym[1]="Hello!"
sym[2]=str
sym[3]=3
sym[4]=x
sym[5]=5
sym[6]=y
sym[7]=6
sym[8]=0
sym[9]=z
sym[10]=1
======= strTable ========
"Hello!".str.3.x.5.y.6.0.z.1.

程式:ifc.c

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

// ================== 基本常數 ===================
#define FALSE   0
#define TRUE    1
#define BYTE    unsigned char
#define BOOL    unsigned char
#define INT32   long
#define INT16   short
#define INT8    char
#define UINT32  unsigned long
#define UINT16  unsigned short
#define UINT8   unsigned char
#define NIL        -1

#define LEN 256

#define SYM_TABLE_MAX 1000
#define STR_TABLE_MAX 10000

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

char *keywords[] = {"if", "else", "for", "while", "int", "char", "float", NULL};

#define STRING "STRING"
#define NUMBER "NUMBER"
#define FLOAT  "FLOAT"
#define ID     "ID"
#define END    "$END$"

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

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

FILE *file;
char ch;
int line=1, pos=0;
char token[LEN], tag[LEN];
int  tokenIdx = 0;

typedef struct Sym {
    int strIdx;
} Sym;

int symTop = 1;
Sym symTable[SYM_TABLE_MAX];

char strTable[STR_TABLE_MAX];
int  strTop = 0;

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 symTemp[LEN];

char *symbol(int s) {
    if (s == 0)
        return "";
    else if (s > 0)
        return &strTable[symTable[s].strIdx];
    else { // s < 0; temp variable
        sprintf(symTemp, "t%d", -1*s);
        return symTemp;
    }
}

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

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

void symTableDump() {
    int i;
    printf("======= symTable ========\n");
    for (i=1; i<symTop; i++) {
        printf("sym[%d]=%s\n", i, symbol(i));
    }
}

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 tempIdx = -1;

int nextTemp() {
    return tempIdx--;
}

char stack[100];
int top = 0;

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

int push(char c) {
    stack[top++] = c;
//    printStack();
}

char pop(char c) {
    char ctop = stack[--top];
//    printStack();
    ASSERT(ctop==c);
    return ctop;
}

// 功能:檢查 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 *tags) { // 檢查下一個詞彙的型態
    char tTags[LEN+1];
    sprintf(tTags, "|%s|", tags);
    if (strPartOf(tag, tTags))
        return TRUE;
    else
        return FALSE;
}

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);
        strcpy(tag, END);
        return;
    }
    tokenIdx = 0;
    if (ch == '\"') { // 如果是 " 代表字串開頭
        // 字串常數 : string = ".."
        cnext(); // 跳過 "
        while (ch != '\"') cnext(); // 一直讀到下一個 " 符號為止。
        cnext(); // 跳過 "
        strcpy(tag, STRING);
    } else if (cmember(ch, OP)) { // 如果是OP(+-*/<=>!等符號)
          // 運算符號 : OP = ++, --, <=, >=, ...
        while (cmember(ch, OP)) cnext(); // 一直讀到不是OP為止
        token[tokenIdx] = '\0';
        strcpy(tag, token);
    } else if (cmember(ch, DIGIT)) { // 如果是數字
           // 數字常數 : number = 312, 77568, ...
        while (cmember(ch, DIGIT)) cnext(); // 一直讀到不是數字為止
        strcpy(tag, NUMBER);
        // 浮點常數 : float = 3.14, ...
        if (ch == '.') {
            cnext(); // 取得小數點
            strcpy(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';
        if (strFind(keywords, token)==NIL)
            strcpy(tag, ID);
        else
            strcpy(tag, token);
    } else { // 其他符號,都解讀為單一字元
        sprintf(tag, "%c", ch);
        cnext(); // 傳回單一字元
    }
    token[tokenIdx] = '\0';
//    printf("token=%s tag=%s\n", token, tag);
}

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

void pcode(char *op, int s, int s1, int s2) {
    SYMBOL(p, s); SYMBOL(p1, s1); SYMBOL(p2, s2);
    printf("pcode:%s %s %s %s\n", op, p, p1, p2);
}

// F=STRING|NUMBER|ID|'(' E ')'
int F() {
    int f;
    push('F');
    if (isNext("(")) {
        next("(");
        f = E();
        next(")");
    } else if (isNext(NUMBER)) {
        NEXT(number, NUMBER);
        int n = symPut(number);
        f = nextTemp();
        pcode("=", f, n, 0);
    } else if (isNext(STRING)) {
        NEXT(str, STRING);
        f=symPut(str);
    } else if (isNext(ID)) {
        NEXT(id, ID);
        f=symPut(id);
    }
    pop('F');
    return f; 
}

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

// ASSIGN=ID=E;
int ASSIGN() {
    push('A');
    NEXT(id, ID);
    next("=");
    int e = E();
    next(";");
    pcode("=", symPut(id), e, 0);
    pop('A');
}

// BLOCK={ BASE* }
int BLOCK() {
    push('K');
    next("{");
    while (!isNext("}")) {
        BASE();
    }
    next("}");
    pop('K');
}

// BASE=ASSIGN|IF|WHILE|FOR|BLOCK
int BASE() {
    push('B');
    if (isNext("{"))
        BLOCK();
    else if (isNext("if"))
        IF();
    else
        ASSIGN();
    pop('B');
}

// IF=if (E) BASE else BASE
int IF() {
    push('I');
    next("if");
    next("(");
    E();
    next(")");
    BASE();
    if (isNext("else")) {
        next("else");
        BASE();
    }
    pop('I');
}

// PROG=BASE*
int PROG() {
    push('P');
    while (!isNext(END)) {
        BASE();
    }
    pop('P');
}

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

int scan() {
    init();
    while (TRUE) {
        tnext();
        if (strcmp(token, END)==0)
            break;
        printf("%s\n", token);
    }
}

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

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

Facebook

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License