用lex和yacc实现的计算器

代码

// calc.lex

 

%{

#include <stdio.h>
#define YYSTYPE    double
#include "calc_y.h"

#define PRINT    printf("%s", yytext)

%}

num        [0-9]
real    {num}+|{num}+"."{num}+
add        "+"
sub        "-"
mul        "*"
div        "/"
eq        "="
lb        "("
rb        ")"
sin        "sin"
cos        "cos"
ln        "ln"
log10    "log10"
tanh    "tanh"
sqrt    "sqrt"
exp        "exp"
abs        "abs"
lr        [/r/n]
space    [ /t]
quit    [q]

%%

{real}    { PRINT; yylval = strtod(yytext, NULL); return REAL; }
{add}    { PRINT; return ADD; }
{sub}    { PRINT; return SUB; }
{mul}    { PRINT; return MUL; }
{div}    { PRINT; return DIV; }
{eq}    { PRINT; return EQ; }
{lb}    { PRINT; return LB; }
{rb}    { PRINT; return RB; }
{sin}    { PRINT; return SIN; }
{cos}    { PRINT; return COS; }
{ln}    { PRINT; return LN; }
{log10}    { PRINT; return LOG10; }
{tanh}    { PRINT; return TANH; }
{sqrt}    { PRINT; return SQRT; }
{exp}    { PRINT; return EXP; }
{abs}    { PRINT; return ABS; }
{lr}    { return LR; }
{quit}    { exit(0); }
{space}    {}
.        {}

%%

int yywrap()
{
    return 1;
}

 

// calc.y

 

%{

#include <stdio.h>
#include <math.h>

#define YYSTYPE    double

extern int yylineno;

%}

%token     REAL EQ LR
%right    SIN COS LN LOG10 TANH SQRT EXP ABS
%left    ADD SUB
%left    MUL DIV
%left    RB
%right    LB
%right    UARY

%%

input:
    |    input line
;

line:    LR
    |    exp LR                { printf("=%f/n", $1); }   
;
   
exp:    REAL                { $$ = $1; }   
    |    exp    ADD exp            { $$ = $1 + $3; }
    |    exp    SUB exp            { $$ = $1 - $3; }
    |    exp    MUL exp            { $$ = $1 * $3; }
    |    exp    DIV exp            { $$ = $1 / $3; }
    |    ADD    exp    %prec UARY    { $$ = $2; }
    |    SUB    exp    %prec UARY    { $$ = -$2; }
    |    LB    exp    RB            { $$ = $2; }
    |    SIN LB exp RB        { $$ = sin($3); }
    |    COS LB exp RB        { $$ = cos($3); }
    |    LN LB exp RB        { $$ = log($3); }
    |    LOG10 LB exp RB        { $$ = log10($3); }
    |    TANH LB exp RB        { $$ = tanh($3); }
    |    SQRT LB exp RB        { $$ = sqrt($3); }
    |    EXP LB exp RB        { $$ = exp($3); }
    |    ABS LB exp RB        { $$ = fabs($3); }
;

%%

int main()
{
    yyparse();
    return 0;
}

int yyerror(char *msg)
{
    printf("error: %s in line %d/n", msg, yylineno);
    return 0;
}

// makefile

 

all:calc_y.c calc_l.c
    gcc -g -o calc calc_y.c calc_l.c -lm

calc_l.c:calc.lex calc.y
    flex -o calc_l.c calc.lex

calc_y.c:calc.y
    bison -d -o calc_y.c calc.y
   

clean:
    @rm -f calc *.c *.h
   

// exam.txt

 

10.6/2
3.3*3
10+5
8-3
4*2
1+3*2-5
-1+5
+1+5
5*(3-1)+6
sin(3.1415926/2)
cos(0)
abs(-10.5)
sqrt(16)
ln(5)
log10(10)
exp(5)

 

// 使用方法 1

$ ./calc < exam.txt

 

// 是用方法2

$ ./calc

1+3

1+3=4

q

$

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是使用 lexyacc 实现计算器的基本步骤: 1. 定义词法分析器(Lex)规则:在 Lex 文件中定义正则表达式和相应的动作,用来将输入的字符流分解成一个个 token,并将其传递给 yacc 进行语法分析。 举个例子,可以定义一个正则表达式匹配整数和浮点数: ``` [0-9]+(\.[0-9]+)? { yylval.num = atof(yytext); return NUM; } ``` 其中 `[0-9]+(\.[0-9]+)?` 匹配整数或浮点数,`yylval.num = atof(yytext)` 将匹配到的字符串转换成浮点数并赋值给 `yylval`,`NUM` 是定义的 token 类型。 2. 定义语法分析器(Yacc)规则:在 Yacc 文件中定义文法规则和相应的动作,用来将 token 序列组成的语法树转化为计算结果。 举个例子,可以定义一个简单的四则运算文法规则: ``` expr : expr '+' term { $$ = $1 + $3; } | expr '-' term { $$ = $1 - $3; } | term { $$ = $1; } ; term : term '*' factor { $$ = $1 * $3; } | term '/' factor { $$ = $1 / $3; } | factor { $$ = $1; } ; factor : '(' expr ')' { $$ = $2; } | NUM { $$ = $1; } ; ``` 其中 `expr` 表示表达式,`term` 表示项,`factor` 表示因子,`NUM` 是上面定义的 token 类型。每个文法规则都有相应的动作,例如 `expr : expr '+' term { $$ = $1 + $3; }` 表示计算表达式的值为左侧表达式的值加上右侧项的值。 3. 编写主程序:在主程序中初始化 LexYacc,读入输入并进行分析。 举个例子,可以编写以下主程序: ``` #include "lex.yy.c" #include "y.tab.c" int main() { yyparse(); return 0; } ``` 其中 `yyparse()` 函数会调用 Lex 词法分析器和 Yacc 语法分析器进行计算。 4. 编译运行程序:使用以下命令编译 LexYacc 文件、主程序文件和相关库文件,并运行程序: ``` $ lex lexer.l $ yacc -d parser.y $ gcc -o calculator y.tab.c lex.yy.c main.c -ll $ ./calculator ``` 以上就是使用 LexYacc 实现计算器的基本步骤。需要注意的是,语法分析器(Yacc)规则需要按照正确的优先级和结合性编写,否则会导致计算结果错误。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值