lex bison

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情

还是人家的例子,自己亲手输入,虽然这样麻烦了不少,但是一字一句的输入对建立一个编译器的过程有了最
为生动的理解。我们的目标就是建立一个这样的程序,可以运行如下的代码:
a = 1;
b = 6 - 2 * (3 - 1);
if(a > b){
 print a;
}
else
{
 print b;
}
// 斐波那契数列
c = 1;
d = 1;
e = 1;
while(a < 10){
 f = d; 
 //临时变量
 d = d + e;
 e = f; a = a + 1;
 //增加计数
 print d;
 //打印斐波那契数列
}
语法有些熟悉吧!虽然这个脚本还只支持整数的运算,只有简单的流程控制(已经包含了程序设计的所有必要
流成了),一个简单的打印输出语句。

言归正传,看看这个程序有那些部分组成呢?
? calc.h 语法分析的结构声明
? calc.lex 词法分析文件
? calc.y 语法分析文件
? ex_parser.c 解释方式运行程序的引擎(还有编译为汇编和输出语法树方式的输出,这里没有列出)

________________________________________
下面还是让代码直接说话吧!
-- calc.h --
/* *  简单计算器分析的节点类型定义 */
typedef enum{ typeCon, typeId, typeOpr}nodeEnum;
/* 常量 */
typedef struct{
int value;
}conNodeType;
/* 变量 */
typedef struct{
int i; /* 指向变量符号表的序号 */
}idNodeType;
/* 运算符 */
typedef struct{
int oper; /* 运算符*/
int nops; /* 算子个数 */
struct nodeTypeTag *op[1]; /* 可扩展的算子数组 */
}oprNodeType;
typedef struct nodeTypeTag{
nodeEnum type; /* 节点的类型 */
/* 各种节点公用的联合体*/
union{ 
conNodeType con; 
idNodeType  id; 
oprNodeType opr;
};
}nodeType;
extern int sym[26];
--calc.lex-- 是一个相当简单的文件,这里支持的关键词比较少。
%{
/*
 * 简单计算器的词法分析程序。
 */
#include <stdlib.h>
#include "calc.h"
#include "calc.tab.h"
void yyerror(char*);
%}
%%
[a-z] {
 yylval.sIndex = *yytext - 'a';
 return VARIABLE;
 }
[0-9]+ {
 yylval.iValue = atoi(yytext);
 return INTEGER;
 }
[-()<>=+*/;{}.] return *yytext;
">=" return GE;
"<=" return LE;
"==" return EQ;
"!=" return NE;
"while" return WHILE;
"if" return IF;
"else" return ELSE;
"print" return PRINT;
[ /t/n] /* 忽略空白 */
////.*  /* 忽略注释 */
. yyerror("未知字符");
%%
int yywrap(void){
 return 1;
}
--calc.y-- 这里是构建语法的核心,如果想自己构建一个编译器什么的,还是首先弄明白自己的语法怎么
使用BNF表达式来表示吧,写成Yacc格式的文件反而不是那么复杂的事情。
%{
/*
 *----------------------------.
 *|  简单计算程序语法分析程序 |
 *`---------------------------/
 */
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "calc.h"
/*
 * 类型定义
 */
nodeType* opr(int oper, int nops, ...);
nodeType* id(int i);
nodeType* con(int value);
void freeNode(nodeType* p);
int  ex(nodeType* p);
int yylex(void);
void yyerror(char*s);
int sym[26]; /* 变量符号表 */
%}
%union  {
 int iValue;  /*整数类型值*/
 char sIndex; /* 符号表的序号*/
 nodeType* nPtr; /* 节点的指针 */
 };
%token <ivalue> INTEGER
%token <sindex> VARIABLE
%token WHILE IF PRINT
%nonassoc IFX
%nonassoc ELSE
%left GE LE EQ NE '>' '<'
%left '+' '-'
%nonassoc UMINUS
%type <nptr> stmt expr stmt_list
%%
program:
       function  {exit(0);}
       ;
function:
 function stmt {ex($2); freeNode($2);}
 | /*NULL*/
 ;
stmt:
    ';'   {$ = opr(';', 2, NULL, NULL);}
    |expr ';'  {$ = $1;}
    |PRINT expr ';' {$ = opr(PRINT, 1, $2);}
    |VARIABLE '=' expr ';' {$ = opr('=', 2, id($1), $3);}
    |WHILE'('expr')'stmt{$ = opr(WHILE, 2, $3, $5);}
    |IF'('expr')'stmt %prec IFX {$ = opr(IF, 2, $3, $5);}
    |IF'('expr')'stmt ELSE stmt {$ = opr(IF, 3, $3, $5, $7);}
    |'{'stmt_list'}' {$ = $2;}
    ;
