Last active
November 25, 2018 12:02
-
-
Save nomunomu0504/6f47b16ad5c460fd70d4b6a4b51edc6f to your computer and use it in GitHub Desktop.
bison, flexを使ったパーサー
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
%{ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
// yacc header | |
#include "y.tab.h" | |
// myfunction header | |
#include "myFunction.h" | |
map<string, double> varStack; | |
extern "C" int yywrap( void ){ return 1 ; } | |
%} | |
/* 優先順位順に記述(上: 優先度高, 下: 優先度低) */ | |
%% | |
" " {} | |
"\n" return CR ; | |
"(" return SBK ; | |
")" return EBK ; | |
"++" return INC ; | |
"--" return DEC ; | |
"*" return MUL ; | |
"/" return DIV ; | |
"%" return SUR ; | |
"+" return ADD ; | |
"-" return SUB ; | |
"<<" return LEFT_SHIFT ; | |
">>" return RIGHT_SHIFT ; | |
"<" return LEFT_CLS ; | |
">" return RIGHT_CLS ; | |
"<=" return LEFT_CLS_EQ ; | |
">=" return RIGHT_CLS_EQ ; | |
"==" return EQ_EQ ; | |
"!=" return NOT_EQ ; | |
"=" return EQ ; | |
"+=" return ADD_EQ ; | |
"-=" return SUB_EQ ; | |
"*=" return MUL_EQ ; | |
"/=" return DIV_EQ ; | |
"%=" return SUR_EQ ; | |
[0-9]+ { | |
yylval.str = new struct number; | |
yylval.str->type = T_INT; | |
yylval.str->val = atof(yytext); | |
return NUMBER; | |
} | |
[0-9]+\.[0-9]+ { | |
yylval.str = new struct number; | |
yylval.str->type = T_DOUBLE; | |
yylval.str->val = atof(yytext); | |
return NUMBER; | |
} | |
[_a-zA-Z]*[_a-zA-Z0-9]+ { | |
yylval.str = new struct number; | |
yylval.str->type = T_STR; | |
// yylval.str->sval = yytext; | |
// memcpy(yylval.str->sval, yytext); | |
memcpy(yylval.str->sval, yytext, strlen(yytext)+1); | |
return CHARACTER; | |
} | |
%% |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
%{ | |
#include "myFunction.h" | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <iostream> | |
#include <map> | |
using namespace std; | |
// map<char*, double> varStack; | |
// yaccが定義する内部関数のプロトタイプ宣言 | |
extern int yyerror( const char* ) ; | |
extern int yyparse( void ) ; | |
extern int yylex( void ) ; | |
extern char* yytext ; | |
extern FILE* yyin ; | |
%} | |
%union { | |
struct number* str; | |
} | |
%token <str> NUMBER | |
%token <str> CHARACTER | |
%token CR | |
%token SBK EBK | |
%token INC DEC | |
%token MUL DIV SUR | |
%token ADD SUB | |
%token LEFT_SHIFT RIGHT_SHIFT | |
%token LEFT_CLS RIGHT_CLS LEFT_CLS_EQ RIGHT_CLS_EQ | |
%token EQ_EQ NOT_EQ | |
%token EQ ADD_EQ SUB_EQ MUL_EQ DIV_EQ SUR_EQ | |
%type <str> expr term factor | |
%left LEFT_SHIFT RIGHT_SHIFT | |
%left LEFT_CLS RIGHT_CLS LEFT_CLS_EQ RIGHT_CLS_EQ EQ_EQ NOT_EQ | |
%right EQ ADD_EQ SUB_EQ MUL_EQ DIV_EQ SUR_EQ | |
%% | |
input : line | |
| input line | |
; | |
line : expr CR { printf(">> %f\n", $1->val) ; } | |
| CR { exit(0) ; } /* 未入力Enterは終了 */ | |
; | |
expr : term { $$ = $1 ; } | |
| expr LEFT_CLS expr { $$ = Comparing($1, $3, LEFT_CLS) ; } | |
| expr RIGHT_CLS expr { $$ = Comparing($1, $3, RIGHT_CLS) ; } | |
| expr LEFT_CLS_EQ expr { $$ = Comparing($1, $3, LEFT_CLS_EQ) ; } | |
| expr RIGHT_CLS_EQ expr { $$ = Comparing($1, $3, RIGHT_CLS_EQ) ; } | |
| expr LEFT_SHIFT expr { $$ = Shiftoperator($1, $3, LEFT_SHIFT) ; } | |
| expr RIGHT_SHIFT expr { $$ = Shiftoperator($1, $3, RIGHT_SHIFT) ; } | |
| expr ADD term { $$ = newVal($1, $3, ADD) ; } | |
| expr SUB term { $$ = newVal($1, $3, SUB) ; } | |
; | |
term : factor { $$ = $1 ; } | |
| term MUL factor { $$ = newVal($1, $3, MUL) ; } | |
| term DIV factor { $$ = newVal($1, $3, DIV) ; } | |
| term SUR factor { $$ = newVal($1, $3, SUR) ; } | |
; | |
factor : NUMBER { $$ = $1 ; } | |
| CHARACTER { $$ = Variant($1, NULL) ; } | |
| CHARACTER ADD_EQ expr { $$ = Substitution($1, $3, ADD_EQ) ; } | |
| CHARACTER SUB_EQ expr { $$ = Substitution($1, $3, SUB_EQ) ; } | |
| CHARACTER MUL_EQ expr { $$ = Substitution($1, $3, MUL_EQ) ; } | |
| CHARACTER DIV_EQ expr { $$ = Substitution($1, $3, DIV_EQ) ; } | |
| CHARACTER SUR_EQ expr { $$ = Substitution($1, $3, SUR_EQ) ; } | |
| CHARACTER EQ expr { $$ = Variant($1, $3) ; } | |
| INC CHARACTER { $$ = front_incdec($2, INC) ; } | |
| DEC CHARACTER { $$ = front_incdec($2, DEC) ; } | |
| CHARACTER INC { $$ = back_incdec($1, INC) ; } | |
| CHARACTER DEC { $$ = back_incdec($1, DEC) ; } | |
| SBK expr EBK { $$ = $2 ; } | |
; | |
%% | |
// 補助関数の定義 | |
int yyerror( char const* str ) | |
{ | |
fprintf( stderr , "parser error near %s\n" , yytext ) ; | |
return 0 ; | |
} | |
int main( void ) | |
{ | |
yyin = stdin ; | |
if ( yyparse() ) { | |
fprintf( stderr , "Error ! Error ! Error !\n" ) ; | |
exit( 1 ) ; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 最終ターゲット | |
mycalc: y.tab.o lex.yy.o myFunction.o | |
g++ -o mycalc y.tab.o lex.yy.o myFunction.o | |
# 構文解析処理 | |
y.tab.o: calculator.y | |
bison -dy calculator.y # -dy : yacc互換 | |
g++ -c y.tab.c | |
# 字句解析処理 | |
lex.yy.o: calculator.l | |
flex -l calculator.l | |
g++ -c lex.yy.c | |
myFunction.o: myFunction.c | |
g++ -c myFunction.c | |
# clean:; rm mycalc y.tab.c y.tab.h lex.yy.cc *.o | |
clean:; rm mycalc y.tab.c y.tab.h lex.yy.c *.o |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <iostream> | |
#include <string> | |
#include <map> | |
#include "myFunction.h" | |
#include <vector> | |
bool isVarFound (struct number* data) { | |
if (varStack.find(data->sval) != varStack.end()) { | |
// 存在する | |
return true; | |
} else { | |
// 存在しない | |
return false; | |
} | |
} | |
struct number* newVal (struct number* p1, struct number* p2, int op) { | |
struct number* res = new struct number ; | |
switch (op) { | |
case ADD: { | |
res->val = p1->val + p2->val; | |
break; | |
} | |
case SUB: { | |
res->val = p1->val - p2->val; | |
break; | |
} | |
case MUL: { | |
res->val = p1->val * p2->val; | |
break; | |
} | |
case DIV: { | |
res->val = p1->val / p2->val; | |
break; | |
} | |
case SUR: { | |
res->val = (int)p1->val % (int)p2->val; | |
break; | |
} | |
default: break; | |
} | |
if ( (p1->type != T_DOUBLE) && (p2->type != T_DOUBLE) ) { | |
res->val = (double)((int)res->val); | |
} | |
return res; | |
} | |
struct number* Variant(struct number* name, struct number* value) { | |
struct number* res = new struct number; | |
// 代入式か | |
if (value != NULL) | |
{ | |
varStack.insert(make_pair(name->sval, value->val)); | |
} | |
// 変数は登録されているか | |
if (isVarFound(name)) | |
{ // 登録されている | |
res->type = T_DOUBLE; | |
res->val = varStack[name->sval]; | |
} | |
else | |
{ // 登録されていない | |
fprintf(stderr, "%s is undefined.\n", name->sval); | |
exit(1); | |
} | |
return res; | |
} | |
struct number* back_incdec (struct number* variant, int op) { | |
// インクリメント前の値保持 | |
double before_inc_val = 0.0; | |
// 表示用構造体を定義 | |
struct number* res = new struct number; | |
res->type = T_DOUBLE; | |
if ( isVarFound(variant) ) | |
{ | |
before_inc_val = varStack[variant->sval]; | |
res->val = before_inc_val; | |
double tmp = before_inc_val; | |
// 変数スタックから削除 | |
varStack.erase(variant->sval); | |
if (INC == op) { | |
tmp = tmp + 1; | |
} else if (DEC == op) { | |
tmp = tmp - 1; | |
} | |
varStack.insert(make_pair(variant->sval, tmp)); | |
} | |
else | |
{ | |
fprintf(stderr, "%s is undefined\n", variant->sval); | |
exit(1); | |
} | |
return res; | |
} | |
struct number* front_incdec (struct number* variant, int op) { | |
// 表示用構造体を定義 | |
struct number* res = new struct number; | |
res->type = T_DOUBLE; | |
if ( isVarFound(variant) ) | |
{ | |
double tmp = varStack[variant->sval]; | |
// 変数スタックから削除 | |
varStack.erase(variant->sval); | |
if (INC == op) { | |
tmp = tmp + 1; | |
} else if (DEC == op) { | |
tmp = tmp - 1; | |
} | |
varStack.insert(make_pair(variant->sval, tmp)); | |
res->val = tmp; | |
} | |
else | |
{ | |
fprintf(stderr, "%s is undefined\n", variant->sval); | |
exit(1); | |
} | |
return res; | |
} | |
struct number* Substitution (struct number* variant, struct number* num, int op) { | |
struct number* res = new struct number; | |
res->type = T_DOUBLE; | |
double before_val = 0; | |
if (isVarFound(variant)) { | |
before_val = varStack[variant->sval]; | |
} else { | |
fprintf(stderr, "%s is undefined.\n", variant->sval); | |
exit(1); | |
} | |
double effect_num = num->val; | |
switch (op) { | |
case ADD_EQ: | |
res->val = before_val + effect_num; | |
break; | |
case SUB_EQ: | |
res->val = before_val - effect_num; | |
break; | |
case MUL_EQ: | |
res->val = before_val * effect_num; | |
break; | |
case DIV_EQ: | |
res->val = before_val / effect_num; | |
break; | |
case SUR_EQ: | |
res->val = (int)before_val % (int)effect_num; | |
break; | |
default: break; | |
} | |
varStack.erase(variant->sval); | |
varStack.insert(make_pair(variant->sval, res->val)); | |
return res; | |
} | |
struct number* Shiftoperator (struct number* source, struct number* target, int op) { | |
// ローカル関数参照用変数 | |
static int s_op; | |
s_op = op; | |
// 計算用ローカル関数を定義 | |
struct { | |
double operator()(double p0, double p1) { | |
double res = 0; | |
switch (s_op) { | |
case LEFT_SHIFT: { | |
// printf("LEFT\n"); | |
res = (int)p0 << (int)p1; | |
break; | |
} | |
case RIGHT_SHIFT: { | |
// printf("RIGHT\n"); | |
res = (int)p0 >> (int)p1; | |
break; | |
} | |
default: { | |
// printf("DEFAULT\n"); | |
break; | |
} | |
} | |
return res; | |
}; | |
} Calc; | |
// 結果格納構造体の定義 | |
struct number* res = new struct number; | |
res->type = T_DOUBLE; | |
// シフトされる構造体が文字列以外 | |
if (source->type != T_STR) | |
{ | |
// シフトする分の構造体が文字列以外 | |
if (target->type != T_STR) | |
{ | |
// シフト演算 | |
res->val = Calc(source->val, target->val); | |
} | |
else | |
{ | |
if (isVarFound(target)) | |
{ | |
// シフトする分の変数取得 | |
double target_val = varStack[target->sval]; | |
// シフト演算 | |
res->val = Calc(source->val, target_val); | |
} | |
else | |
{ | |
// 変数未定義ならエラーで終了 | |
fprintf(stderr, "%s is undefined.\n", target->sval); | |
exit(1); | |
} | |
} | |
} | |
else | |
{ | |
double source_val = 0.0; | |
// シフトする変数が存在するか | |
if (isVarFound(source)) | |
{ | |
// シフトされる値を格納 | |
source_val = varStack[source->sval]; | |
} | |
else | |
{ | |
// 変数未定義ならエラーで終了 | |
fprintf(stderr, "%s is undefined.\n", source->sval); | |
exit(1); | |
} | |
// シフト量構造体が文字列以外 | |
if (target->type != T_STR) | |
{ | |
// シフト演算 | |
res->val = Calc(source_val, target->val); | |
} | |
else | |
{ | |
// シフトされる変数が存在するか | |
if (isVarFound(target)) | |
{ | |
// 変数に格納してシフト演算 | |
double target_val = varStack[target->sval]; | |
res->val = Calc(source_val, target_val); | |
} | |
else | |
{ | |
// 変数が存在しなかったらエラーで終了 | |
fprintf(stderr, "%s is undefined.\n", target->sval); | |
exit(1); | |
} | |
} | |
} | |
return res; | |
} | |
struct number* Comparing (struct number* p1, struct number* p2, int op) { | |
struct number* res = new struct number; | |
res->type = T_BOOL; | |
switch (op) { | |
case LEFT_CLS: | |
res->val = p1->val < p2->val; | |
break; | |
case RIGHT_CLS: | |
res->val = p1->val > p2->val; | |
break; | |
case LEFT_CLS_EQ: | |
res->val = p1->val <= p2->val; | |
break; | |
case RIGHT_CLS_EQ: | |
res->val = p1->val >= p2->val; | |
break; | |
default: break; | |
} | |
return res; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef MYFUNCTION_H | |
#define MYFUNCTION_H | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <iostream> | |
#include <map> | |
// トークン識別番号利用のため include | |
#include "y.tab.h" | |
using namespace std; | |
// 変数用スタック | |
extern map<string, double> varStack; | |
// 変数の種別一覧 | |
enum numberType { | |
T_NULL = 0, | |
T_INT, | |
T_DOUBLE, | |
T_STR, | |
T_BOOL | |
} ; | |
// 入力用構造体 | |
struct number { | |
enum numberType type; | |
union { | |
char sval[100]; | |
double val; | |
} ; | |
} ; | |
bool isVarFound (struct number* data) ; | |
struct number* newVal (struct number* p1, struct number* p2, int op) ; | |
struct number* Variant (struct number* name, struct number* value) ; | |
struct number* back_incdec (struct number* variant, int op) ; | |
struct number* front_incdec (struct number* variant, int op) ; | |
struct number* Substitution (struct number* variant, struct number* num, int op) ; | |
struct number* Shiftoperator (struct number* source, struct number* target, int op) ; | |
struct number* Comparing (struct number* p1, struct number* p2, int op) ; | |
#endif /* end of include guard: MYFUNCTION_H */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment