基于Lex 和 Yacc 的 C 语言编译器

       最近由于项目需要,看了点关于编译原理和编译器等方面的资料,特别是词法分析和语法分析部分,现做一下小结。

      一、编译器及其工作流程

       编 译器,是将便于人编写,阅读,维护的高级计算机语言翻译为计算机能识别,运行的低级机器语言的程序。编译器将源程序(Source program)作为输入,翻译产生使用目标语言(Target language)的等价程序。源程序一般为高级语言(High-level language),如Pascal,C++等,而目标语言则是汇编语言或目标机器的目标代码(Object code),有时也称作机器代码(Machine code)。

       一个现代编译器的主要工作流程如下:
       源程序(source code)→预处理器(preprocessor)→编译器(compiler)→汇编程序(assembler)→目标程序(object code)→连接器(链接器,Linker)→可执行程序(executables)

       而编译器各阶段的主要工作包括:  

      1. 词法分析

       词法分析器根据词法规则识别出源程序中的各个记号(token),每个记号代表一类单词(lexeme)。源程序中常见的记号可以归为几大类:关键字、标识符、字面量和特殊符号。词法分析器的输入是源程序,输出是识别的记号流。词法分析器的任务是把源文件的字符流转换成记号流。本质上它查看连续的字符然后把它们识别为“单词”。

       2. 语法分析

       语法分析器根据语法规则识别出记号流中的结构(短语、句子),并构造一棵能够正确反映该结构的语法树。

       3. 语义分析

       语义分析器根据语义规则对语法树中的语法单元进行静态语义检查,如果类型检查和转换等,其目的在于保证语法正确的结构在语义上也是合法的。

       4. 中间代码生成

      中间代码生成器根据语义分析器的输出生成中间代码。中间代码可以有若干种形式,它们的共同特征是与具体机器无关。最常用的一种中间代码是三地址码,它的一种实现方式是四元式。三地址码的优点是便于阅读、便于优化。

        5. 中间代码优化

      优化是编译器的一个重要组成部分,由于编译器将源程序翻译成中间代码的工作是机械的、按固定模式进行的,因此,生成的中间代码往往在时间和空间上有很大浪费。当需要生成高效目标代码时,就必须进行优化。

       6. 目标代码生成

      目标代码生成是编译器的最后一个阶段。在生成目标代码时要考虑以下几个问题:计算机的系统结构、指令系统、寄存器的分配以及内存的组织等。编译器生成的目标程序代码可以有多种形式:汇编语言、可重定位二进制代码、内存形式。

       7 符号表管理

      符号表的作用是记录源程序中符号的必要信息,并加以合理组织,从而在编译器的各个阶段能对它们进行快速、准确的查找和操作。符号表中的某些内容甚至要保留到程序的运行阶段。

      8 出错处理

      用 户编写的源程序中往往会有一些错误,可分为静态错误和动态错误两类。所谓动态错误,是指源程序中的逻辑错误,它们发生在程序运行的时候,也被称作动态语义 错误,如变量取值为零时作为除数,数组元素引用时下标出界等。静态错误又可分为语法错误和静态语义错误。语法错误是指有关语言结构上的错误,如单词拼写 错、表达式中缺少操作数、begin和end不匹配等。静态语义错误是指分析源程序时可以发现的语言意义上的错误,如加法的两个操作数中一个是整型变量名,而另一个是数组名等。

       二、 lex 和 yacc 简单入门

Lex(Lexical Analyzar 词法分析生成器),Yacc(Yet Another Compiler Compiler
编译器代码生成器)是Unix下十分重要的词法分析,语法分析的工具。经常用于语言分
析,公式编译等广泛领域。遗憾的是网上中文资料介绍不是过于简单,就是跳跃太大,
入门参考意义并不大。本文通过循序渐进的例子,从0开始了解掌握Lex和Yacc的用法。

<本系列文章的地址:http://blog.csdn.net/liwei_cmg/category/207528.aspx>

1.Lex(Lexical Analyzar) 初步示例

先看简单的例子(注:本文所有实例皆在RetHat Linux下完成):

一个简单的Lex文件 exfirst.l 内容:

%{
#include "stdio.h"
%}
%%
[\n]                  ;
[0-9]+                printf("Int     : %s\n",yytext);
[0-9]*\.[0-9]+        printf("Float   : %s\n",yytext);
[a-zA-Z][a-zA-Z0-9]* printf("Var     : %s\n",yytext);
[\+\-\*\/\%]          printf("Op      : %s\n",yytext);
.                     printf("Unknown : %c\n",yytext[0]);
%%

在命令行下执行命令flex解析,会自动生成lex.yy.c文件:
[root@localhost liweitest]flex exfirst.l

进行编译生成parser可执行程序:
[root@localhost liweitest]cc -o parser lex.yy.c -ll

[注意:如果不加-ll链结选项,cc编译时会出现以下错误,后面会进一步说明。]

