用lex和yacc写成的一个具有解析类C语言的编译器,能够进行正确的词法、语法、语义分析并生成语法树进行可视化以及中间码。

Chapter 1 : 编译器简介

1.1 编译器简介

用lex和yacc写成的一个具有解析类C语言的编译器,能够解析基础的C语言文法,并生成相应的语法树,通过语义分析形成中间代码。

1.2 编译器功能介绍

  • 编译的功能:

    • 翻译一个语言到另一个语言
    • 输入源语言(高级语言)转变为输出的目标语言(机器码等)
  • 编译流程:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qcpVBYrM-1645692610654)(report/img/trans_pro.png)]

1.3 总体架构和运行环境

1.3.1 总体架构

画代码结构调用关系图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GRAQuiHz-1645692610656)(report/img/code.png)]

1.3.2 运行环境

环境要求:flex bison g++11 python3

Chapter 2 : 词法分析

2.1 总体描述

词法分析器是从左到右逐个字符地对源程序进行扫描,产生一个个的单词符号,把作为字符串的源程序改造成为单词符号串的中间程序。词法分析器部分由Lex实现。

2.2 正规表达式描述

2.2.1 数据表示

先列实现的常量数据类型:eg. void,int,double,char

类别内容
D(数字)[0-9]
L(字母)[a-zA-Z]
H(16进制)[a-fA-F0-9]
E(科学计数表示)[Ee][±]?{D}+
P([Pp][±]?{D}+)
FS(f|F|l|L)
标识符{L}({L}|{D})*
整数常量[1-9][0-9]*
浮点数常量[0-9]+.[0-9]+
字符串常量L?“(\\.|[^\\”\n]*"
常量L?.(\\.|[^\\‘\n])+’
常量0[xX]{H}+{P}{FS}?
常量0[xX]{H}*“.”{H}+{P}?{FS}?
常量0[xX]{H}+“.”{H}*{P}?{FS}?

正则表达式定义:

{L}({L}|{D})* 	{count(); yylval.gt =create_tree("IDENTIFIER",0,yylineno);	return(check_type());/*IDENTIFIER*/ }

[1-9][0-9]*	{ count(); yylval.gt =create_tree("CONSTANT_INT",0,yylineno);	return(CONSTANT_INT); /*10进制*/}

L?'(\\.|[^\\'\n])+'		{ count(); return(CONSTANT); }

[0-9]+\.[0-9]+		{ count(); yylval.gt =create_tree("CONSTANT_DOUBLE",0,yylineno);	return(CONSTANT_DOUBLE); /*浮点数*/}

0[xX]{H}+{P}{FS}?			{ count(); return(CONSTANT); }

0[xX]{H}*"."{H}+{P}?{FS}?   { count(); return(CONSTANT); }

0[xX]{H}+"."{H}*{P}?{FS}?   { count(); return(CONSTANT); }



"/*"			{ comment();/*注释*/}

"//"[^\n]*      { /* consume //-comment */ }

L?\"(\\.|[^\\"\n])*\"	{ count();  yylval.gt =create_tree("STRING_LITERAL",0,yylineno);	return(STRING_LITERAL); /*字符串常量*/
2.2.2 关键字
名称
bool, char, int, double, void
continue, break, do, while, for
if, else
goto, return
return
true, false
2.2.3 操作符

先列实现的操作符类型

类别内容
单目运算符+ - ~ !
关系运算符< > <= >= != ==
算术运算符+ - * / % | ^ &
逻辑运算符|| &&
移位运算>> <<
赋值运算符= += -= *= /= %= &= ^= |= <<= >>=
2.2.4 注释及其他

注释表示: // /* */

"/*"			{ comment();/*注释*/}

"//"[^\n]*      { /* consume //-comment */ }

[\t\v\n\f ]		{ count();}

Chapter 3 : 语法分析

3.1 总体描述

语法分析是编译过程的核心部分。它的任务是在词法分析识别出单词符号串的基础上,分析并判定程序的语法结构是否符合语法规则。语法分析部分由YACC在基于我们定义的树的结构的基础上实现。

3.2 文法描述

CFG流程图:

Program -> translation_unit


3.2.1 转化单元

translation_unit -> external_declaration | translation_unit external_declaration


3.2.2 状态语句的分类:复合,表达,选择,迭代,跳转

statement -> **compound_statement **| expression_statement| selection_statement| iteration_statement| jump_statement

  • 复合

**compound_statement ** -> ‘{’ ‘}’ | ‘{’ block_item_list ‘}’

block_item_list -> block_item | block_item_list block_item

block_item* -> declaration | statement

  • 表达

expression_statement -> ‘;’ | expression ‘;’

  • 选择

selection_statement -> IF ‘(’ expression ‘)’ statement %prec LOWER_THAN_ELSE | IF ‘(’ expression ‘)’ statement ELSE statement

  • 迭代

iteration_statement -> WHILE ‘(’ expression ‘)’ statement| DO statement WHILE ‘(’ expression ‘)’ ‘;’| FOR ‘(’ expression_statement expression_statement ‘)’ statement| FOR ‘(’ expression_statement expression_statement expression ‘)’ statement| FOR ‘(’ declaration expression_statement ‘)’ statement| FOR ‘(’ declaration expression_statement expression ‘)’ statement

  • 跳转

jump_statement ->CONTINUE ‘;’| BREAK ‘;’| RETURN ‘;’| RETURN expression ‘;’


3.2.3 外部函数声明

external_declaration -> function_definition | declaration


3.2.4 函数定义

function_definition -> type_definition declarator declaration_list compound_statement| type_definition declarator compound_statement


3.2.5 声明部分
  • 声明列表

declaration_list -> declaration | declaration_list declaration

  • 声明部分

declaration -> type_definition ‘;’| type_definition init_declarator_list ‘;’

  • 类型定义

type_definition -> VOID | CHAR | INT | DOUBLE | BOOL

  • 初始化声明列表

init_declarator_list ->init_declarator| init_declarator_list ‘,’ init_declarator

  • 初始化声明

init_declarator ->declarator| declarator ‘=’ initializer

  • 声明

declarator ->IDENTIFIER| ‘(’ declarator ‘)’| declarator ‘[’ assignment_expression ‘]’| declarator ‘[’ ‘*’ ‘]’| declarator ‘[’ ‘]’| declarator ‘(’ parameter_list ‘)’| declarator '('identifier_list ‘)’| declarator ‘(’ ‘)’


3.2.6 初始化部分
  • 初始化格式

initializer ->assignment_expression| ‘{’ initializer_list ‘}’| ‘{’ initializer_list ‘,’ ‘}’

  • 初始化列表

initializer_list ->initializer| designation initializer| initializer_list ‘,’ initializer| initializer_list ‘,’ designation initializer

designation -> designator_list

designator_list -> designator | designator_list designator

designator -> ‘[’ logical_or_expression ‘]’ | ‘.’ IDENTIFIER


3.2.7 参数部分
  • 参数列表

parameter_list ->parameter_declaration| parameter_list ‘,’ parameter_declaration

  • 参数声明

parameter_declaration ->type_definition declarator| type_definition abstract_declarator| type_definition

  • 标识符列表

identifier_list ->IDENTIFIER| **identifier_list **‘,’ IDENTIFIER

