您尚未登录。

楼主 #1 2018-05-09 21:22:47

bunny
会员
注册时间: 2020-05-23
已发帖子: 154
积分: 154

一步一步写一个超级简陋的C编译器——flex&yacc运算化简

先上flex文件:

%{
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "simple_compiler.tab.h"
#define YY_SKIP_YYWRAP
extern int yylval;
int yylex(void);

static int var_save(char* v) {
	char* p = (char*)malloc(32);
	sprintf(p, "%s", v);
	return (int)p;
}

static int new_var(void) {
	static int index = 0;
	char* p = (char*)malloc(16);
	sprintf(p, "r_%d", index++);
	return (int)p;
}

static int function_paras(int para0, int para1) {
	char* p = (char*)malloc(128);
	sprintf(p, "%s, %s",  (const char*)para0, (const char*)para1);
	free((char*)para0);
	free((char*)para1);
	return (int)p;
}

static int function_call(int func) {
	char* p = (char*)malloc(256);
	sprintf(p, "%s()",  (const char*)func);
	free((char*)func);
	return (int)p;
}

static int function_callp(int func, int paras) {
	char* p = (char*)malloc(256);
	sprintf(p, "%s(%s)",  (const char*)func, (const char*)paras);
	free((char*)func);
	free((char*)paras);
	return (int)p;
}

%}

num [0-9]+
hex "0x"[0-9a-fA-F]+
bin "0b"[01]+
_var [_a-zA-z]+[_a-zA-z0-9]*

_equal "="
_lp_s "("
_rp_s ")"
_split1 ","
_split2 ";"

_plus "+"
_minus "-"
_mul "*"
_divide "/"
_mod "%%"
_shift_r ">>"
_shift_l "<<"
_not "~"
_more ">"
_less "<"
_more_equal ">="
_less_equal "<="
_equal_equal "=="
_not_equal "!="

_next_line [\n]+
space [ \t]+

%%
{num} {
	yylval = var_save(yytext);
	return var;
}
{hex} {
	yylval = var_save(yytext);
	return var;
}
{bin} {
	yylval = var_save(yytext);
	return var;
}
{_var} {
	yylval = var_save(yytext);
	return var;
}

{_lp_s} {
	return lp_s;
}
{_rp_s} {
	return rp_s;
}

{_split1} {
	return split1;
}
{_split2} {
	return split2;
}

{_plus} {
	return plus;
}
{_minus} {
	return minus;
}
{_mul} {
	return mul;
}
{_divide} {
	return divide;
}
{_mod} {
	return mod;
}
{_shift_r} {
	return shift_r;
}
{_shift_l} {
	return shift_l;
}
{_not} {
	return not;
}
{_more} {
	return more;
}
{_less} {
	return less;
}
{_more_equal} {
	return more_equal;
}
{_less_equal} {
	return less_equal;
}
{_equal_equal} {
	return equal_equal;
}
{_not_equal} {
	return not_equal;
}

{_equal} {
	return equal;
}

{_next_line} {
	return next_line;
}
{space} {
}
. {
}

%%

再上yacc文件:

%{
#include <stdio.h>
#define YYSTYPE int
#include "lex.yy.c"
int yyparse(void);
void yyerror(char* s);
%}

%token dig var lp_s rp_s plus minus mul divide mod shift_r shift_l not more less more_equal less_equal equal_equal not_equal equal split1 split2 next_line

%%

code_lines: code_lines code_line next_line {}
	| code_line next_line {}
	;
code_line: code split2 {}
	;
code: var_set {}
	| var_level5 {}
	;
var_set: var equal var_level5 {printf("%s = %s;\n", (char*)$1, (char*)$3); free((char*)$1); free((char*)$3);}
	;
var_level5: var_level5 more var_level4 {$$ = new_var(); printf("%s = %s > %s;\n", (char*)$$, (char*)$1, (char*)$3); free((char*)$1); free((char*)$3);}
	| var_level5 less var_level4 {$$ = new_var(); printf("%s = %s < %s;\n", (char*)$$, (char*)$1, (char*)$3); free((char*)$1); free((char*)$3);}
	| var_level5 more_equal var_level4 {$$ = new_var(); printf("%s = %s >= %s;\n", (char*)$$, (char*)$1, (char*)$3); free((char*)$1); free((char*)$3);}
	| var_level5 less_equal var_level4 {$$ = new_var(); printf("%s = %s <= %s;\n", (char*)$$, (char*)$1, (char*)$3); free((char*)$1); free((char*)$3);}
	| var_level5 equal_equal var_level4 {$$ = new_var(); printf("%s = %s == %s;\n", (char*)$$, (char*)$1, (char*)$3); free((char*)$1); free((char*)$3);}
	| var_level5 not_equal var_level4 {$$ = new_var(); printf("%s = %s != %s;\n", (char*)$$, (char*)$1, (char*)$3); free((char*)$1); free((char*)$3);}
	| var_level4 {$$ = $1;}
	;
