<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                # 手把手教你做一個 C 語言編譯器(1):設計 本章是“手把手教你構建 C 語言編譯器”系列的第二篇,我們要從整體上講解如何設計我們的 C 語言編譯器。 **本系列:** 1. [手把手教你做一個 C 語言編譯器(0):前言](http://blog.jobbole.com/97332/) 首先要說明的是,雖然標題是編譯器,但實際上我們構建的是 C 語言的解釋器,這意味著我們可以像運行腳本一樣去運行 C 語言的源代碼文件。這么做的理由有兩點: 1. 解釋器與編譯器僅在代碼生成階段有區別,而其它方面如詞法分析、語法分析是一樣的。 2. 解釋器需要我們實現自己的虛擬機與指令集,而這部分能幫助我們了解計算機的工作原理。 ## 編譯器的構建流程 一般而言,編譯器的編寫分為 3 個步驟: 1. 詞法分析器,用于將字符串轉化成內部的表示結構。 2. 語法分析器,將詞法分析得到的標記流(token)生成一棵語法樹。 3. 目標代碼的生成,將語法樹轉化成目標代碼。 已經有許多工具能幫助我們處理階段1和2,如 flex 用于詞法分析,bison 用于語法分析。只是它們的功能都過于強大,屏蔽了許多實現上的細節,對于學習構建編譯器幫助不大。所以我們要完全手寫這些功能。 所以我們會根據下面的流程: 1. 構建我們自己的虛擬機以及指令集。這后生成的目標代碼便是我們的指令集。 2. 構建我們的詞法分析器 3. 構建語法分析器 ## 編譯器的框架 我們的編譯器主要包括 4 個函數: 1. `next()` 用于詞法分析,獲取下一個標記,它將自動忽略空白字符。 2. `program()` 語法分析的入口,分析整個 C 語言程序。 3. `expression(level)` 用于解析一個表達式。 4. `eval()` 虛擬機的入口,用于解釋目標代碼。 這里有一個單獨用于解析“表達式”的函數 `expression` 是因為表達式在語法分析中相對獨立并且比較復雜,所以我們將它單獨作為一個模塊(函數)。 因為我們的源代碼看起來就像是: ``` #include <stdio.h> #include <stdlib.h> #include <memory.h> #include <string.h> int token; // current token char *src, *old_src; // pointer to source code string; int poolsize; // default size of text/data/stack int line; // line number void next() { token = *src++; return; } void expression(int level) { // do nothing } void program() { next(); // get next token while (token > 0) { printf("token is: %c\n", token); next(); } } int eval() { // do nothing yet return 0; } int main(int argc, char **argv) { int i, fd; argc--; argv++; poolsize = 256 * 1024; // arbitrary size line = 1; if ((fd = open(*argv, 0)) < 0) { printf("could not open(%s)\n", *argv); return -1; } if (!(src = old_src = malloc(poolsize))) { printf("could not malloc(%d) for source area\n", poolsize); return -1; } // read the source file if ((i = read(fd, src, poolsize-1)) <= 0) { printf("read() returned %d\n", i); return -1; } src[i] = 0; // add EOF character close(fd); program(); return eval(); } ``` 上面的代碼看上去挺復雜,但其實內容不多,就是讀取一個源代碼文件,逐個讀取每個字符,并輸出每個字符。這里重要的是注意每個函數的作用,后面的文章中,我們將逐個填充每個函數的功能,最終構建起我們的編譯器。 本節的代碼可以在 [Github](https://github.com/lotabout/write-a-C-interpreter/tree/step-0) 上下載,也可以直接 clone ``` git clone -b step-0 https://github.com/lotabout/write-a-C-interpreter ``` 這樣我們就有了一個最簡單的編譯器:什么都不干的編譯器,下一章中,我們將實現其中的`eval`函數,即我們自己的虛擬機。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看