stmt_list:
  stmt  {$ = $1;}
  |stmt_list stmt{$ = opr(';', 2, $1, $2);}
  ;
expr:
    INTEGER  {$ = con($1);}
    |VARIABLE  {$ = id($1);}
    |'-' expr %prec UMINUS {$ = opr(UMINUS, 1, $2);}
    |expr '+' expr {$ = opr('+', 2, $1, $3);}
    |expr '-' expr {$ = opr('-', 2, $1, $3);}
    |expr '*' expr {$ = opr('*', 2, $1, $3);}
    |expr '/' expr {$ = opr('/', 2, $1, $3);}
    |expr '<' expr {$ = opr('<', 2, $1, $3);}
    |expr '>' expr {$ = opr('>', 2, $1, $3);}
    |expr GE  expr {$ = opr(GE, 2, $1, $3);}
    |expr LE  expr {$ = opr(LE, 2, $1, $3);}
    |expr NE  expr {$ = opr(NE, 2, $1, $3);}
    |expr EQ  expr {$ = opr(EQ, 2, $1, $3);}
    |'('expr')'  {$ = $2;}
    ;
%%
#define SIZEOF_NODETYPE ((char*)&p->con - (char*)p)
nodeType* con(int value){
 nodeType* p;
 size_t nodeSize;
 /* allocate node */
 nodeSize = SIZEOF_NODETYPE + sizeof(conNodeType);
 if ((p = malloc(nodeSize)) == NULL)
  yyerror("out of memory");
 /* copy information */
 p->type = typeCon;
 p->con.value = value;
 return p;
}
nodeType* id(int i){
 nodeType* p;
 size_t nodeSize;
 nodeSize = SIZEOF_NODETYPE + sizeof(idNodeType);
 if((p = malloc(nodeSize)) == NULL)
  yyerror("out of memory");
 
 p->type = typeId;
 p->id.i = i;
 return p;
}
nodeType* opr(int oper, int nops, ...){
 va_list ap;
 nodeType* p;
 size_t nodeSize;
 int i;
 nodeSize = SIZEOF_NODETYPE + sizeof(oprNodeType) +
  (nops - 1) * sizeof(nodeType*);
 if((p = malloc(nodeSize)) == NULL)
  yyerror("out memory");
 
 p->type = typeOpr;
 p->opr.oper = oper;
 p->opr.nops = nops;
 va_start(ap, nops);
 for(i = 0;i < nops;i ++){
  p->opr.op[i] = va_arg(ap, nodeType*);
 }
 va_end(ap);
 return p;
}
void freeNode(nodeType* p){
 int i;
 if(!p){
  return ;
 }
 if(p->type == typeOpr){
  for(i = 0;i < p->opr.nops;i++){
   freeNode(p->opr.op[i]);
  }
 }
 free(p);
}
void yyerror(char*s){
 fprintf(stderr, "Error: %s /n", s);
}
int main(void){
 yyparse();
 return 0;
}

--ex_parser.c-- 包含了ex()函数的一个版本:如何解释执行脚本。这是一个以递归方式执行的函数,
一次单独的调用返回可以看作是一个独立的语法上下文。
/*
 * 这是一个使用解释方式运行程序的编译处理ex(nodeType*)函数版本。
 */
