Commit 7b285662 authored by Genki Sakanashi's avatar Genki Sakanashi

initial commit

parents
This diff is collapsed.
#pragma once
#include <map>
#include <list>
#include <string>
#include "Resource.h"
#include "define.h"
#include "Program.h"
#include "Routine.h"
#include "Option.h"
#include "Variable.h"
extern void throw_syntax_error(std::string s);
class Program;
class Routine;
struct Instruction;
struct Variable;
class CodeBlock : Resource{
Program* program;
Routine* routine;
void merge_instruction_list(InstPtrList& xs, InstPtrList& ys);
public:
//OPR, ROT, OUTPUT, INPUTも含めた直前の命令列
//IF文等で分岐した処理フローが合流することがあるのでlistで管理する;
InstPtrList last_instructions;
//直前のOPR, ROT, OUTPUT, INPUT,SET,RESETの順序制御用のIF_BRANCH
//IF文等で分岐した処理フローが合流することがあるのでlistで管理する;
InstPtrList last_cluster_branches;
InstPtrList main_instructions;
//OBREAKに対応するIF_BRANCH(REPEATENDまでの無条件ジャンプ)の命令の集合
// (抜けるREPEATの数-1) -> 命令の集合
std::vector<InstPtrList> break_instructions;
CodeBlock(Program* program, Routine* routine);
void merge_block(CodeBlock* block);
//insに飛ぶようにジャンプ命令(NEXT + IF_BRANCH)を加える.直前の命令がIF_BRANCHの場合は,その飛び先をinsにする
void jump_to(InstPtr ins);
//
void jump_to_next();
//ROT,OPR,OUTPUT,INPUT,SET,RESET後のIF_BRANCHを引数で与えられたcluster_branchに追加する
void add_cluster_branch(InstPtrList& target_cluster_branches, std::string label);
void add_cluster_branch(InstPtrList& target_cluster_branches/* 追加対象のIF_BRANCHのリスト */, std::string label /*直前の命令からの飛び先として使用するlabel,ROT_U_X, L_OUTPUTなど*/, Routine* routine /*命令が所属するルーチン*/);
void add_main_instruction(InstPtr inst);
void cut_branch_chain();
void rot(Variable* varname);
void opr(Variable* varname);
void djmp(Variable* var);
void rot_opr(Variable*, std::string label);
void output();
void input();
void set(std::string flag);
void reset(std::string flag);
void end();
void next(std::string flagname);
void ind_opr(Variable* varname);
void if_statement(std::string if_flag, CodeBlock* if_block, CodeBlock* else_block);
void repeat(long long repeat_num, CodeBlock* block);
void repeat_break(long long num);
void switch_statement(Variable* var, CodeBlock* case0_block, CodeBlock* case1_block, CodeBlock* case2_block);
void call(std::string name);
void func_return();
void flip(std::string name);
};
#include "Generator.h"
Generator& Generator::program_start_to(std::string entry){
this->code << "PROGRAM_START_TO ENTRY@" << entry;
this->ln();
return *this;
}
Generator& Generator::routine_start(std::string routinename){
this->code << "ROUTINE " << routinename << "{";
this->ln();
return *this;
}
Generator& Generator::routine_end(){
this->code << "}";
return *this;
}
Generator& Generator::entry(){
return this->label("ENTRY");
}
Generator& Generator::add_spaces(){
this->code << std::string(2*this->tab_count, ' ');
return *this;
}
Generator& Generator::flag(std::string flagname, int val){
this->code << "FLAG " << val << "/2, " << flagname;
this->ln();
return *this;
}
Generator& Generator::label(std::string labelname){
this->code << labelname << ":";
this->ln();
return *this;
}
Generator& Generator::djmp(std::string varname){
this->label(LABEL_DJMP(varname)).add_spaces();
this->code << "DJMP " << varname;
this->ln();
return *this;
}
Generator& Generator::opr(std::string varname){
this->label(LABEL_OPR(varname)).add_spaces();
this->code << "OPR " << varname;
this->ln();
return *this;
}
Generator& Generator::rot(std::string varname){
this->label(LABEL_ROT(varname)).next(FLAG_REV_OPR_ROT).add_spaces();
this->code << "ROT";
this->ln();
return *this;
}
Generator& Generator::ind_opr(std::string varname){
this->label(LABEL_IND_OPR(varname)).next(FLAG_REV_IND_OPR).add_spaces();
this->code << "IND_OPR " << varname;
this->ln();
return *this;
}
Generator& Generator::rev_opr(){
this->add_spaces();
this->code << "REV OPR";
this->ln();
return *this;
}
Generator& Generator::rev_rot(){
this->add_spaces();
this->code << "REV ROT";
this->ln();
return *this;
}
Generator& Generator::dup(){
this->add_spaces();
this->code << "DUP";
this->ln();
return *this;
}
Generator& Generator::end(){
this->add_spaces();
this->code << "END";
this->ln();
return *this;
}
Generator& Generator::skip(std::string labelname){
this->add_spaces();
this->code << "SKIP " << labelname;
this->ln();
return *this;
}
Generator& Generator::var(std::string varname, std::string val){
this->code << varname << ":" << val;
this->ln();
return *this;
}
Generator& Generator::if_branch(std::string flag, std::string branch){
this->add_spaces();
this->code << "IF " << flag;
this->ln().add_spaces();
this->code << "BRANCH " << branch;
this->ln();
return *this;
}
Generator& Generator::next(std::string flag){
this->add_spaces();
this->code << "NEXT " << flag;
this->ln();
return *this;
}
Generator& Generator::output(){
this->add_spaces();
this->code << "OUTPUT";
this->ln();
return *this;
}
Generator& Generator::input(){
this->add_spaces();
this->code << "INPUT";
this->ln();
return *this;
}
Generator& Generator::rev_output(){
this->add_spaces();
this->code << "REV OUTPUT";
this->ln();
return *this;
}
Generator& Generator::rev_input(){
this->add_spaces();
this->code << "REV INPUT";
this->ln();
return *this;
}
Generator& Generator::jmp(std::string jmp){
this->add_spaces();
this->code << "JMP " << jmp;
this->ln();
return *this;
}
Generator& Generator::rev_jmp(){
this->add_spaces();
this->code << "REV JMP";
this->ln();
return *this;
}
Generator& Generator::indent(){
this->tab_count++;
return *this;
}
Generator& Generator::outdent(){
this->tab_count--;
return *this;
}
Generator& Generator::ln(){
this->code << std::endl;
return *this;
}
Generator& Generator::raw(std::string str){
this->code << str;
return *this;
}
Generator& Generator::unit_call(std::string unit, std::string unit_arg){
this->add_spaces();
this->code << unit;
if(unit_arg.length() > 0){
this->code << " " << unit_arg;
}
this->code << std::endl;
return *this;
}
void Generator::output_code(){
std::cout << this->code.str() << std::endl;
}
#pragma once
#include "define.h"
#include <iostream>
#include <sstream>
#include <string>
class Generator{
int tab_count = 1;
std::stringstream code;
Generator& add_spaces();
public:
Generator& program_start_to(std::string entry);
Generator& routine_start(std::string routinename);
Generator& routine_end();
Generator& entry();
Generator& flag(std::string flagname, int val);
Generator& label(std::string labelname);
Generator& djmp(std::string varname);
Generator& opr(std::string varname);
Generator& rot(std::string varname);
Generator& ind_opr(std::string varname);
Generator& rev_opr();
Generator& rev_rot();
Generator& dup();
Generator& end();
Generator& skip(std::string labelname);
Generator& var(std::string varname, std::string val);
Generator& if_branch(std::string flag, std::string branch);
Generator& next(std::string flag);
Generator& output();
Generator& input();
Generator& rev_output();
Generator& rev_input();
Generator& jmp(std::string jmp);
Generator& rev_jmp();
Generator& indent();
Generator& outdent();
Generator& ln();
Generator& raw(std::string str);
Generator& unit_call(std::string unit, std::string unit_arg);
void output_code();
};
#include "Instruction.h"
Instruction::Instruction(){}
Instruction::Instruction(INS_TYPE type){
this->type = type;
}
InstPtr Instruction::IF_BRANCH(std::string flag){
auto p = new Instruction(INS_TYPE::IF_BRANCH);
p->flag = flag;
return p;
}
InstPtr Instruction::IF_BRANCH_ASSIGNED(std::string flag, InstPtr branch){
auto p = new Instruction(INS_TYPE::IF_BRANCH_ASSIGNED);
p->flag = flag;
p->move_to = branch;
return p;
}
InstPtr Instruction::NEXT(std::string flag){
auto p = new Instruction(INS_TYPE::NEXT);
p->flag = flag;
return p;
}
InstPtr Instruction::SKIP(InstPtr label){
auto p = new Instruction(INS_TYPE::SKIP);
p->move_to = label;
return p;
}
InstPtr Instruction::LABEL(std::string label){
auto p = new Instruction(INS_TYPE::LABEL);
p->label = label;
return p;
}
InstPtr Instruction::JMP(InstPtr jmp){
auto p = new Instruction(INS_TYPE::JMP);
p->move_to = jmp;
return p;
}
InstPtr Instruction::REV_JMP(){
return new Instruction(INS_TYPE::REV_JMP);
}
InstPtr Instruction::INPUT(){
return new Instruction(INS_TYPE::INPUT);
}
InstPtr Instruction::REV_INPUT(){
return new Instruction(INS_TYPE::REV_INPUT);
}
InstPtr Instruction::OUTPUT(){
return new Instruction(INS_TYPE::OUTPUT);
}
InstPtr Instruction::REV_OUTPUT(){
return new Instruction(INS_TYPE::REV_OUTPUT);
}
InstPtr Instruction::DUP(){
return new Instruction(INS_TYPE::DUP);
}
InstPtr Instruction::END(){
return new Instruction(INS_TYPE::END);
}
InstPtr Instruction::VAR(std::string name, long long val){
return Instruction::VAR(name, std::to_string(val));
}
InstPtr Instruction::VAR(std::string name, std::string val){
auto ins = new Instruction(INS_TYPE::VAR);
ins->varname = name;
ins->varval = val;
return ins;
}
InstPtr Instruction::UNIT_CALL(std::string unitname, std::string arg){
auto ins = new Instruction(INS_TYPE::UNIT_CALL);
ins->unit = unitname;
ins->unit_arg = arg;
return ins;
}
#pragma once
#include "define.h"
#include "Routine.h"
#include "Resource.h"
#include <memory>
#include <list>
#include <string>
#include <new>
class Routine;
struct Instruction : Resource{
Routine* routine = nullptr; //この命令を含む関数
INS_TYPE type; //命令の種別
std::string label; //命令に付加されたラベル
std::string flag; //IFの条件となるフラグ or NEXTで変化させるフラグ
/*
InstPtr branch = nullptr; //BRANCHの飛び先
std::string jmp; //JMPの飛び先
std::string skip; //SKIPの飛び先
*/
InstPtr move_to = nullptr; //BRANCH, JMP, SKIPの飛び先
InstPtr next_cluster_branch = nullptr; //次のOPR,ROT,OUTPUT,INPUTのInstruction
//以下の変数名・値は通常の変数定義には使われない.
//CALL命令内部など,メインストリームにLABEL:VALUR形式を埋め込みたいときに使用する.
std::string varname; //変数名となるラベル名
std::string varval; //変数の値
std::string unit; //ユニット名
std::string unit_arg; //ユニットを呼ぶときの引数(というかDレジスタにセットする値).なくてもよい
Instruction();
Instruction(INS_TYPE type);
static InstPtr IF_BRANCH(std::string flag);
static InstPtr IF_BRANCH_ASSIGNED(std::string flag, InstPtr branch = NULL);
static InstPtr NEXT(std::string flag);
static InstPtr SKIP(InstPtr label);
static InstPtr LABEL(std::string label);
static InstPtr JMP(InstPtr jmp);
static InstPtr REV_JMP();
static InstPtr INPUT();
static InstPtr REV_INPUT();
static InstPtr OUTPUT();
static InstPtr REV_OUTPUT();
static InstPtr DUP();
static InstPtr END();
static InstPtr VAR(std::string name, std::string val);
static InstPtr VAR(std::string name, long long val);
static InstPtr UNIT_CALL(std::string name, std::string arg = "");
};
CC = g++
CFLAGS = -std=c++0x -lstdc++ -O2 -Wdeprecated-declarations -w
LEX = flex -i
YACC = bison -y
all: main.cc parser.cc scanner.cc Resource.o Program.o Radix.o Option.o Routine.o CodeBlock.o Instruction.o Generator.o Variable.o
$(CC) $(CFLAGS) $^ -ll -o parser
scanner.cc: scanner.ll
$(LEX) -o $@ $^
parser.cc: parser.yy
$(YACC) -o $@ --defines=parser.h $^
%.o:%.cc
$(CC) $(CFLAGS) $^ -c -o $@
clean:
rm -f parser parser.h scanner.cc parser.cc *.o stack.hh
#include "Option.h"
Option& Option::getInstance() {
static Option instance;
return instance;
}
bool Option::get_rand(){
return this->rand2(this->mt) == 1;
}
void Option::set_seed(int seed){
this->seed = seed;
this->mt.seed(seed);
}
bool Option::back_to_main(){
if(this->jmp_main){
if(this->jmp_directly){
return this->get_rand();
}
return true;
}
return false;
}
bool Option::use_op_block(){
if(this->op_block){
if(this->op_inline){
return this->get_rand();
}
return true;
}
return false;
}
#pragma once
#include <iostream>
#include <random>
class Option{
Option():rand2(0,1),mt(seed){}
Option(const Option &other){}
Option &operator=(const Option &other);
unsigned int seed = (*(new std::random_device))(); //初期値として適当なシードを与える
std::mt19937 mt;
std::uniform_int_distribution<int> rand2;
bool get_rand();
public:
bool op_block = true;
bool op_inline = true;
bool jmp_main = true;
bool jmp_directly = true;
static Option &getInstance();
void set_seed(int seed);
bool back_to_main();
bool use_op_block();
};
#include "Program.h"
Program::Program(){
this->add_flag(FLAG_JMP, FLAG_OFF);
this->add_flag(FLAG_REV_OPR_ROT, FLAG_ON);
//this->add_flag(FLAG_REV_IND_OPR, FLAG_OFF);
this->add_flag(FLAG_CASE0, FLAG_ON);
this->add_flag(FLAG_CASE1, FLAG_ON);
this->add_flag(FLAG_CASE2, FLAG_ON);
auto r = this->global_routine = this->add_routine(GLOBAL_ROUTINE, false);
this->VAR_CON0 = r->add_var("CON0", CON0_VAL);
this->VAR_CON1 = r->add_var("CON1", CON1_VAL);
this->VAR_CON2 = r->add_var("CON2", CON2_VAL);
r->add_var("BASE", 0);
r->add_block();
r->pop_block();
}
void Program::add_flag(std::string flag_name, int val){
this->flags[flag_name] = val;
}
Routine* Program::add_routine(std::string name, bool prototype_only){
auto routines = this->routines;
bool defined = routines.count(name) > 0;
if(defined && routines[name]->is_implemented){
throw_syntax_error("Routine '"+name+"' is already defined.");
}
if(!defined){
this->routines[name] = new Routine(this, name);
}
this->routines[name]->is_implemented = !prototype_only;
return this->current_routine = this->routines[name];
}
std::string Program::create_branch_flag(){
auto flag = this->get_next("FLAG");
this->add_flag(flag, FLAG_OFF);
return flag;
}
std::string Program::get_next(std::string seq_key){
return seq_key + std::to_string(this->seq_ids[seq_key]++);
}
void Program::check_flag(std::string flag_name){
if(this->flags.count(flag_name) == 0){
throw_syntax_error("Undefined flag : "+flag_name);
}
}
void Program::generate(){
Generator g;
g.program_start_to("MAIN");
//フラグ出力
for(auto it = this->flags.begin(); it != this->flags.end(); it++){
auto f = *it;
g.flag(f.first, f.second);
}
bool use_ind_opr = this->ind_opr_branches.size() > 0;
if(use_ind_opr){
g.raw(RAW_IND_OPR_FLAGS);
g.raw(RAW_IND_OPR_UNIT);
}
if(this->is_using_djmp){
g.raw(RAW_DJMP_UNIT);
}
for(auto r : this->routines){
(*r.second).generate(g);
g.ln();
}
g.output_code();
}
#pragma once
#include "define.h"
#include "Instruction.h"
#include "Generator.h"
#include "CodeBlock.h"
#include "Routine.h"
#include <iostream>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <list>
#include <map>
#include <stack>
#include "Resource.h"
#include "Variable.h"
#include "raw/ind-opr.h"
#include "raw/djmp.h"
extern void throw_syntax_error(std::string s);
class Routine;
struct Variable;
class Program : Resource{
//get_nextで使用する値
std::map<std::string, int> seq_ids;
//フラグ名 -> 初期値(0,1) のmap
std::map<std::string, int> flags;
public:
//関数名 -> 関数オブジェクト
std::map<std::string, Routine*> routines;
Routine* current_routine;
InstPtrList ind_opr_branches;
bool is_using_djmp;
Routine* global_routine;
Variable* VAR_CON0;
Variable* VAR_CON1;
Variable* VAR_CON2;
Program();
std::string create_branch_flag();
//branch用のフラグなどで使用する連番文字列を生成する
//keyごとに連番となる
std::string get_next(std::string seq_key);
void add_flag(std::string flag_name, int val);
void check_flag(std::string flag_name);
Routine* add_routine(std::string name, bool prototype_only);
void generate();
};
2017.03.24
制御付き疑似命令列から低級アセンブリプログラムへ変換するプログラム.
SimpleConverterがスパゲッティコードになっていたので一から作成し直したもの.
加えて河邉さんが提案した配列機能も実装してある.
実行方法
./parser [-cimds] test.mg > test.mc
オプションの詳細は2016.11.2のレポートを参照すること
\ No newline at end of file
#include "Radix.h"
Radix::Radix(const char* s) : s(s) {
int i;
for(i = 0; s[i]; ++i)
a[(int)s[i]] = i;
}
std::string Radix::to(long long p, int q) {
int i;
if(!p)
return "0";
char t[64] = { };
for(i = 62; p; --i) {
t[i] = s[p % q];
p /= q;
}
return std::string(t + i + 1);
}
std::string Radix::to(const std::string& t, int p, int q) {
return to(to(t, p), q);
}
long long Radix::to(const std::string& t, int p) {
int i;
long long sm = a[(int)t[0]];
for(i = 1; i < (int)t.length(); ++i)
sm = sm * p + a[(int)t[i]];
return sm;
}
#pragma once
#include <string>
class Radix {
private:
const char* s;
int a[128];
public:
Radix(const char* s = "0123456789ABCDEF");
std::string to(long long p, int q);
std::string to(const std::string& t, int p, int q);
long long to(const std::string& t, int p);
};
#include "Resource.h"
//静的メンバ変数はコンストラクタからアクセスするとsegmentation faultが起こるため,静的メンバ関数内のstatic変数を代わりに使用する
std::list<Resource*>& Resource::collection(){
static std::list<Resource*> list;
return list;
}
Resource::Resource(){
Resource::collection().push_back(this);
}
void Resource::release(){
auto& collection = Resource::collection();
while(!collection.empty()){
delete collection.front();
collection.pop_front();
}
}
#pragma once
#include <iostream>
#include <list>
class Resource{
static std::list<Resource*>& collection();
public:
Resource();
static void release();
};