abstract_declarator -> ‘(’ abstract_declarator ‘)’| ‘[’ ‘]’| ‘[’ assignment_expression ‘]’| abstract_declarator ‘[’ ‘]’| abstract_declarator ‘[’ assignment_expression ‘]’| ‘[’ ‘’ ‘]’| abstract_declarator ‘[’ '’ ‘]’| ‘(’ ‘)’| ‘(’ parameter_list ‘)’| abstract_declarator ‘(’ ‘)’| abstract_declarator ‘(’ parameter_list ‘)’


3.2.8 表达式部分

expression -> assignment_expression | expression ‘,’ assignment_expression

  • 赋值表达式

assignment_expression -> **logical_or_expression **| monocular_expression assignment_operator assignment_expression

assignment_operator -> ‘=’|MUL_ASSIGN|DIV_ASSIGN|MOD_ASSIGN|ADD_ASSIGN|SUB_ASSIGN|LEFT_ASSIGN|RIGHT_ASSIGN| AND_ASSIGN|XOR_ASSIGN|OR_ASSIGN

  • 逻辑表达式

logical_or_expression -> logical_and_expression | logical_or_expression OR_OP logical_and_expression

logical_and_expression -> bitwise_or_expression | logical_and_expression AND_OP bitwise_or_expression

bitwise_or_expression -> xor_expression | bitwise_or_expression ‘|’ xor_expression

xor_expression -> **and_expression **| xor_expression ‘^’ and_expression

and_expression -> equaljudge_expression | and_expression ‘&’ equaljudge_expression

equaljudge_expression -> **compare_expression **| equaljudge_expression EQ_OP compare_expression | equaljudge_expression NE_OP compare_expression

compare_expression -> **shift_expression **| compare_expression ‘<’ shift_expression | compare_expression ‘>’ shift_expression | compare_expression LE_OP shift_expression | compare_expression GE_OP shift_expression

  • 移位表达式

shift_expression -> **addsub_expression **| shift_expression LEFT_OP addsub_expression | shift_expression RIGHT_OP addsub_expression

  • 算数表达式

addsub_expression -> muldiv_expression | addsub_expression ‘+’ muldiv_expression| addsub_expression ‘-’ muldiv_expression

muldiv_expression -> monocular_expression | **muldiv_expression **‘*’ monocular_expression | muldiv_expression ‘/’ **monocular_expression **| muldiv_expression ‘%’ monocular_expression

  • 一元表达式

monocular_expression>postfix_expression| INC_OP monocular_expression| DEC_OP monocular_expression| monocular_operator monocular_expression

monocular_operator ->‘+’| ‘-’| ‘*’| ‘~’| ‘!’

  • 后缀表达式

postfix_expression -> basic_expression | postfix_expression ‘[’ expression ‘]’| postfix_expression ‘(’ ‘)’| postfix_expression ‘(’ argument_expression_list ‘)’| postfix_expression INC_OP| postfix_expression DEC_OP

  • 参数表达式

argument_expression_list->assignment_expression|argument_expression_list’,’ assignment_expression

  • 基础表达式

basic_expression ->IDENTIFIER| TRUE| FALSE| CONSTANT_INT| CONSTANT_DOUBLE| ‘(’ expression ‘)’

3.3 数据结构

3.3.1 语法树结构定义

SyntaxTree定义:

struct SyntaxTree
{
    string content;
    string name;
    int line; 
    int number; 

    struct SyntaxTree *child;
    struct SyntaxTree *sibling;
};

content存储树的注释,即语义分析用到的变量的值等;树的结构采用 first-child next-sibling的结构

3.3.2 函数说明

语法树每个函数功能描述:

struct SyntaxTree *create_tree(string name, int num, ...);

void free_tree(SyntaxTree *node);
void print_tree(SyntaxTree *root, FILE *fp);
void analysis_tree(struct SyntaxTree *head, int leael);
void traverse_tree(SyntaxTree *node, ofstream &outfile);

void write_to_file(SyntaxTree *root, string path);
函数功能
create_tree创建树节点
free_tree释放语法树
traverse_tree遍历语法树
analysis_tree分析打印树content
print_tree打印出语法树
write_to_file将树结构写入文件

3.4 原理及实现

.y和tree.cpp调用模式

# build.sh
if [ ! -d "dist" ]; then
  mkdir dist
fi

flex --outfile=dist/compiler.lex.yy.cpp compiler.l
yacc --output=dist/y.tab.cpp -d compiler.y

cp tree.cpp dist/tree.cpp
cp tree.h dist/tree.h
cd dist

echo '#include"tree.h"\n' | cat - y.tab.hpp > y.tab.hpp.temp && rm y.tab.hpp && mv y.tab.hpp.temp y.tab.hpp
g++ -std=c++11 -o compiler tree.cpp compiler.lex.yy.cpp y.tab.cpp

语法树例子和图:

例如demo.c为

int main()
{
    int a[10];

    int i;
    for (i=1;i<5;i++)
        a[i] = i + 1;

    for (i=1;i<5;i++)
        print(a[i]);

}

生成的语法树的图为:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4Np83OoP-1645692610657)(report/img/ir_tree.png)]

Chapter 4 : 语义分析

4.1 总体描述

语义分析是编译过程的一个逻辑阶段, 语义分析的任务是对结构上正确的源程序进行上下文有关性质的审查,进行类型审查。语义分析是审查源程序有无语义错误,为代码生成阶段收集类型信息。
语义分析的地位是编译程序最实质性的工作;第一次对源程序的语义作出解释,引起源程序质的变化。

4.2 数据结构

4.2.1 数据结构定义
4.2.1.1 作用域变量管理
class Block:
    def __init__(self, name="", type="", num=-1):
        self.func = funcNode()
        self.is_func = False
        self.varMap = {}
        self.arrayMap = {}
        self.label_bk = ""
        self.can_bk = False

