Skip to content

Instantly share code, notes, and snippets.

@nomunomu0504
Last active November 25, 2018 12:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nomunomu0504/6f47b16ad5c460fd70d4b6a4b51edc6f to your computer and use it in GitHub Desktop.
Save nomunomu0504/6f47b16ad5c460fd70d4b6a4b51edc6f to your computer and use it in GitHub Desktop.
bison, flexを使ったパーサー
%{
#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;
}
%%
%{
#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 ) ;
}
}
# 最終ターゲット
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
#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;
}
#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