#include <stdio.h>
#include "calc.h"
#include "calc.tab.h"
int ex(nodeType* p){
 if(!p){
  return 0;
 }
 switch(p->type){
  case typeCon:
   return p->con.value;
  case typeId:
   return sym[p->id.i];
  case typeOpr:
   switch(p->opr.oper){
    case WHILE:
     while(ex(p->opr.op[0]))
      ex(p->opr.op[1]);
     return 0;
    case IF:
     if(ex(p->opr.op[0]))
      ex(p->opr.op[1]);
     else if(p->opr.nops > 2)
      ex(p->opr.op[2]);
     return 0;
    case PRINT:
     printf("%d/n",ex(p->opr.op[0]));
     return 0;
    case ';':
     ex(p->opr.op[0]);
     return ex(p->opr.op[1]);
    case '=':
     return sym[p->opr.op[0]->id.i] = ex(p->opr.op[1]);
    case UMINUS:
     return -ex(p->opr.op[0]);
    case '+':
     return ex(p->opr.op[0]) + ex(p->opr.op[1]);
    case '-':
     return ex(p->opr.op[0]) - ex(p->opr.op[1]);
    case '*':
     return ex(p->opr.op[0]) * ex(p->opr.op[1]);
    case '/':
     return ex(p->opr.op[0]) / ex(p->opr.op[1]);
    case '<':
     return ex(p->opr.op[0]) < ex(p->opr.op[1]);
    case '>':
     return ex(p->opr.op[0]) > ex(p->opr.op[1]);
    case GE:
     return ex(p->opr.op[0]) >= ex(p->opr.op[1]);
    case LE:
     return ex(p->opr.op[0]) <= ex(p->opr.op[1]);
    case NE:
     return ex(p->opr.op[0]) != ex(p->opr.op[1]);
    case EQ:
     return ex(p->opr.op[0]) == ex(p->opr.op[1]);
   }
 }
 return 0;
}
如何编译呢?也是非常的简单:
>bison -d calc.y     (生成calc.tab.c和calc.tab.h两个文件)
>flex calc.lex         (生成yy.lex.c这个文件)
>gcc -g -Wall  calc.tab.c yy.lex.c -o calc
如果将最上面提到的那个脚本存为 test.txt那么执行它就可以用:
>cat test.txt | ./calc
那么你就可以看到出现一排数字(每行一个),从第二行开始到结束就是那个斐波那契数列啦!!
转自:http://blog.chinaunix.net/u/30708/showart_434574.html

编译原理实验二:Bison HNU编译原理实验二:Bison 阅读详情

相关推荐

Lex(flex)和yacc(bison)写的简单计算器

Lex文件如下: %{#include "cal.tab.h"%}%option noyywrapinteger      [0-9]+dreal        ([0-9]*"."[0-9]+)ereal        ([0-9]*"."[0-9]+[EedD][+-]?[0-9]+)real         {dreal}|{ereal}nl           /nplus        

P2P 研究 思考 4336

编译原理 if-else条件语句的翻译(Java)

1)简洁的用户使用界面 2)可以实现if-else和if的循环嵌套 3)具备一定的检错能力 4)用LR分析方法实现分析 5)不过循环体中只能是一条赋值语句

Windows下安装lex(flex)与yacc(bison)

上完第一节编译原理,Mr李要求这周自己探索一下lex和yacc这两个工具。 查了一下lex与yacc是两个在Unix下的分别作词法分析和语法分析的工具,都说很强大。而他俩在linux下又有对应的东西叫flexbison。虽然硬盘上装了ubuntu但是不怎么用,linux是自带这两个工具的。但是平时还是用windows比较多,当让希望在windows上用这两个东西了。已经有在windows上用c...

XiaoPANGXia的专栏 1万+

flexbison实现小型编译器生成中间代码源程序.zip

···flexbison ····实现小型编译器 ···最终生成中间代码--四元式 ···可以实现if语句、for循环语句、while语句、变量声明和赋值语句的翻译

[编译原理]lexbison实现逻辑表达式求值以及短路计算次数统计

内容:逻辑表达式的求值工具 输入一个包含数值的逻辑表达式,输出计算其真值,和因短路操作而跳过的数值比较的次数。输出格式为Output: [true or false], [次数]。注意,逻辑表达式的计算符合短路算法。其中,!计入逻辑运算次数,而 == 或 != 只用于非布尔型的数值比较。例如: 输入:3 == 2 输出:Output: false, 0 输入:3 > 2 输出:Output: true, 0 输入:3 > 2 && 10 > 1 输出:O...

Joseph115的博客 1802

手把手教程-lex与yacc/flexbison入门(一)(使用windows环境)

前言 1.文章诞生的契机 在计算机学习中,我们有时可能会想到自制一门属于自己的编程语言,此时选择lex与yacc来生成词法分析器与语法分析器是非常不错的选择。然而,这两个工具虽然用起来简单,但对于新手来说,入门还有着些许的难度。 入门的难度通常不是因为工具的复杂,而是因为教程有些难懂。在大多数教程作者眼里,想要自制一个语言的必然不会是初学者,毕竟新手们还在被C和JAVA等语言搞得晕头转向。这导致大多数lex与yacc教程都是面向进阶选手,内容“点到为止”,并心照不宣地省略了一些“常识”。导致内容在我等这般新

weixin_44007632的博客 7万+

编译原理—LexBison实现计算器