Block这个类的作用是描述一个作用域主要用于管理这个作用域中的变量、标签和(函数信息),包括变量信息,函数信息,数组信息。

变量名作用
func函数结构体
is_func是否是函数块
varMap变量名和变量节点映射
arrayMap数组名和数组节点映射
label_bk跳转的标记名
can_bk是否需要跳转
4.2.1.2 变量信息
class varNode:
    def __init__(self):
        self.name = ""
        self.type = ""
        self.num = -1
        self.use_addr = False
        self.bool_exp = ""

varNode类的作用是储存变量信息。

变量名作用
namecontent或者临时变量名
type数据类型
num变量数量
use_addr是否是数组, 数组类型则赋值为True
bool_exp存储返回值为bool的表达式 “>= <= == !=”
4.2.1.3 数组信息
class arrayNode:
    def __init__(self):
        self.name = ""
        self.type = ""
        self.num = -1

arrayNode的作用是存放数组信息,包括数组大小、命名等。

变量名作用
name数组名
type数组类型
num数组长度
4.2.1.4 函数信息
class funcNode:
    def __init__(self):
        self.name = ""
        self.re_type = ""
        self.para_list = []

funcNode的作用是存放函数名称,返回类型和变量参数等。

变量名作用
name函数名
re_type返回类型
para_list参数结点,存储的是varnode
4.2.1.5 语义分析类
class Parser:
    funcPool = None
    blockStack = None
    root = None
root表示从json文件读入的经过语法分析后的语法树,在此基础上构建的SyntaxTree数据结构以便于自下而上的语义分析。

blockStack表示一个符号表栈,Block这个类的作用是描述一个作用域主要用于管理这个作用域中的变量、标签和(函数信息),这个list模仿了Block的进栈出栈模式。

fucPool存储源码中的函数定义和声明。
4.2.2 语义分析实现

语义分析主要任务是分析源程序的含义并做出相应的语义处理。语义处理主要包含两个部分:

  • 静态语义检查

    类型检查,控制流检查,唯一性检查,其它相关的语义检查

  • 语义翻译

    生成与硬件机器相对独立的中间语言代码

4.2.2.1 语义翻译与符号表栈

符号表栈的处理包括作用域的进栈与出栈,以及对语法树的属性翻译和属性计算以解析整个语法树的具体语义,并协助翻译中间码,具体符号表栈的分析将在中间码介绍。

4.2.2.2 静态语义检查

MiniC编译器主要实现三类语义错误检查:

  • 类型确定与类型检查
  • 控制流检查
  • 唯一性检查

错误检查具体功能实现如下:

4.2.2.2.1 类型确定与类型检查

类型定义包含变量或函数使用前是否经过定义。

if (rnode.num < 0):
	self.error(primary_exp.child.line,
               "Undefined variable " + content)

...

if (funcName not in self.funcPool):
	self.error(post_exp.child.child.child.line,
               "Undefined function " + funcName)

类型检查包含,运算符两边的变量是否可以进行计算,对数据进行的处理是否符合数据本身特性,函数返回值是否和定义函数返回值匹配,函数输入参数与定义参数类型不匹配或数量不匹配等等。

if (funcName not in self.funcPool):
	self.error(post_exp.child.child.child.line,
               "Undefined function " + funcName)

...


elif op == 'MOD_ASSIGN':
	if node1.type != 'int' or node2.type != 'int':
		self.error(assign_exp.child.line,
                   "The two variables should be int.")

...

if rnode.type != funcType:
	self.error(node.child.sibling.line, 
               "return type error! doesn't match function return type.")

类型确定样例:

(这里以函数未定义为例)

int main()
{
    int a[10];
    function(a);
}

类型检查样例:

(这里以函数实际返回值与定义不符为例)

int function()
{
    return 1.1;
}
int main()
{
    int para;
    para = function();
}

4.2.2.2.2 控制流检查

控制流中每个节点代表一个基本块,例如,没有任何跳跃或跳跃目标的直线代码块;跳跃目标以一个块开始,和以一个块结束。在控制流检查过程中,如果先前没有定义跳转的代码块,则会对其进行报错:

elif node.child.name == "BREAK":
	num = self.getBreakBlockNumber()
	if num < 0:
		self.error(node.child.line, "break statement not within a loop..")

控制流检查样例:

int main()
{
    int a[10];
    break;
}

4.2.2.2.3 唯一性检查

