创建一门新的编程语言-Flex&Bison教程-(2)-加减乘除

上一篇基本介绍了一些知识,那么现在我们就尝试做一个简单的计算器

首先先写bison文件

test2yy.y

%{
  #include 
  using namespace std;
  int yylex();  //只是一个声明
  int yyerror(const char *); //必须要有
%}
%token  Number
%type  exp
%union {
  double dv;
}
%left '+' '-'
%left '*' '/'
%%

main : main exp '\n' { cout << "Result : " << $2 << endl; }
     | 
     ;

exp  : exp '+' exp  { $$ = $1 + $3 }
     | exp '-' exp  { $$ = $1 - $3 }
     | exp '*' exp  { $$ = $1 * $3 }
     | exp '/' exp  { $$ = $1 / $3 }
     | '(' exp ')'  { $$ = $2 }
     | Number       { $$ = $1 }
     ;
  
%%

int yyerror(const char *emseg)
{
	cout << "Error: " << emseg << endl;
}

int main()
{
  yyparse();
}


在这里我们需要关注一些事情

bison默认第一个表达式(文中的main)为默认表达式,意思是程序执行时处理的表达式,而其他的(文中的exp)则作为辅助,所以你不必一定要命名它为main

%left的作用是规定左优先,因为加减乘除中的乘除需要先运算,在有多个%left的情况下,越下优先级越高

什么意思?假如有

....
%left 'a' 'b'
%left 'c'
%left 'd'
....
那么当遇到这串东西的时候:

a c b d

首先d被处理,然后是c,a和b优先级相同,按先后处理

那么,既然有左优先,那就肯定还有右优先

%right

右优先怎么用呢?看这两个例子:

5+2*4-1/3

a = b = c = d

上面的是一个算式,算式是要从左到右算的,因此是左优先

下面是一个赋值语句,需要从右边赋值到左边,那么我们就可以

%right '='


继续看,我们又发现了$$这个新变量,它代表的是当前表达式的值,所以我们要告诉bison这个表达式的类型是什么,于是便有了上面的%type exp

实际上

%token Number

%token Number

%type Number

等价


好了,让我们来看新的flex文件

test2ll.l

%{
  #include 
  #include "test2yy.h"  //由bison生成
  extern int yyerror(const char *);
  using namespace std;
%}
%%
[0-9]+         { yylval.dv = strtod(yytext,0); return Number; }  //无小数点
[0-9]+\.[0-9]+ { yylval.dv = strtod(yytext,0); return Number; }  //有小数点
[)(+*-/\n]       { return *yytext; } //直接返回字符为符号
[ \t]          ; //忽略空格         
%%
int yywrap()
{
  return 1;
}

这里和上一篇比没有什么差别,就不说了


bison -d -otest2yy.c test2yy.y
flex -otest2ll.c test2ll.l
g++ test2*.c -otest2
./test2

随便输入点算式,是不是成功了?


(2)-加减乘除 结束



你可能感兴趣的:(Flex&Bison教程)