欢迎光临散文网 会员登陆 & 注册

C编译器实践 (1) 引例

2023-03-15 10:15 作者:GC_CH  | 我要投稿


前言

    要想自动优化C代码, 还得首先分析C代码. 所以, 学习怎么写一个C编译器很有必要.

    当然, 也可以使用开源的C编译器代码. 但是, 看懂别人的代码都够写2个C编译器了!

    最后, 写一个编译器并不是那么难的事, 接下来看一个例子.

    项目地址 : https://gitee.com/chenguc/c-compiler-

文法

    文法就是描述文本排列的规则, 也就是什么字(word)可以跟在什么字之后, 什么词(token)和什么词构成一个句子, 所有的句子构成了一门语言(language).

     以下是一个加减乘除表达式的文法, 表达式用E(expression)表示, 项用T(term)表示, 因子用F(factor)表示, + 就是加号, * 就是乘号, num就是一个数字, () 就是括号. 什么是项呢? 大家或许听过 常数项, 多项式等, 项就是这个意思(只可意会不可言传). 因子又是什么呢? 就是最基础的东西, 数字当然是表达式最基础的东西了, () 的优先级非常高, 所以把()看成一个整体, 也认为是因子:

E -> T + T | T

T -> F * F | F

F ->  ( | num

    其中, 蓝色的是非终结符(nonterminal),  黑色的是终结符(terminal), 橙色的是特殊符号, 用来描述文法的, 不属于语言中的符号. 比如, -> 表示左边由右边构成,  | 表示或者.

    E -> T + T | T 这句的意思就是, 表达式由 项 + 项 或者 构成.

举例

    (3 + 5) * 4 就是上述文法的一个句子, 因为这一串文本是能够被上述文法匹配的.

    其中, 3, 4, 5都是终结符 num, +* 也是终结符, (, ) 也是终结符. 可以看到的都是终结符, 而非终结符是由终结符或非终结符构成的, 所以不能直接看到.

    num表示数字, 3, 4, 5 都是数字, 所以3, 4, 5都是num, 这应该很好理解. +, * 表示加号和乘号,(, ) 表示括号, 也应该很好理解(理解不了的大概可能或许需要看一下小学数学课本). 

    以下用右边的替换左边的来证明 (3 + 5) * 4 是符合上述文法的.

(1) E -> T, 应用 E -> T + T | T 的右边那个(或者就是哪个都行);

(2) E -> F * F, 应用 T -> F * F 得到;

(3) E -> F * num, 应用  F -> num 得到;

(4) E -> ( E ) * num, 应用 F -> ( E )得到;

(5) E -> (T + T) * num, 应用 E -> T + T 得到;

(6) E -> (num + num) * num, 应用 E -> T, T -> F, F -> num 连续多次替换得到.

所以 (3 + 5) * 4 就是 (num + num) * num, 就是一个完整的表达式.

编码

    文法转代码是非常简单的, 非终结符就对应一个函数, 终结符就对应一个单词(单词由多个字符组成). 于是可以得到如下代码:

#include <iostream>

using namespace std;


bool E(const char*& p);


bool F(const char*& p)

{

// F -> ( E )

if (*p == '(')

{

E(++p);

return *p == ')';

}

// F -> num

if (isdigit(*p))

{

++p;

return true;

}

return false;

}


bool T(const char*& p)

{

if (F(p) == false)

return false;

if (*p == '*')

{

if (F(++p) == false)

return false;

}

return true;

}


bool E(const char*& p)

{

if (T(p) == false)

return false;

if (*p == '+')

{

if (T(++p) == false)

return false;

}

return true;

}


int main()

{

const char *text = "(3+5)*4";

const char *p = text;

if (E(p))

cout << text << " 是表达式" << endl;

else

cout << text << " 不是表达式" << endl;


system("pause");

}

匹配过程

    以下是匹配过程的一个图示:

        

    

    

    

C编译器实践 (1) 引例的评论 (共 条)

分享到微博请遵守国家法律