c语言中对函数名的要求是唯一的,不存在两个名称相同的函数名,在编译器语义分析时需要对函数名进行是否重复定义的分析:

if self.funcPool[funcName].isdefinied:
	self.error(declarator.child.child.line, "Function " +
                           funcName + " has been defined before.")

唯一性检查样例:

int function()
{
    int a = 1;
}
int function()
{
    int a = 2;
}
int main()
{
    int a[10];
}

Chapter 5 : 中间代码

5.1 总体描述

5.2 中间代码格式说明

GrammerDescription
LABEL label_name :声明标签
left := right赋值语句
right: var binomial_op var | var | unary_op var | *temp | &temp | array_element | CALL f(var1,var2,var3…)
var: temp | constant
left: temp | array_element | *temp
array_item: temp[var]
temp必须只含有小写英文字母、数字、下划线,且首字符是字母
GOTO label1无条件跳转至标签处
IF var GOTO label1条件语句
IFNOT var GOTO label1条件语句
RETURN var函数返回
MALLOC var1[size]申请大小为size的内存空间,并将申请到的连续内存首地址赋给var1
CALL f (var1,var2,var3…)调用函数并不需要返回值
Function f(var1,var2,var3…)声明函数f

5.3 数据结构

5.3.1 数据结构定义

符号表 各种操作

5.3.2 算法

5.4 原理及实现

例子

Chapter 6 : 运行方式和结果

6.1 运行方式

~ bash build.sh
~ bash test.sh
~ python load_json.py
~ python load_quadruples.py

6.2 demo结果

6.2.1 运算符测试

源码:

int main()
{
    int a, b, result;
    a = read();
    b = read();


    result = a + b;
    print(result);

    result = a - b;
    print(result);

    result = a * b;
    print(result);

    result = a / b;
    print(result);

    result = a % b;
    print(result);

    a++;
    b++;
    print(a);
    print(b);
    
}

语法树:

中间码:

FUNCTION main :
temp0 := #10
temp2 := #4
temp1 := temp2 * temp0
temp2 := #1
var0 := temp2
LABEL lab :
temp3 := #5
temp4 := var0 <= temp3
IF var0 GOTO temp3
GOTO goto
LABEL lab :
temp7 := #4
temp6 := var0 * temp7
temp5 := &var0 + temp6
temp8 := #1
temp9 := var0 + temp8
temp5 := temp9
GOTO goto
LABEL lab :
temp10 := #1
var0 := temp10
LABEL lab :
temp11 := #5
temp12 := var0 <= temp11
IF var0 GOTO temp11
GOTO goto
LABEL lab :
temp15 := #4
temp14 := var0 * temp15
temp13 := &var0 + temp14
ARG temp13
CALL print
GOTO goto
LABEL lab :
6.2.1 选择语句测试
int main()
{
    int a, b, result;
    a = read();
    b = read();

    if (a > b)
    {
        result = a - b;
        print(result);
    }
    else if(a == b)
    {
        result = a - b;
        print(result);
    }
    else
    {
        result = b - a;
        print(result);
    }
}
```http://www.biyezuopin.vip

语法树:

![](https://img-blog.csdnimg.cn/img_convert/ace1be3a69096bfdf7ec42c939695c69.png)

中间码:

FUNCTION main :
var0 := CALL read
var1 := CALL read
temp2 := var0 >= var1
IF var0 GOTO var1
GOTO goto
LABEL lab :
temp3 := var0 - var1
var2 := temp3
ARG var2
CALL print
GOTO goto
LABEL lab :
IF var0 GOTO var1
GOTO goto
LABEL lab :
temp5 := var0 - var1
var2 := temp5
ARG var2
CALL print
GOTO goto
LABEL lab :
temp6 := var1 - var0
var2 := temp6
ARG var2
CALL print
LABEL lab :
LABEL lab :


#### 6.2.3 循环语句测试

```c++
int main()
{
    int a[10], i, result;
    for (i=1;i<10;i++)
    {
        a[i] = i;
        print(a[i]);
    }

    i = 10;
    while(i>1)
    {
        print(a[i]);
        if(a[i]<5)
        {
            break;
        }
    }
}

语法树:

中间码:
http://www.biyezuopin.vip

