圖靈機(jī)談學(xué)習(xí)編程

一個通用編程語言要做的最基本的就是圖靈完備,我們常用的語言的通用語言都是圖靈完備。那么為什么圖靈完備(Turing Complete)這么重要呢?

維基百科
可計算性理論,如果一系列操作數(shù)據(jù)的規(guī)則(如指令集編程語言、細(xì)胞自動機(jī))可以用來模擬任何圖靈機(jī),那么它是圖靈完備的。

那么問題來了,啥又是圖靈機(jī)呢。繼續(xù)維基百科

通俗而簡單的說法就是:一個處理器能不斷的處理輸入數(shù)據(jù),并輸出數(shù)據(jù),這個處理器維護(hù)一個有限狀態(tài)集,狀態(tài)集+數(shù)據(jù)對應(yīng)的結(jié)果是固定。

那么圖靈完備的通俗說法就是:能控制圖靈機(jī)完成所有功能的編程語言。

我們大名鼎鼎的編程語言C語言,當(dāng)然是圖靈完備的。但是我們今天要介紹一款神奇的編程語言,簡潔,關(guān)鍵字少,容易上手,關(guān)鍵是圖靈完備。要說缺點么,就是要實現(xiàn)功能,過于繁瑣了。

Brainfuck
它的默認(rèn)有狀態(tài)集:
一個以字節(jié)為單位、被初始化為零的數(shù)組、一個指向該數(shù)組的指針(初始時指向數(shù)組的第一個字節(jié))、以及用于輸入輸出的兩個字節(jié)流。

能執(zhí)行的操作:

字符 含義
> 指針加一
< 指針減一
+ 指針指向的字節(jié)的值加一
- 指針指向的字節(jié)的值減一
. 輸出指針指向的單元內(nèi)容(ASCII碼
, 輸入內(nèi)容到指針指向的單元(ASCII碼)
[ 如果指針指向的單元值為零,向后跳轉(zhuǎn)到對應(yīng)的]指令的次一指令處
] 如果指針指向的單元值不為零,向前跳轉(zhuǎn)到對應(yīng)的[指令的次一指令處

打印 hello world! (摘抄自wikipedia)

++++++++++[>+++++++>++++++++++>+++>+<<<<-]
>++.>+.+++++++..+++.>++.<<+++++++++++++++.
>.+++.------.--------.>+.>.

代碼很簡潔,但不是很那讀懂,非常燒腦。但是讀代碼可以倒過來看,不是要打印Hello World!嗎?打印字符用的是.,那么肯定要執(zhí)行至少12個.,實際上還有一個不可見字符換行符\n,總共執(zhí)行13個.。我們往代碼里面數(shù),發(fā)現(xiàn)正好13個。那就可以倒推出來,第一個.打印的是H。依次類推,我們就能知道所有點對應(yīng)的字符是啥了。

下面給出從打印開始的,狀態(tài)集的狀態(tài):

'.', arr: [00 48 64 1e 0a], ptr: 1 # print arr[1] 'H'
'>', arr: [00 48 64 1e 0a], ptr: 2
'+', arr: [00 48 65 1e 0a], ptr: 2
...
'.', arr: [00 57 64 21 0a], ptr: 4 # print arr[4] '\n'

c語言實現(xiàn)的解析器(簡單):

typedef struct {
    char arr[1024];
    char ptr;
    void (*putc)(char* p);
    void (*getc)(char* p);
} BrainfuckStateSet;

void Brainfuck_putc(char* p) {
    putc(*p, stdout);
}

void Brainfuck_getc(char* p) {
    *p = (char)getc(stdin);
}

void Brainfuck_parser(BrainfuckStateSet* state, const char* code) {
    int codeIdx = 0;
    while (code[codeIdx]) {
        //printf("arr: [%02x %02x %02x %02x %02x %02x], ptr: %02x  ---- code: %4d: %c\n", state->arr[0], state->arr[1], state->arr[2], state->arr[3], state->arr[4], state->arr[5], state->ptr, codeIdx, code[codeIdx]);
        switch (code[codeIdx]) {
        case '>':
            state->ptr++;
            break;
        case '<':
            state->ptr--;
            break;
        case '+':
            state->arr[state->ptr]++;
            break;
        case '-':
            state->arr[state->ptr]--;
            break;
        case '.':
            state->putc(&state->arr[state->ptr]);
            break;
        case ',':
            state->getc(&state->arr[state->ptr]);
            break;
        case '[':
            if (!state->arr[state->ptr]) {
                while (code[codeIdx] != ']') codeIdx++;
            }
            break;
        case ']':
            if (state->arr[state->ptr]) {
                while (code[codeIdx] != '[') codeIdx--;
            }
            break;
        default:
            // nothing todo, ignore
            break;
        }
        codeIdx++;
    }
}

// print hello world use brainfuck
// simulate brainfuck
void Brainfuck_PrintHelloWorld() {
    // prepare state set
    BrainfuckStateSet state = {
        {0}, 0, Brainfuck_putc, Brainfuck_getc
    };
    memset(&state.arr, 0, 1024);


    // parser
    const char* code = "++++++++++[>+++++++>++++++++++>+++>+<<<<-]"
        ">++.>+.+++++++..+++.>++.<<+++++++++++++++."
        ">.+++.------.--------.>+.>.";
    Brainfuck_parser(&state, code);
}

其實編程語言的三要素:順序執(zhí)行,條件判斷,循環(huán)(條件判斷+跳轉(zhuǎn)),其它都是輔助功能。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容