/usr/lib/gcc-lib/i386-redhat-linux/3.2.2/http://www.cnblogs.com/../crt1.o(.text+0x18): In function `_start':
../sysdeps/i386/elf/start.S:77: undefined reference to `main'
/tmp/cciACkbX.o(.text+0x37b): In function `yylex':
: undefined reference to `yywrap'
/tmp/cciACkbX.o(.text+0xabd): In function `input':
: undefined reference to `yywrap'
collect2: ld returned 1 exit status


创建待解析的文件 file.txt:

title
i=1+3.9;
a3=909/6
bcd=4%9-333

通过已生成的可执行程序,进行文件解析。

[root@localhost liweitest]# ./parser < file.txt
Var     : title
Var     : i
Unknown : =
Int     : 1
Op      : +
Float   : 3.9
Unknown : ;
Var     : a3
Unknown : =
Int     : 909
Op      : /
Int     : 6
Var     : bcd
Unknown : =
Int     : 4
Op      : %
Int     : 9
Op      : -
Int     : 333

到此Lex用法会有个直观的了解:

1.定义Lex描述文件
2.通过lex,flex工具解析成lex.yy.c文件
3.使用cc编译lex.yy.c生成可执行程序


再来看一个比较完整的Lex描述文件 exsec.l :


%{
#include "stdio.h"
int linenum;
%}
%%
title                 showtitle();
[\n]                  linenum++;
[0-9]+                printf("Int     : %s\n",yytext);
[0-9]*\.[0-9]+        printf("Float   : %s\n",yytext);
[a-zA-Z][a-zA-Z0-9]* printf("Var     : %s\n",yytext);
[\+\-\*\/\%]          printf("Op      : %s\n",yytext);
.                     printf("Unknown : %c\n",yytext[0]);
%%
showtitle()
{
printf("----- Lex Example -----\n");
}

int main()
{
linenum=0;
yylex(); /* 进行分析 */
printf("\nLine Count: %d\n",linenum);
return 0;
}
int yywrap()
{
return 1;
}

进行解析编译:
[root@localhost liweitest]flex exsec.l
[root@localhost liweitest]cc -o parser lex.yy.c
[root@localhost liweitest]./parser < file.txt

----- Lex Example -----
Var     : i
Unknown : =
Int     : 1
Op      : +
Float   : 3.9
Unknown : ;
Var  &n

LexYacc使用教程(九).Windows下使用LexYacc LexYacc应用方法(九).Windows下使用LexYacc草木瓜  20070904一、序    不想LexYacc系列的最后一篇文章竟如此“难产”,已时隔三个月之久。不由慨叹自由可支配时间是如此之少,如此岂不谓新时代的“奴隶”~    罢罢罢,闲话少叙,回归正题,本文主要介绍在Windows下如何去使用LexYacc,以作为本系列文章的终结。    二、方法介绍   阅读详情

相关推荐

TinyCompiler:基于flexlex),bison(yaccLLVM的c编译器,支持LLVM IRobj代码生成。基于flex,bison以及LLVM,使用c ++ 11实现的类C语法编译器,支持生成中间代码及替换文件

TinyCompiler 序言 项目概述 本项目是基于flex,bisonLLVM,使用c ++ 11实现的类C语法编译器,使用flexbindingyacc对源代码进行词法,语法分析;在语法分析阶段生成整个源代码相应的抽象语法树后,根据LLVM IR(中间表示)模块中定义的中间代码语法输出与LLVM中间语言语法,机器无关的中间代码;最后,本项目通过调用LLVM后端模块的接口,根据本地指令集与操作系统架构,将中间代码编译成二进制目标代码。编译生成的目标代码之后可直接编译生成初始化文件,或与其他目标代码链接生成替代文件。 本项目解析的语法与是C语言的一个子集,但部分语法存在区别,这些将在最后的测试用例中具体说明。目前已支持的数据类型包括: 虚空 整型 浮动 双 烧焦 串 布尔 自定义结构体 样本(包括多维样本) 支持的主要语法包括: 变量的声明,初始化(包括一维细分初始化,多维序列暂不支持初始化,只能逐个元素赋值使用) 函数声明,函数调用(传递参数类型可以是任意已支持类型) 外部函数声明调用 控制流语句if-else,for,while任意层级的嵌套使用 单行注释(#) 二元运算

LEX&&YACC--编译界的神

最近研究lex&&yacc,记录并总结一些重要的概念解释。 lex&&yacc是gnu开源的全文解析工具,lex用于词法解析,yacc用于语法解析。lex一般也称为token scanner/lexer,yacc称为parser generator(语法解析器生成器)。 lex&&yacc这两个工具已经很老了,现代版本的工具为flex&&bison。两个工具可以结合使用,也可以只使用bison。 基本原理 lex词法解析,使用正则表达式进

aiyo_的博客 2147

YaccLex 快速入门

简介: Lex Yacc 是 UNIX 两个非常重要的、功能强大的工具。事实上, 如果你熟练掌握 Lex Yacc 的话,它们的强大功能使创建 FORTRAN C 的编译器如同儿戏。本文详细的讨论了编写自己的语言编译器所 用到的这两种工具,包括常规表达式、声明、匹配模式、变量、Yacc 语 法解析器代码。最后,本文解释了怎样把 Lex Yacc 结合起来。

红孩儿编程大师 4491

编译原理——LexYacc及应用

一. 实验原理: Lex(Lexical Analyzar 词法分析生成器),Yacc(Yet Another Compiler Compiler 编译器代码生成器)是Unix下十分重要的词法分析,语法分析的工具。经常用于语言分析,公式编译等广泛领域。 Lex工具是一种词法分析程序生成器,它可以根据词法规则说明书的要求来生成单词识别程序,由该程序识别出输入文本中的各个单词。 一般可以分为<定义部分><规则部分><用户子程序部分>。其中规则部分是必须的,定义用户子程序部

TTTSEP9TH2244的博客 5977

使用LexYacc开发C语言编译器(转)

(1) 从网站:http://www.lysator.liu.se/c/  下载C语言的语法文件:The ANSI C grammar (Yacc and Lex) (2) 编译词法文件: > lex c.l(3) 编译语法文件:> yacc -dv c.y说明:-d:产生头文件y.yab.h,-v:产生分析表y.output。针对else产生的移进规约冲突,采用了yacc默认

5687

探索C语言编译器的魅力:一款基于lexyacc的开源实现

探索C语言编译器的魅力:一款基于lexyacc的开源实现 在这个数字化的世界里,软件开发是推动科技进步的关键力量,而编程语言则是程序员的利器。今天,我们要向您推荐一款开源的C语言编译器,它由lexyacc构建,不仅揭示了编译原理的奥秘,也为开发者提供了一个实践学习编译器设计的绝佳平台。 项目介绍 这个项目是一个纯C语言编译器,实现了大部分C语言的语法特性(不包括struct指针),包括但不...

gitblog_00056的博客 439

使用LexYacc开发C语言编译器

(1) 从网站:http://www.lysator.liu.se/c/  下载C语言的语法文件: The ANSI C grammar (Yacc and Lex)  (2) 编译词法文件: > lex c.l (3) 编译语法文件: > yacc -dv c.y 说明:-d:产生头文件y.yab.h,-v:产生分析表y.output。针对else产生的移进规约冲突,采用了y

xyjikl 1440

c语言 lex编译器,使用LexYacc开发C语言编译器

0$accept:translation_unit$end 1primary_expression:IDENTIFIER 2|CONSTANT 3|STRING_LITERAL 4|'('expression')' 5postfix_expression:primary_expression 6|postfix_expression'['expression']'...

weixin_39631689的博客 651

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

lexyacc写成的一个具有解析类C语言编译器,能够解析基础的C语言文法,并生成相应的语法树,通过语义分析形成中间代码。翻译一个语言到另一个语言输入源语言(高级语言)转变为输出的目标语言(机器码等)编译流程:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qcpVBYrM-1645692610654)(report/img/trans_pro.png)]->int line;int number;content存储树的注释,即语义分析用到的变量的值等。

毕业作品网站 3333

python c语言语法分析_GitHub - hhlrank/cCompiler: c语言编译器,用 lex yacc 工具完成词法分析与语法分析并生成语法树,C++实现了语 法树的解析并生成中...

C语言编译器lexyacc编写的c语言编译器实现了C语言除了struct指针几乎所有的语法。运行环境要求:flex bison g++11 python3中间代码生成windows命令行输入:flex compiler.lbison -vdty compiler.yg++ -std=c++11 -o compiler tree.cpp Praser.cpp innerCode.cpp tool...

weixin_39526741的博客 535

c语言编译工具ut,GitHub - Polly29/cCompiler: c语言编译器,用 lex yacc 工具完成词法分析与语法分析并生成语法树,C++实现了语 法树的解析并生成中间代码,生...

C语言编译器lexyacc编写的c语言编译器实现了C语言除了struct指针几乎所有的语法。运行环境要求:flex bison g++11 python3中间代码生成windows命令行输入:flex compiler.lbison -vdty compiler.yg++ -std=c++11 -o compiler tree.cpp Praser.cpp innerCode.cpp tool...

weixin_42521795的博客 415

c语言实现一个编译器生成语法树,GitHub - wolf1981/cCompiler: c语言编译器,用 lex yacc 工具完成词法分析与语法分析并生成语法树,C++实现了语 法树的解析并生...

C语言编译器lexyacc编写的c语言编译器实现了C语言除了struct指针几乎所有的语法。运行环境要求:flex bison g++11 python3中间代码生成windows命令行输入:flex compiler.lbison -vdty compiler.yg++ -std=c++11 -o compiler tree.cpp Praser.cpp innerCode.cpp tool...

weixin_39619170的博客 566
下一篇: 一个HR人给应届生的面试建议【推荐】
JennyComputer2014
博客等级 码龄12年 2粉丝 0原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值