FUNCTION main :
temp0 := #10
temp2 := #4
temp1 := temp2 * temp0
temp2 := #1
var0 := temp2
LABEL lab :
temp3 := #10
temp4 := var0 <= temp3
IF var0 GOTO temp3
GOTO goto
LABEL lab :
temp7 := #4
temp6 := var0 * temp7
temp5 := &var0 + temp6
temp5 := var0
temp10 := #4
temp9 := var0 * temp10
temp8 := &var0 + temp9
ARG temp8
CALL print
GOTO goto
LABEL lab :
temp11 := #10
var0 := temp11
LABEL lab :
temp12 := #1
temp13 := var0 >= temp12
IF var0 GOTO temp12
GOTO goto
LABEL lab :
temp16 := #4
temp15 := var0 * temp16
temp14 := &var0 + temp15
ARG temp14
CALL print
temp19 := #4
temp18 := var0 * temp19
temp17 := &var0 + temp18
temp20 := #5
temp21 := temp17 <= temp20
IF temp17 GOTO temp20
GOTO goto
LABEL lab :
GOTO goto
LABEL lab :
GOTO goto
LABEL lab :
6.2.4 函数与递归

源码:

int fact(int i) {
    if (i <= 1) {
        return 1;
    }
    else{
        return i * fact(i - 1);
    }
}
int main() {
    int i;
    int times;
    times=read();
    for(i = 1; i < times + 1; i++)
    print( fact(i) );
    return 0;
}

语法树:

中间码:

FUNCTION fact :
PARAM var0
temp0 := #1
temp1 := var0 <= temp0
IF var0 GOTO temp0
GOTO goto
LABEL lab :
temp2 := #1
RETURN temp2
GOTO goto
LABEL lab :
temp3 := #1
temp4 := var0 - temp3
ARG temp4
temp5 := CALL fact
temp6 := var0 * temp5
RETURN temp6
LABEL lab :
FUNCTION main :
var2 := CALL read
temp8 := #1
var1 := temp8
LABEL lab :
temp9 := #1
temp10 := var2 + temp9
temp11 := var1 <= temp10
IF var1 GOTO temp10
GOTO goto
LABEL lab :
ARG var1
temp12 := CALL fact
ARG temp12
CALL print
GOTO goto
LABEL lab :

Chapter 7 : 开发困难及解决方案

7.1 困难1

  • 困难

  • 解决方案

7.2 困难2

  • 困难

  • 解决方案

7.3 困难3

  • 困难

  • 解决方案

7.4 困难4

  • 困难

  • 解决方案

Chapter 8 : 总结

MiniC基本实现了C语言的部分常用功能,能够进行正确的词法、语法、语义分析并生成语法树进行可视化以及中间码。

未实现的功能还有很多,例如:

  • 结构体
  • 指针
  • 外部函数调用
  • ……

在实验中,对词法和语法分析有了更深刻的了解,能熟练运用lex和yacc进行操作,同时,对语义分析和错误纠正也有一定的了解。结合课程所学知识,能够通过语法树转化成四元码并生成中间码。在未来,我们将会对MiniC编译器进行优化与改善以实现更多功能。

  • 1
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本题要求使用lexyacc结合llvm编写一个C语言的简单编译器,需要完成词法分析、语法分析、语义分析以及代码生成等功能。 1.词法分析 词法分析器(lexer)将输入的源代码分解成一个个的词法单元(token),并将这些token传递给语法分析器。在本例中,我们使用lex工具生成词法分析器。 2.语法分析 语法分析器(parser)根据语法规则,将词法分析器传递过来的token组成的序列转换为一棵抽象语法树(AST)。在本例中,我们使用yacc工具生成语法分析器。 3.语义分析 语义分析器(semantic analyzer)对抽象语法树进行遍历,检查语法上的错误,并进行型检查、作用域检查等。在本例中,我们需要处理一些简单的语法规则,如变量声明、赋值语句、函数声明等。 4.代码生成 代码生成器(code generator)将抽象语法树转换为目标代码,这里我们使用LLVM作为目标代码生成器。LLVM是一个开源的编译器基础设施,提供了很好的中间表示(IR)和优化器,可以方便地生成目标代码。 综上所述,我们需要完成以下步骤来实现一个简单的C语言编译器: 1.使用lex工具生成词法分析器,解析代码中的token。 2.使用yacc工具生成语法分析器,将token序列转换成抽象语法树。 3.对抽象语法树进行语义分析,检查语法上的错误,进行型检查和作用域检查等。 4.使用LLVM作为目标代码生成器,将抽象语法树转换为目标代码。 5.完成上述四个步骤后,我们就可以将源代码编译成可执行文件,并执行程序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值