1.字句解析
字句解析のプロセスは、ソースコードは、スキャナと呼ばれるものに入力され、スキャナジョブは、字句解析することです。彼と呼ばれる適用有限状態機械のような、例えば、トークンにソースコードのアルゴリズムをarray[index] = (index + 4) * (2 + 3)
スキャンし、コードの行マークは、以下のようになります。
マーク | タイプ |
---|---|
アレイ | 識別子 |
[ | 左角括弧 |
指数 | 識別子 |
] | 右ブラケット |
= | 割り当て |
( | 左括弧 |
指数 | 識別子 |
+ | プラス |
4 | デジタル |
) | 左括弧 |
* | 乗算記号 |
( | 左括弧 |
2 | デジタル |
+ | プラス |
3 | デジタル |
) | 右括弧 |
:これらのより一般的な記号は、次のカテゴリ持っているキーワード、識別子、リテラル(数値、文字列、など)や特殊記号を。
単語を入力 | 他の種 | 種はコードしません |
---|---|---|
キーワード | ため、それ以外の、もし...... | 用語1ヤード |
識別子 | 変数名、配列名...... | マルチワード1ヤード |
定数 | 整数、浮動小数点、文字...... | タイプ1ヤード |
演算子 | 算術演算(+ - * /%)、関係(> <=)、ロジック(&|〜) | 用語1ヤード |
デリミタ | ; ()[] {} | 用語1ヤード |
これらのマーカーの同定が、スキャナはまた、識別子は、数、文字列定数は、後続の工程のために、テーブルに、シンボルテーブルに格納されています。C言語のための前処理、コンパイラにマクロ置換を含む、彼とファイルは仕事をしませんが、別のプリプロセッサの範囲に。
2.解析
解析しパーサー解析するために、スキャナによって生成されたマークを走査するために、それは構文木を生成し、プロセスが使用する文脈自由文法、解析手段を式ツリーの構文解析ツリーノードがツリーで生成します次のように
枝の数残っているarray[index]
と右の枝がされている(index + 4) * (2 + 3)
左右の枝、彼らは構文木を形成し、再び開くことができる
構文木によって、私たちは意味と優先順位演算記号の多くを見ることができるにもダウン同定されています。シンボルが複数の意味を持っているために同じように、*
あなたが乗算を行うことができ、区別するためにその意味を決定するために行く、舞台を解析し、ポインタとして使用することができ、法的な表現がなかった、構文エラーがスローされます。
3.意味解析
意味解析セマンティックアナライザ完全なパーサには無意味ですが、確かに、構文レベルでは、彼は2を乗じたC言語のポインタで実装コードの世話をしないという意味、唯一の右と間違った文法を完了しました法的。セマンティックコンパイラが分析することができます静的意味逆に、コンパイルの意味で決定することができ、動的なセマンティクスが意味を決定する前に、実行時にあります。
文のタイプと一致の種類、変換などの静的意味。例えば、浮動小数点数は、整数、隠されたプロセスに割り当てられている場合、浮動小数点から整数変換プロセスです。しかし、ポインタが浮動小数点数に割り当てられている場合、構文レベルではそれができますが、意味的なステージは、あなたは、型の不一致エラーが発生するでしょう。
:次のように意味分析した後、文法的表現の全体的な数は、タイプがマークされている
すべての種類の基本的な式は、整数、型変換する必要はありませんされ、変換を行うには、いくつかの必要性が構文木変換に挿入されますノード
4.z中間言語生成
目前的编译器都会有很多优化,在源代码中就会有一些优化过程,比如以上的(2+6)
就会在编译的时候进行优化,优化后就直接变成了一个数字5
其实直接在语法树上边做优化比较困难,所以源代码优化器往往把整个语法树转换成中间代码,跟目标机器和运行环境无关,他不包含数据的尺寸、变量地址和寄存器的名字。常见的中间代码有三地址码,P-代码等。比如x = y op z
,该三地址码表示将变量y和z进行op操作后赋值给x,比如x = y + z;一下是常用的三地址表示方式
指令类型 | 指令形式 |
---|---|
赋值操作 | x = y op z 、 x = op y |
复制指令 | x = y |
条件跳转 | if x op y goto z |
非条件跳转 | goto z |
参数传递 | param z |
过程调用 | call p, n |
过程返回 | return x |
数组引用 | x = y[ i ] |
数组赋值 | y[ i ] = x |
地址以及指针操作 | x = &y 、x = *y 、*x = y |
我们把上述的例子的语法树翻译成三地址码如下
t1 = 2 + 3
t2 = index + 4
t3 = t1 * t2
array[index] = t3
在三地址码基础上进行优化,会把2+3的结果计算出来,得到t1 = 5
然后把t1换成5。这样三地址码就变成了如下
t2 = index + 4
t2 = t2 * 8
array[index] = t2
中间代码把编译器分成了前端和后端(此前后端非彼前后端),前端负责生成与机器无挂的中间代码,后端则是将中间代码变成目标代码。这样对于一些跨平台的编译器而言,可以针对不同平台使用同一个前端,然后对应不同机器开发不同后端。
参考资料《编译原理》、《程序员的自我修养(链接、装载与库)》