calc.lex文件 %{ /* * 一个简单计算器的Lex词法文件 */ #include #include void yyerror(char*); /* #include "calc.tab.h" */ %} %% /* a-z为变量 */ [a-z] { yylval =

LY_624的专栏 4198

lex && yacc && bison && flex 配置的问题

关于yacc 和 lex 的配置,我选用的是bison 和 flex 。 关于unxutils 的配置参考以下文章: 第一篇有讲解yacc、bisonlex、flex的一些共同点,然后给出解决方案。 https://blog.csdn.net/bedusing/article/details/5409495 第二篇可以看成第一篇的补充,如果配置时有什么错误的话,基本上参考第二篇就可以解决。 https://www.freesion.com/article/5374631329/ ...

xiaojin_hhhc的博客 353

LexBison实现简单的计算器

运用LexBison实现一个简单的命令行计算器,支持基本的四则运算(加、减、乘、除),并允许使用括号来改变运算优先级。用户可以在命令行输入一个算术表达式,程序会计算该表达式的值并输出结果。打开终端,输入以下命令来安装 Bison(通常同时也会安装 Flex,它是 Lex 的 GNU 版本)

2302_77871725的博客 363

lex,yacc(flex,bison)与MFC结合起来使用!

近来开始用lexbison来写一些东东,这两者结合起来使用是相当的方便。用lexbison做完核心的分析处理之后,想必大家都会把这些嵌入到自己的工程里面,和其他的功能结合起来。但是,往往此时会出现许多的错误。       lex,bison默认生成的都是C的源程序,而且二者都有自己的语法规则。 有时会与VC有些冲突,但是,只要修改部分定义之后这些问题都是可以解决的。1,yyerror()函数,

P2P 研究 思考 6104

【编译原理】解析器开发利器:LEX、FLEX、YACC和BISON

LEX和FLEX用于生成词法分析器,通过正则表达式将输入文本分解为令牌;YACC和BISON则用于生成语法分析器,基于上下文无关文法分析令牌结构。它们常配合使用,如FLEX+BISON组合,可构建编译器/解释器的完整前端处理流程。FLEXBISON分别作为LEX和YACC的改进版本,提供更好的性能和扩展功能。

Joy T的博客 606

lex yacc flex bison

简介 lex与yacc是两个在Unix下的分别作词法分析和语法分析的工具, Linux对应flexbison。 Yacc 与 Lex 快速入门 flexbison的安装和使用 Windows下安装lex(flex)与yacc(bison)

嵌入式技术 284

使用Bison和Flex(Windows下的基于GNU开源的Yacc和Lex

听说Yacc很久了,今天下下来试了一下,下载地址httpwww.monmouth.com~wstreettlex-yacclex-yacc.html 是gnu的开源项目,用C实现的,有源码,并且基于Windows的注意,除了下bison.exe, flex.exe还要下载bison.simple文件并将其与bison.exe放于同一目录下,下面进行简单的测试:1. 在放置bison.exe的目

Akerlis的专栏 6084

Lex+YACC or Flex+Bison

1.简介 只要你在Unix环境中写过程序,你必定会邂逅神秘的Lex&YACC,就如GNU/Linux用户所熟知的Flex&Bison,这里的Flex就是由Vern Paxon实现的一个LexBison则是GNU版本的YACC. 在此我们将统一称呼这些程序为Lex和YACC.新版本的程序是向上兼容的(译注:即兼容老版本),所以你可以用Flex和Bis...

zzhongcy的专栏 3591

Windows环境下Lex与Yacc/FlexBison快速入门指南

上,可以直接体验预配置好的Lex/Yacc环境,无需繁琐的Windows环境配置。平台内置的代码生成功能能快速创建分析器框架,实时预览效果让学习过程更加直观。特别是对初学者而言,跳过环境配置环节能更专注于核心语法规则的学习。:将输入文本分割为有意义的词法单元(token),这是编译器/解释器工作的第一步。比如将"int a=5;"分解为类型标识符、变量名、赋值符和数字。通过$$=$1+$3等语义动作实现运算。MinGW提供gcc编译环境。匹配任意字符(除换行外)最后用gcc编译合并。

SilvermistOwl67的博客 293

在Windows系统中使用vscode配置CMake和win_flex_bison实现LEX和YACC

最近在学校的专业课《编译原理》学习LEX和YACC,在Windows中使用vscode和CMake配置flex&bison

qq_74959300的博客 1062
上一篇: sscanf 函数用法
下一篇: windows下yacc和lex开发环境配置(Parser Generator篇)
chenxiaohua
博客等级 码龄24年 81粉丝 121原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值