前言
前不久,入手了一本《自制编程语言》。这里记录一下我的学习过程和遇到的困难。
1.配置环境
我这里直接用的下载了虚拟机,里面安装的Ubuntu系统。
里面安装的flex和bison。
2.一个小项目
第一章就是做一个计算器,这里作者并没有直接用c语言来进行制作。而是先使用了lex和bison这两个工具进行制作。
lex是自动生成词法分析的工具,可以根据你写的代码,输出词法分析的c语言代码。
至于词法分析器,就是将输入的字符串分割为记号的程序。然后给语法分析器来分析执行相应代码。
%{ #include <stdio.h> #include "y.tab.h" int yywrap(void) { return 1; } %} %% "+" return ADD;//定义加号 "-" return SUB//定义减法 "*" return MUL//定义乘法 "/" return DIV//定义除法 "\n" return CR;//定义换行 ([1-9][0-9]*)|0|([0-9]+\.[0-9]*) { double temp; sscanf(yytext, "%lf", &temp); yylval.double_value = temp; return DOUBLE_LITERAL; }//这个地方用正则进行匹配,返回标记DOUBLE_LITERAL [ \t] ; . { fprintf(stderr, "lexical error.\n"); exit(1); } %%
这里首先执行了#include <stdio.h>导入了c语言的头文件,在下面定义了记号。这里是词法分析器,对你输入的代码进行分析。
比如你输入1+1.应该就是被分割成DOUBLE_LITERAL ADD DOUBLE_LITERAL。
语法分析器
%{ #include <stdio.h> #include <stdlib.h> #define YYDEBUG 1 %} %union { int int_value; double double_value; } %token <double_value> DOUBLE_LITERAL %token ADD SUB MUL DIV CR %type <double_value> expression term primary_expression %% line_list : line | line_list line ; line : expression CR { printf(">>%lf\n", $1); } expression : term | expression ADD term { $$ = $1 + $3; } | expression SUB term { $$ = $1 - $3; } ; term : primary_expression | term MUL primary_expression { $$ = $1 * $3; } | term DIV primary_expression { $$ = $1 / $3; } ; primary_expression : DOUBLE_LITERAL ; %% int yyerror(char const *str) { extern char *yytext; fprintf(stderr, "parser error near %s\n", yytext); return 0; } int main(void) { extern int yyparse(void); extern FILE *yyin; yyin = stdin; if (yyparse()) { fprintf(stderr, "Error ! Error ! Error !\n"); exit(1); } }
这里对语法进行分析,对开始的词法分析器传过来的进行匹配,并执行相应的操作。比如lex的词法分析器传过来一个1+1.被分解成DOUBLE_LITERAL ADD DOUBLE_LITERAL。在这里1先匹配到primary_expression。在又由primary_expression匹配到term.再匹配到
expression。+则没有匹配到任何东西,就是ADD。此时变成了expression ADD 。1再传进来就匹配到了expression ADD term。从而执行 $$ = $1 + $3;这里的$1对应的是1,$2对应是+,$3对应的也是1.$$就是最终的值。
编译项目
yacc -dv mycalc.y lex mycalc.l cc -o mycalc y.tab.c lex.yy.c
这三个命令进行编译
运行
最激动人心的地方到了,运行!!!
运行成功!!!
学习交流群342096685