var_level4: var_level4 shift_r var_level3 {$$ = new_var(); printf("%s = %s >> %s;\n", (char*)$$, (char*)$1, (char*)$3); free((char*)$1); free((char*)$3);}
	| var_level4 shift_l var_level3 {$$ = new_var(); printf("%s = %s << %s;\n", (char*)$$, (char*)$1, (char*)$3); free((char*)$1); free((char*)$3);}
	| var_level3 {$$ = $1;}
	;
var_level3: var_level3 plus var_level2 {$$ = new_var(); printf("%s = %s + %s;\n", (char*)$$, (char*)$1, (char*)$3); free((char*)$1); free((char*)$3);}
	| var_level3 minus var_level2 {$$ = new_var(); printf("%s = %s - %s;\n", (char*)$$, (char*)$1, (char*)$3); free((char*)$1); free((char*)$3);}
	| var_level2 {$$ = $1;}
	;
var_level2: var_level2 mul var_level1 {$$ = new_var(); printf("%s = %s * %s;\n", (char*)$$, (char*)$1, (char*)$3); free((char*)$1); free((char*)$3);}
    | var_level2 divide var_level1 {$$ = new_var(); printf("%s = %s / %s;\n", (char*)$$, (char*)$1, (char*)$3); free((char*)$1); free((char*)$3);}
	| var_level2 mod var_level1 {$$ = new_var(); printf("%s = %s %% %s;\n", (char*)$$, (char*)$1, (char*)$3); free((char*)$1); free((char*)$3);}
    | var_level1 {$$ = $1;}
	;
var_level1: var {$$ = $1;}
	| not var {$$ = new_var(); printf("%s = ~%s;\n", (char*)$$, (char*)$1); free((char*)$1);}
	| func_call {$$ = $1;}
	| not func_call {$$ = new_var(); printf("%s = ~%s;\n", (char*)$$, (char*)$1); free((char*)$1);}
	| lp_s var_level5 rp_s {$$ = $2;}
	;
func_call: var lp_s rp_s {$$ = new_var(); printf("%s = %s;\n", (char*)$$, (char*)function_call($1));}
	| var lp_s func_para rp_s {$$ = new_var(); printf("%s = %s;\n", (char*)$$, (char*)function_callp($1, $3));}
	;
func_para: var_level5 {$$ = $1;}
	| func_para split1 var_level5 {$$ = function_paras($1, $3);}
	;
%%
int main(int argc, char *argv[]) {
	return yyparse();
}

int yywrap(void) {
	return 1;
}

void yyerror(char* s) {
	printf("error: %s\n", s);
}

转换成c文件
bison.exe -d simple_compiler.y
flex simple_compiler.l

编译成exe,测试:
输入文件:
TIM20180509212140.png
输出文件:
TIM20180509212150.png

离线

#2 2019-11-11 23:09:25

演技担当黄晓明
会员
注册时间: 2017-10-17
已发帖子: 184
积分: 122.5

Re: 一步一步写一个超级简陋的C编译器——flex&yacc运算化简

留下记号以后再看

离线

#3 2019-11-11 23:13:05

daydayup
会员
注册时间: 2017-10-09
已发帖子: 343
积分: 343

Re: 一步一步写一个超级简陋的C编译器——flex&yacc运算化简

居然有此等好帖,相见恨晚唉

离线

#4 2019-11-12 09:19:59

kekemuyu
会员
注册时间: 2018-12-13
已发帖子: 849
积分: 720

Re: 一步一步写一个超级简陋的C编译器——flex&yacc运算化简

很长时间没有看编译原理了,老是中断。

离线

#5 2019-11-12 09:29:48

明月心惜
会员
注册时间: 2018-08-19
已发帖子: 24
积分: 29

Re: 一步一步写一个超级简陋的C编译器——flex&yacc运算化简

离线

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn