├── .gitignore ├── .gitmodules ├── Makefile ├── README.md ├── codegen.cpp ├── codegen.h ├── codegen1.cpp ├── codegen2.cpp ├── codegen3.cpp ├── codegen4.cpp ├── codegen5.cpp ├── codegen6.cpp ├── codegen7.cpp ├── compile.sh ├── compiled ├── flat.py ├── output └── output.c ├── emelio-util.cpp ├── emelio.cpp ├── emelio.h ├── lab.em ├── notation.cpp ├── notation.h ├── ocamlgen.cpp ├── parse.cpp ├── pp.py ├── reduction.cpp ├── test.em ├── testcases ├── dollar.em ├── imperative_semantics.em ├── let.em ├── meta-notation.em └── testcases.em ├── type.cpp ├── utest.sh ├── util.cpp └── util.h /.gitignore: -------------------------------------------------------------------------------- 1 | emelio 2 | memo.md 3 | .vscode/ 4 | .DS_Store 5 | compiled/env.c 6 | compiled/code.c 7 | compiled/lib.s 8 | 9 | # Prerequisites 10 | *.d 11 | 12 | # Compiled Object files 13 | *.slo 14 | *.lo 15 | *.o 16 | *.obj 17 | 18 | # Precompiled Headers 19 | *.gch 20 | *.pch 21 | 22 | # Compiled Dynamic libraries 23 | *.so 24 | *.dylib 25 | *.dll 26 | 27 | # Fortran module files 28 | *.mod 29 | *.smod 30 | 31 | # Compiled Static libraries 32 | *.lai 33 | *.la 34 | *.a 35 | *.lib 36 | 37 | # Executables 38 | *.exe 39 | *.out 40 | *.app 41 | 42 | *.cpp.cc 43 | 44 | *.new 45 | *.inc 46 | 47 | # IDE 48 | *.cflags 49 | *.config 50 | *.files 51 | *.cxxflags 52 | *.includes 53 | *.creator 54 | *.creator.user 55 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "Tokenizer"] 2 | path = Tokenizer 3 | url = https://github.com/CreativeGP/Tokenizer.git 4 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | %.cpp.cc: %.cpp 2 | python pp.py $< 3 | astyle $@ -Y 4 | rm *.orig 5 | 6 | %.a: %.o 7 | ar r $@ $< 8 | ranlib $@ 9 | 10 | tkutil.o: Tokenizer/util.cpp 11 | g++ -pg -std=c++2a -c $< -g3 -o $@ 12 | tk.o: Tokenizer/tokenizer.cpp 13 | g++ -pg -std=c++2a -c $< -g3 -o $@ 14 | util.o: util.cpp emelio-util.cpp emelio.h util.h 15 | g++ -pg -std=c++2a -c $< -g3 -o $@ 16 | emelio-util.o: emelio-util.cpp emelio.h util.h 17 | g++ -pg -std=c++2a -c $< -g3 -o $@ 18 | reduction.o: reduction.cpp.cc emelio.h util.h notation.h 19 | g++ -pg --std=c++2a -c $< -g3 -o $@ 20 | parse.o: parse.cpp.cc emelio.h util.h 21 | g++ -pg --std=c++2a -c $< -g3 -o $@ 22 | notation.o: notation.cpp emelio.h util.h notation.h 23 | g++ -pg --std=c++2a -c $< -g3 -o $@ 24 | transpile.o: transpile.cpp emelio.h util.h notation.h 25 | g++ -pg --std=c++2a -c $< -g3 -o $@ 26 | # codegen.o: codegen.cpp emelio.h util.h notation.h codegen.h codegen*.cpp ocamlgen.cpp 27 | # g++ -pg --std=c++2a -c $< -g3 -o $@ 28 | codegen.o: codegen.cpp emelio.h util.h notation.h codegen.h codegen7.cpp ocamlgen.cpp 29 | g++ -pg --std=c++2a -c $< -g3 -o $@ 30 | type.o: type.cpp emelio.h util.h 31 | g++ -pg --std=c++2a -c $< -g3 -o $@ 32 | emelio.o: emelio.cpp emelio.h util.h codegen.h 33 | g++ -pg --std=c++2a -c $< -g3 -o $@ 34 | 35 | 36 | OBJS = tkutil.o tk.o util.o emelio-util.o type.o parse.o notation.o codegen.o reduction.o emelio.o 37 | SML_OBJS = tkutil.o tk.o util.o emelio-util.o parse.o emelio.o 38 | 39 | compile: emelio 40 | ./emelio c test.em | gcc -lm -xc -Wall -o output - 41 | 42 | comptest: emelio 43 | ./emelio c test.em > compiled/vim.c 44 | astyle compiled/vim.c 45 | gcc -xc -lm -std=gnu11 -g compiled/vim.c -o compiled/a.out 46 | 47 | compr: 48 | ./compiled/a.out 49 | 50 | clean: 51 | rm *.o 52 | rm *.cpp.cc 53 | 54 | build: $(OBJS) emelio.h 55 | g++ -pg -std=c++2a -o emelio $(OBJS) -g3 56 | 57 | sml-build: $(SML_OBJS) emelio.h 58 | g++ -pg -std=c++2a -o emelio $(SML_OBJS) -g3 59 | 60 | 61 | clang: $(OBJS) 62 | clang -std=c++17 -o emelio $(OBJS) 63 | 64 | test: 65 | ./utest.sh 66 | 67 | run: emelio 68 | ./emelio 69 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # intprt-cpp 2 | 3 | 4 | Emelio interpreter written in C++ 5 | 6 | ## ※注意※ 7 | 8 | 9 | このリポジトリまだ完全に開発途中で、コードもガンガン変わりまし、バグもありえないほどあります。 10 | (急にStarが増えてPRも来たので焦って書いてますw) 11 | -------------------------------------------------------------------------------- /codegen.cpp: -------------------------------------------------------------------------------- 1 | /* ======================================================================== 2 | $File: codegen.cpp $ 3 | $Date: Nov 11 2019 $ 4 | $Revision: $ 5 | $Creator: Creative GP $ 6 | $Notice: (C) Copyright 2019 by Creative GP. All Rights Reserved. $ 7 | ======================================================================== */ 8 | 9 | #include "emelio.h" 10 | #include "util.h" 11 | #include "notation.h" 12 | #include "codegen.h" 13 | 14 | #include 15 | 16 | map set_type::data_bind; 17 | set set_type::special_values; 18 | 19 | const set builtin_functions = { 20 | "add", "sub", "mul", "div", "negate", "concat", "fuse" 21 | }; 22 | 23 | const map bf2arity = { 24 | { "negate", 1 }, 25 | { "add", 2 }, 26 | { "sub", 2 }, 27 | { "mul", 2 }, 28 | { "div", 2 }, 29 | { "concat", 2 }, 30 | }; 31 | 32 | const map bf2typesig = { 33 | { "negate", make_shared( TypeFn { {"int"}, "int" } )}, 34 | { "add", make_shared( TypeFn { {"int","int"}, "int" } )}, 35 | { "sub", make_shared( TypeFn { {"int","int"}, "int" } )}, 36 | { "mul", make_shared( TypeFn { {"int","int"}, "int" } )}, 37 | { "div", make_shared( TypeFn { {"int","int"}, "int" } )}, 38 | { "concat", make_shared( TypeFn { {"string","string"}, "string" } )}, 39 | { "_get", make_shared( TypeFn { {"any"}, "any" } )}, 40 | }; 41 | 42 | #define CODEGEN_DELIMITER " " 43 | 44 | inline void outprg(string &res, const string &body) { res += body + (CODEGEN_DELIMITER); } 45 | inline void outprg(string &res, string &env, const pair &bodyenv) { res += bodyenv.first + (CODEGEN_DELIMITER); env += bodyenv.second + (CODEGEN_DELIMITER); } 46 | 47 | inline void outprg(vector &res, const string &body) { 48 | res.push_back(body); 49 | } 50 | inline void outroot(StackLanguage &dist, const StackLanguage &src) { 51 | copy(src.root.begin(), src.root.end(), back_inserter(dist.root)); 52 | copy(src.env.begin(), src.env.end(), back_inserter(dist.env)); 53 | } 54 | inline void outenv(StackLanguage &dist, const StackLanguage &src) { 55 | copy(src.root.begin(), src.root.end(), back_inserter(dist.env)); 56 | copy(src.env.begin(), src.env.end(), back_inserter(dist.env)); 57 | } 58 | 59 | string StaticProgram = ""; 60 | unsigned function_call_counter = 0; 61 | unsigned conditional_counter = 0; 62 | 63 | Guard get_guard(const deque> &args) { 64 | Guard res; 65 | for (auto arg : args) { 66 | if (is_literal(arg->l->argnames[0])) { 67 | res.finites.push_back(make_pair(arg->l->argnames[0], arg->l->body)); 68 | } else { 69 | res.countables.emplace_back(arg); 70 | } 71 | } 72 | return res; 73 | } 74 | 75 | GuardType get_guard_type(const deque> &args) { 76 | for (auto arg : args) { 77 | if (!is_literal(arg->l->argnames[0])) { 78 | return GTYPE_COUNTABLE_FINITE; 79 | } 80 | } 81 | return GTYPE_FINITE; 82 | } 83 | 84 | /* 85 | cgen(add e1 ...) = 86 | cgen(e1) 87 | ... 88 | pop $1 89 | pop $2 90 | add $1, $1, $2 91 | push $1 92 | 93 | 94 | */ 95 | 96 | /* TODO: 97 | ・配列データ 98 | ・bindされない引数の扱い 99 | */ 100 | 101 | void rename_variables(const shared_ptr c) 102 | { 103 | map varused_counter = {}; 104 | 105 | function)> _rename_variables = 106 | [&](const shared_ptr c) { 107 | for (auto e : c->args) { 108 | _rename_variables(e); 109 | } 110 | 111 | if (c->l) { 112 | for (auto &n : c->l->argnames) { 113 | // 数字なら飛ばす 1が何回もfuseに現れるからって12, 13とかにされても困るよね 114 | if (is_number(n)) continue; 115 | 116 | varused_counter[n]++; 117 | if (varused_counter[n] != 1) 118 | n = /*"____renamed____" + */ n + to_string(varused_counter[n]); 119 | } 120 | _rename_variables(c->l->body); 121 | } else { 122 | if (!is_literal(c->lit.val)) { 123 | if (varused_counter[c->lit.val] >= 2) 124 | c->lit.val = /*"____renamed____" + */c->lit.val + to_string(varused_counter[c->lit.val]); 125 | } 126 | } 127 | 128 | }; 129 | 130 | _rename_variables(c); 131 | } 132 | 133 | // template 134 | // void SCOUT(const stack &s) { 135 | // auto tmp = s; 136 | // while (!tmp.empty()) { 137 | // cout << tmp.top() << " "; 138 | // tmp.pop(); 139 | // } 140 | // cout << endl; 141 | // } 142 | 143 | template 144 | void SCOUT(deque> s) { 145 | while (!s.empty()) { 146 | cout << *s.back() << endl; 147 | s.pop_back(); 148 | } 149 | cout << endl; 150 | } 151 | 152 | void set_arity::operator () (const shared_ptr c) { 153 | if (c->l) { 154 | c->arity += c->l->argnames.size(); 155 | 156 | for (int i = c->args.size()-1; i >= 0; i--) { 157 | (set_arity(&bind))(c->args[i]); 158 | argstack.push(c->args[i]); 159 | } 160 | 161 | int i = 0; 162 | for (auto argname : c->l->argnames) { 163 | // cout << argname << endl; 164 | if (argstack.empty()) { 165 | // 引数情報から推論できない場合でも、種の指定があればそれとする。 166 | // 指定もなければbindに入れないことでマークしておく(下の方の処理でないと推論の情報があった時つじつまを合わせる) 167 | if (c->l->argarities[i] != -1) 168 | bind[argname] = c->l->argarities[i]; 169 | continue; 170 | } 171 | // cout << *argstack.top() << endl; 172 | bind[argname] = argstack.top()->arity; 173 | // 種の指定があれば、整合性をチェック 174 | if (c->l->argarities[i] != -1) 175 | ASSERT(bind[argname] == c->l->argarities[i], 176 | ("引数"+argname+"の種が合致しません. (expected:" + to_string(c->l->argarities[i]) + 177 | " inferred:"+to_string(bind[argname])+")")); 178 | argstack.pop(); 179 | i++; 180 | } 181 | 182 | this->operator()(c->l->body); 183 | c->arity += c->l->body->arity; 184 | 185 | } 186 | else if (c->lit.val == "fuse") { 187 | for (auto a : c->args) (set_arity(&bind))(a); 188 | 189 | c->arity = c->args[0]->arity + c->args.size() /*for adjust*/; // TODO? 190 | } 191 | else { 192 | if (!c->l && builtin_functions.contains(c->lit.val)) { 193 | c->arity += bf2arity.at(c->lit.val); 194 | } 195 | else { // what.. 196 | // 不明な関数は分からないのでarityは引数の数で値を返す。つまり無条件で0になるようにする 197 | try { 198 | // cout << c->lit.val << " " << bind.at(c->lit.val) << endl; 199 | c->arity += bind.at(c->lit.val); 200 | } catch (exception &e) { 201 | c->arity += c->args.size(); 202 | } 203 | } 204 | 205 | for (auto a : c->args) (set_arity(&bind))(a); 206 | } 207 | 208 | // cout << "a" << endl; 209 | cout << *c << endl; 210 | 211 | c->arity -= c->args.size(); 212 | } 213 | 214 | // プログラム中で型指定されているlambdaしか情報がないので、その情報などをもとに全てのlambda, codeに妥当な型を当てはめます 215 | // (| | body ) O O とあった時、(|1| 3 ) 2 の順番で処理していきます。 216 | // まず、1で指定された型の情報を信用してbindに保存し、 217 | // 2その情報を持って順番に引数を処理して、最終的な型が1と合致することを確かめます。 218 | // 3そしてbodyを処理して 219 | // 4その全体のCodeの型を3で得た型に引数の個数だけ適用した型として決定します 220 | 221 | // fn O O とあった時、fnの型はすでに分かっていないとエラーにする. Oから 222 | void set_type::operator () (const shared_ptr c) { 223 | if (c->l) { 224 | // 1 225 | int i = 0; 226 | for (auto argname : c->l->argnames) { 227 | bind[argname] = c->l->argtypes[i]; 228 | i++; 229 | } 230 | 231 | // 3 232 | this->operator()(c->l->body); 233 | 234 | // 2 235 | for (int i = c->args.size()-1; i >= 0; i--) { 236 | excepted = c->l->argtypes[i]; 237 | (set_type(&bind))(c->args[i]); 238 | // argstack.push(c->args[i]); 239 | } 240 | excepted = shared_ptr(); 241 | 242 | // 2 合致することを確かめます 243 | for (int i = 0; i < min(c->args.size(),c->l->argnames.size()); i++) { 244 | auto argname = c->l->argnames[i]; 245 | TypeSignature a = normalized(bind[argname]); 246 | TypeSignature b = normalized(c->args[i]->type); 247 | cout << argname << " 型検査" << endl; 248 | ASSERT(verify(a, b, data_bind), 249 | ("引数"+argname+"の型が合致しません. (expected:" + to_string(a) + 250 | " inferred:"+to_string(b)+")")); 251 | deep_copy_from(c->args[i]->type, bind[argname]); 252 | } 253 | 254 | // 4 255 | deep_copy_from(c->l->type, c->l->body->type); 256 | deep_copy_from(c->type, c->l->body->type); 257 | // cout << to_string(c->type) << endl; 258 | // cout << "wrap " << c->l->argtypes.size() << endl; 259 | for (int i = 0; i < c->l->argtypes.size(); ++i) { 260 | wrap(c->l->type, c->l->argtypes[i]); 261 | wrap(c->type, c->l->argtypes[i]); 262 | } 263 | // cout << "apply " << c->args.size() << endl; 264 | apply(c->type, (int) c->args.size()); 265 | } 266 | else if (c->lit.val == "_get") { 267 | (set_type(&bind))(c->args[0]); 268 | TypeSignature from = MATCH(string)(c->args[0]->type) ? data_bind[PURE(string)(c->args[0]->type)] : c->args[0]->type; 269 | if (MATCHS(TypeProduct)(from)) { 270 | auto &records = PURES(TypeProduct)(from); 271 | string varname = ""; 272 | { 273 | auto &pivot = c->args[1]; 274 | while (pivot->l) { pivot = pivot->l->body; } 275 | varname = pivot->lit.val; 276 | } 277 | auto &fruit = records->products[distance(records->names.begin(), find(records->names.begin(), records->names.end(), varname))]; 278 | deep_copy_from(c->type, fruit); 279 | 280 | // shared_ptr newfn(new TypeFn); 281 | // deep_copy_from(newfn->to, fruit); 282 | // { 283 | // TypeSignature tmp; 284 | // deep_copy_from(tmp, type_name); 285 | // newfn->from.emplace_back(tmp); 286 | // } 287 | // c->type = fruit; 288 | } else { 289 | assert("TODO: あとで!"); 290 | } 291 | } 292 | else if (c->lit.val == "fuse") { 293 | c->type = shared_ptr(new TypeSum); 294 | 295 | // for (int i = c->args.size()-1; i >= 0; i--) { 下のやつも 296 | for (int i = 0; i < c->args.size(); i++) { 297 | (set_type(&bind))(c->args[i]); 298 | // argstack.push(c->args[i]); 上のやつも 299 | PURES(TypeSum)(c->type)->add_type(c->args[i]->type); 300 | } 301 | 302 | if (PURES(TypeSum)(c->type)->sums.size() == 1) 303 | c->type = c->args[0]->type; 304 | else 305 | c->type = sumfactor(PURES(TypeSum)(c->type)); 306 | } 307 | else if (c->lit.val == "type") { 308 | shared_ptr new_type_fn = shared_ptr(new TypeFn); 309 | new_type_fn->to = c->args[0]->lit.val; 310 | // TODO: 積型しか対応してない.... 311 | if (MATCHS(TypeProduct)(c->args[1]->rawtype)) { 312 | for (auto typ : PURES(TypeProduct)(c->args[1]->rawtype)->products) { 313 | new_type_fn->from.emplace_back(typ); 314 | } 315 | bind[c->args[0]->lit.val] = new_type_fn; 316 | } else { 317 | if (MATCHS(TypeSum)(c->args[1]->rawtype)) { 318 | for (auto e : PURES(TypeSum)(c->args[1]->rawtype)->sums) 319 | if (MATCH(SpecialValue)(e)) 320 | special_values.insert(PURE(SpecialValue)(e).val); 321 | } 322 | new_type_fn->from.emplace_back(c->args[1]->rawtype); 323 | bind[c->args[0]->lit.val] = new_type_fn; 324 | normalize(bind[c->args[0]->lit.val]); 325 | } 326 | data_bind[c->args[0]->lit.val] = c->args[1]->rawtype; 327 | cout << c->args[0]->lit.val << " " << to_string(bind[c->args[0]->lit.val]) << endl; 328 | 329 | this->operator()(c->args.back()); 330 | } else if (builtin_functions.contains(c->lit.val)) { 331 | for (auto a : c->args) (set_type(&bind))(a); 332 | 333 | deep_copy_from(c->type, bf2typesig.at(c->lit.val)); 334 | apply(c->type, (int) c->args.size()); 335 | 336 | int i = 0; 337 | for (auto a : c->args) { 338 | cout << to_string(arg(bf2typesig.at(c->lit.val),i)) << endl; 339 | TypeSignature x = normalized(arg(bf2typesig.at(c->lit.val),i)); 340 | TypeSignature y = normalized(c->args[i]->type); 341 | ASSERT(verify(x, y, data_bind), 342 | "'"+c->lit.val+"'の"+to_string(i)+"番目の引数の型が合致しません. (expected:" + to_string(bf2typesig.at(c->lit.val)) + 343 | " inferred:"+to_string(c->args[i]->type)+")"); 344 | } 345 | } else if (is_literal(c->lit.val)) { 346 | if (is_number(c->lit.val)) { 347 | c->type = "int"; 348 | } 349 | } else { 350 | auto fnname = c->lit.val; 351 | for (auto a : c->args) (set_type(&bind))(a); 352 | 353 | // もし、関数の型が分かっていないならとりまエラー 354 | if (c->cRawtype) { 355 | fnname = to_string(c->rawtype); 356 | if (MATCHS(Parametered)(c->rawtype)) 357 | fnname = PURES(Parametered)(c->rawtype)->type; 358 | ASSERT(bind.contains(fnname), "コンストラクタ '"+to_string(c->rawtype)+"' は定義されていません"); 359 | } else if (special_values.contains(fnname)) { // 特殊値 360 | ASSERT(c->args.size() == 0, "特殊値? '"+fnname+"' に適用することは出来ません"); 361 | c->type = SpecialValue{fnname}; 362 | return; 363 | } else { 364 | cout << special_values.contains(fnname); 365 | ASSERT(bind.contains(fnname), "'"+fnname+"' の型が不明です"); 366 | } 367 | 368 | deep_copy_from(c->type, bind[fnname]); 369 | cout << fnname << " " << to_string(c->type) << endl; 370 | apply(c->type, (int) c->args.size()); 371 | 372 | int i = 0; 373 | for (auto a : c->args) { 374 | ASSERT(verify(normalized(arg(bind[fnname],i)), normalized(c->args[i]->type), data_bind), 375 | "'"+c->lit.val+"'の"+to_string(i)+"番目の引数の型が合致しません. (expected:" + to_string(bind[fnname]) + 376 | " inferred:"+to_string(c->args[i]->type)+")"); 377 | } 378 | } 379 | cout << * c << endl; 380 | 381 | // cout << "a" << endl; 382 | } 383 | 384 | // #include "codegen1.cpp" 385 | // #include "codegen2.cpp" 386 | // #include "codegen3.cpp" 387 | // #include "codegen4.cpp" 388 | // #include "codegen5.cpp" 389 | #include "codegen7.cpp" 390 | //#include "ocamlgen.cpp" 391 | 392 | vector split_instr(string instr) { 393 | vector res; 394 | replace(instr.begin(), instr.end(), ',', ' '); 395 | istringstream iss(instr); 396 | string s; 397 | while (iss >> s) { 398 | res.push_back(s); 399 | } 400 | return res; 401 | } 402 | 403 | string join_instr(vector instrs) { 404 | if (instrs.size() == 0) return ""; 405 | 406 | string res; 407 | res += instrs[0] + " "; 408 | for (int i = 1; i < instrs.size(); i++) { 409 | res += instrs[i] + ","; 410 | } 411 | res.pop_back(); 412 | return res; 413 | } 414 | 415 | string fasm_ins(string ins) { 416 | if (is_literal(ins)) { 417 | return 418 | "_push " + ins; 419 | } 420 | else if (ins.starts_with(":")) { 421 | // label 422 | return 423 | ins.substr(1) + ":"; 424 | } 425 | else if (ins.starts_with("dup")) { 426 | return 427 | "_dup " + ins.substr(3); 428 | } 429 | else if (ins.starts_with("drop")) { 430 | return 431 | "_pop"; 432 | } 433 | else if (ins.starts_with("!dup")) { 434 | return 435 | "_exec " + ins.substr(4); 436 | } 437 | else if (ins.starts_with("decbsp")) { 438 | return 439 | "_decbsp " + ins.substr(6); 440 | } 441 | else if (ins.starts_with("rewind")) { 442 | return 443 | "_rewind " + ins.substr(6); 444 | } 445 | else if (ins.starts_with("'")) { 446 | return 447 | "_push " + ins.substr(1); 448 | } 449 | else if (ins == ";") return "ret"; 450 | else if (ins == "+") return "call __add"; 451 | else if (ins == "-") return "call __sub"; 452 | else if (ins == "*") return "call __mul"; 453 | else if (ins == "/") return "call __div"; 454 | else if (ins == "negate") return "call __negate"; 455 | else { 456 | return 457 | "call " + ins; 458 | } 459 | } 460 | 461 | string fasm(const vector &s) { 462 | string res; 463 | 464 | for (string ins : s) res += fasm_ins(ins) + "\n"; 465 | 466 | return res; 467 | } 468 | 469 | // make it executable 470 | string fasm(string pseudasm) { 471 | string res; 472 | stringstream ss { pseudasm }; 473 | string buf; 474 | stack program_line_stack; 475 | unsigned program_line = 0; 476 | 477 | while (getline(ss, buf, '\n')) { 478 | vector instrs = split_instr(buf); 479 | 480 | if (instrs.size() == 0) { res += "\n"; continue; } 481 | 482 | // single mms replace 483 | for (string &ins : instrs) { 484 | if (ins == "#push_here") { 485 | program_line_stack.push(program_line); 486 | goto continue_line; 487 | } else if (ins == "#pop") { 488 | ins = to_string(program_line_stack.top()); 489 | program_line_stack.pop(); 490 | } 491 | else if (builtin_functions.contains(ins)) { ins = "call __" + ins; } 492 | else if (ins == "$a0") { ins = "eax"; } 493 | } 494 | 495 | // multiple mms replace 496 | if (instrs[0] == "push") { 497 | instrs = { "mov", "eax", instrs[1] }; 498 | res += join_instr(instrs) + "\n"; 499 | 500 | instrs = { "call", "__push" }; 501 | res += join_instr(instrs) + "\n"; 502 | continue; 503 | } 504 | else if (instrs[0] == "getf") { 505 | instrs = { "mov", "edx", instrs[1] }; 506 | res += join_instr(instrs) + "\n"; 507 | 508 | instrs = { "call", "__getf" }; 509 | res += join_instr(instrs) + "\n"; 510 | continue; 511 | } 512 | else if (instrs[0] == "pushf") { 513 | instrs = { "mov", "eax", instrs[1] }; 514 | res += join_instr(instrs) + "\n"; 515 | 516 | instrs = { "call", "__pushf" }; 517 | res += join_instr(instrs) + "\n"; 518 | continue; 519 | } 520 | else if (instrs[0] == "popf") { 521 | instrs = { "call", "__popf" }; 522 | res += join_instr(instrs) + "\n"; 523 | continue; 524 | } 525 | 526 | res += join_instr(instrs) + "\n"; 527 | 528 | continue_line: 529 | program_line++; 530 | } 531 | 532 | return res; 533 | } 534 | -------------------------------------------------------------------------------- /codegen.h: -------------------------------------------------------------------------------- 1 | #if !defined(CODEGEN_H) 2 | /* ======================================================================== 3 | $File: codegen.h $ 4 | $Date: Dec 12 2019 $ 5 | $Revision: $ 6 | $Creator: Creative GP $ 7 | $Notice: (C) Copyright 2019 by Creative GP. All Rights Reserved. $ 8 | ======================================================================== */ 9 | 10 | #include "emelio.h" 11 | 12 | 13 | enum GuardType { GTYPE_COUNTABLE_FINITE, GTYPE_FINITE }; 14 | struct Guard { 15 | deque>> finites; 16 | deque> countables; 17 | }; 18 | Guard get_guard(const deque> &args); 19 | GuardType get_guard_type(const deque> &args); 20 | 21 | 22 | class set_arity { 23 | private: 24 | map bind; 25 | stack> argstack; 26 | public: 27 | set_arity(map *pb = nullptr, stack> *pa = nullptr) { 28 | if (pa) argstack = *pa; 29 | if (pb) bind = *pb; 30 | } 31 | ~set_arity() { 32 | } 33 | void operator () (const shared_ptr c); 34 | }; 35 | 36 | class set_type { 37 | private: 38 | map bind; 39 | static map data_bind; 40 | static set special_values; 41 | map> type_constructors; 42 | stack> argstack; 43 | TypeSignature excepted; 44 | 45 | public: 46 | set_type(map *pb = nullptr, stack> *pa = nullptr) { 47 | if (pa) argstack = *pa; 48 | if (pb) bind = *pb; 49 | } 50 | ~set_type() { 51 | } 52 | void operator () (const shared_ptr c); 53 | }; 54 | 55 | class codegen { 56 | private: 57 | Code callable; 58 | 59 | deque> argstack; 60 | map> bind; 61 | set in_recursion; 62 | bool is_root = true; 63 | 64 | public: 65 | codegen() {} 66 | ~codegen() {} 67 | pair operator () (const shared_ptr c); 68 | }; 69 | 70 | struct StackLanguage { 71 | vector root; 72 | vector env; 73 | }; 74 | 75 | class codegen2 { 76 | private: 77 | Code callable; 78 | 79 | unsigned insfunc_counter = 0; 80 | unsigned bsoffset = 0; 81 | 82 | deque unbinded; 83 | set defined; 84 | map> bind; 85 | deque> argstack; 86 | // map> bind; 87 | set in_recursion; 88 | bool is_root = true; 89 | 90 | public: 91 | codegen2() {} 92 | ~codegen2() {} 93 | StackLanguage operator () (const shared_ptr c); 94 | }; 95 | 96 | struct BindInfo { 97 | shared_ptr code; 98 | }; 99 | 100 | struct Compiled { 101 | string body="", env="", global=""; 102 | bool return_required=true; // return body;としてよいか 103 | }; 104 | 105 | class codegen3 { 106 | private: 107 | 108 | // バインド保留のコード と それの実体(または実体を指すポインタ)があるスタックの絶対位置 のペア 109 | deque argstack; 110 | deque> argstack_code; 111 | 112 | map bind; 113 | map bindinfo; 114 | set in_recursion; 115 | int stack_height = 0; 116 | bool is_root = true; 117 | 118 | public: 119 | bool human = false; 120 | codegen3() {} 121 | codegen3(bool h) : human(h) {} 122 | ~codegen3() {} 123 | string print_rel(int rel); 124 | Compiled evoke_rel(int rel); 125 | Compiled copy_rel(int rel); 126 | Compiled literal(const string lit); 127 | Compiled fuse(const vector> fns); 128 | Compiled builtin(const string &name); 129 | Compiled all_arguments_evoked(const vector> &args); 130 | Compiled argument_evoked(const shared_ptr &args); 131 | Compiled operator () (const shared_ptr c, const shared_ptr enviroment); 132 | // v.main <+ v.env 133 | string compress(const Compiled &&v); 134 | // a += b 135 | void paircat(Compiled &a, const Compiled &&b); 136 | }; 137 | 138 | class codegen4 { 139 | private: 140 | 141 | // バインド保留のコード と それの実体(または実体を指すポインタ)があるスタックの絶対位置 のペア 142 | deque>> argstack; 143 | deque> argstack_code; 144 | 145 | map bind; 146 | map bindinfo; 147 | set in_recursion; 148 | int stack_height = 0; 149 | bool is_root = true; 150 | 151 | public: 152 | bool human = false; 153 | codegen4() {} 154 | codegen4(bool h) : human(h) {} 155 | ~codegen4() {} 156 | string print_rel(int rel); 157 | Compiled evoke_rel(int rel); 158 | Compiled copy_rel(int rel); 159 | Compiled literal(const string lit); 160 | Compiled fuse(const vector> fns); 161 | Compiled builtin(const string &name); 162 | Compiled all_arguments_evoked(const vector> &args); 163 | Compiled argument_compiled(const string &ident , const shared_ptr &arg); 164 | Compiled operator () (const shared_ptr c, const shared_ptr enviroment); 165 | // v.main <+ v.env 166 | string compress(const Compiled &&v); 167 | // a += b 168 | void paircat(Compiled &a, const Compiled &&b); 169 | }; 170 | 171 | class codegen5 { 172 | private: 173 | 174 | // バインド保留のコード と それの実体(または実体を指すポインタ)があるスタックの絶対位置 のペア 175 | deque>> argstack; 176 | deque> argstack_code; 177 | 178 | deque reserved; 179 | map reserved_bind; 180 | 181 | map bind; 182 | map bindinfo; 183 | set in_recursion; 184 | int stack_height = 0; 185 | bool is_root = true; 186 | 187 | public: 188 | bool human = false; 189 | codegen5() {} 190 | codegen5(bool h) : human(h) {} 191 | ~codegen5() {} 192 | string print_rel(int rel); 193 | Compiled evoke_rel(int rel); 194 | Compiled copy_rel(int rel); 195 | Compiled literal(const string lit); 196 | Compiled fuse(const vector> fns); 197 | Compiled builtin(const string &name); 198 | Compiled all_arguments_evoked(); 199 | string get_name(string name); 200 | Compiled argument_evoked( const shared_ptr &arg); 201 | Compiled argument_compiled(const string &ident , const shared_ptr &arg); 202 | // string argument_signature(const Type &); 203 | // string type_signature(const deque &type, const string &name); 204 | 205 | string vardef(const string &name, const TypeSignature &typesig); 206 | string argdef(const TypeSignature &typesig, bool reserve = false); 207 | 208 | Compiled operator () (const shared_ptr c, const shared_ptr enviroment, bool); 209 | // v.main <+ v.env 210 | string compress(const Compiled &&v); 211 | // a += b 212 | void paircat(Compiled &a, const Compiled &&b); 213 | }; 214 | 215 | class codegen6 { 216 | private: 217 | stack barstack; 218 | stack> argstack; 219 | static map> bind; 220 | static map> type_constructors; // TODO: スコープいいの? 221 | // static map data_bind; 222 | int pseudo_func_counter = 0; 223 | 224 | public: 225 | codegen6() {} 226 | ~codegen6() {} 227 | // string print_data_structure(const DataStructure &ds); 228 | // DataStructure parse_data_structure(const shared_ptr &c); 229 | string print_type_to(const TypeSignature &ty); 230 | string print_type_from(const deque &tys, const shared_ptr &lam); 231 | string print_decl(string name, const TypeSignature &type, bool pointer=false); 232 | string print_def(string name, const shared_ptr& code); 233 | Compiled operator () (const shared_ptr &); 234 | // v.main <+ v.env 235 | string compress(const Compiled &&v); 236 | // a += b 237 | void paircat(Compiled &a, const Compiled &&b); 238 | }; 239 | 240 | 241 | template 242 | class pseudo_map { 243 | public: 244 | T& operator[](const Key& x); 245 | bool contains(const Key& k) const; 246 | deque &get_keys() { return keys; } 247 | size_t size() const { return keys.size(); } 248 | private: 249 | deque keys; 250 | deque vals; 251 | }; 252 | 253 | template 254 | T& pseudo_map::operator[](const Key& x) { 255 | if (contains(x)) { 256 | return vals[distance(keys.begin(), find(keys.begin(), keys.end(), x))]; 257 | } else { 258 | keys.emplace_back(x); 259 | vals.emplace_back(); 260 | return vals.back(); 261 | } 262 | } 263 | 264 | template 265 | bool pseudo_map::contains(const K& k) const { 266 | for (int i = 0; i < keys.size(); i++) { 267 | if (keys[i] == k) return true; 268 | } 269 | return false; 270 | } 271 | 272 | 273 | class codegen7 { 274 | private: 275 | stack> argstack; 276 | stack> dummy_argstack; 277 | static map data_bind; // TODO: スコープいいの? 278 | static pseudo_map, string> type_constrs; // コンストラクタのオーバーロードが出来ないので名前を保存しておく 279 | static map> spvals; 280 | // fuseは特別な名前で実体が作られるので元の名前からその名前への写像 281 | static map fuse_bind; 282 | 283 | // TODO hashを作ってunordered_mapに作った型情報を保存して使い回すようにする 284 | static pseudo_map tmptypes; 285 | // 多相型について、実際に定義しなければならないデータ構造のリスト 286 | pseudo_map defined_polymos; 287 | // 多相型の単純なリスト 288 | map> polymos; 289 | // deque tmptypes; 290 | // deque tmptypes_name; 291 | 292 | static unsigned int type_count; 293 | static unsigned int dummy_count; 294 | 295 | public: 296 | codegen7(stack> init_argstack) { argstack = init_argstack; } 297 | codegen7() {} 298 | ~codegen7() {} 299 | Compiled operator () (const shared_ptr &c); 300 | Compiled fuse(const shared_ptr &c); 301 | Compiled define(string name, const shared_ptr& code); 302 | Compiled print_constructor(string type_name, const TypeSignature& newtype, int rtti=-1); 303 | Compiled type_def(const string newtype_name, const TypeSignature &newtype); 304 | string print_def(string name, const shared_ptr& code); 305 | Compiled print_decl(std::string, const TypeSignature&); 306 | tuple print_data_structure(const TypeSignature type, string type_name="", const map ¶ms={}); 307 | string print_type_from(const deque &tys, const shared_ptr &lam); 308 | string print_polymos(); 309 | string c_type_name(string s, bool bPrefix = true); 310 | string typesig_to_typename(const TypeSignature &type); 311 | string typesig_to_constructor(const TypeSignature &type); 312 | string new_tmptype(const TypeSignature type); 313 | string new_dummy_var(); 314 | void paircat(tuple &x, const tuple &&y); 315 | int spval_to_int(SpecialValue sp); 316 | bool is_spval(string a); 317 | // v.main <+ v.env 318 | string compress(const Compiled &&v); 319 | string compress(const Compiled &v); 320 | // a += b 321 | void paircat(Compiled &a, const Compiled &&b); 322 | void paircat(Compiled &a, const Compiled &b); 323 | }; 324 | 325 | class ocamlgen { 326 | private: 327 | stack> argstack; 328 | static map data_bind; // TODO: スコープいいの? 329 | 330 | public: 331 | ocamlgen() {} 332 | ~ocamlgen() {} 333 | Compiled operator () (const shared_ptr &c); 334 | string print_type_from(const deque &tys, const shared_ptr &lam); 335 | string print_def(string name, const shared_ptr& code); 336 | string print_data_structure(const TypeSignature type); 337 | string ocaml_type_name(string s); 338 | // v.main <+ v.env 339 | string compress(const Compiled &&v); 340 | // a += b 341 | void paircat(Compiled &a, const Compiled &&b); 342 | }; 343 | 344 | // pair codegen(CodegenFlow); 345 | string fasm(const vector &sl); 346 | string fasm(string); 347 | void rename_variables(const shared_ptr c); 348 | 349 | 350 | 351 | #define CODEGEN_H 352 | #endif 353 | -------------------------------------------------------------------------------- /codegen1.cpp: -------------------------------------------------------------------------------- 1 | 2 | pair 3 | codegen::operator () (const shared_ptr c) { 4 | 5 | string res = ""; 6 | string env = ""; 7 | 8 | for (int i = c->args.size()-1; i >= 0; i--) { 9 | argstack.push_back(c->args[i]); 10 | } 11 | 12 | if (c->l) { 13 | // instant function call 14 | 15 | auto _argstack = this->argstack; 16 | for (auto argname : c->l->argnames) { 17 | if (_argstack.empty()) { 18 | // unbinded.push_back(argname); 19 | return make_pair("", ""); 20 | } else { 21 | cout << argname << ":" << *_argstack.back() << endl << endl; 22 | 23 | if (_argstack.back()->arity == 0 && is_root) { 24 | outprg(env, argname + ":"); 25 | is_root = true; 26 | this->argstack.clear(); 27 | outprg(env, env, this->operator()(_argstack.back())); 28 | outprg(env, "ret\n"); 29 | 30 | bind[argname] = shared_ptr(); 31 | } else { 32 | bind[argname] = _argstack.back(); 33 | } 34 | 35 | _argstack.pop_back(); 36 | } 37 | // defined.insert(argname); 38 | } 39 | this->argstack = _argstack; 40 | 41 | is_root = true; 42 | outprg(res, env, this->operator()(c->l->body)); 43 | 44 | return make_pair(res, env); 45 | } 46 | else if (c->lit.val == "fuse") { 47 | } 48 | else if (builtin_functions.contains(c->lit.val)) { 49 | // builtin-function call 50 | 51 | if (bf2arity.at(c->lit.val) != argstack.size()) return make_pair("", ""); 52 | 53 | cout << "buitin-function call" << endl; 54 | cout << *c <operator()(arg)); 63 | // copy(argstack.begin(), argstack.end(), back_inserter(_argstack)); 64 | } 65 | argstack.clear(); 66 | 67 | outprg(res, c->lit.val); 68 | } 69 | else if (is_literal(c->lit.val)) { 70 | // literal 71 | 72 | cout << "literal" << endl; 73 | cout << *c <operator()(arg)); 80 | // copy(argstack.begin(), argstack.end(), back_inserter(_argstack)); 81 | } 82 | argstack.clear(); 83 | 84 | 85 | outprg(res, "push "+c->lit.val); 86 | } 87 | else { 88 | // general function call 89 | 90 | // NOTE: spill counter cuz it's grobval 91 | const unsigned fnidx = function_call_counter++; 92 | const unsigned argnum = argstack.size(); 93 | const bool is_recursive = !bind.contains(c->lit.val); 94 | 95 | cout << "general function call: " << c->lit.val << endl; 96 | cout << "current stack: "; 97 | SCOUT(argstack); 98 | 99 | if (!bind[c->lit.val].get()) { 100 | outprg(res, "call " + c->lit.val); 101 | } 102 | else if (bind[c->lit.val]->arity - argnum > 0) { 103 | cout << "few !!" << endl; 104 | // copy(argstack.begin(), argstack.end(), back_inserter(bind[c->lit.val]->args)); 105 | // outprg(res, env, this->operator()(c->l->body)); 106 | return make_pair("",""); 107 | } 108 | else { 109 | outprg(res, ";; " + c->lit.val); 110 | 111 | //body call 112 | is_root = false; 113 | outprg(res, env, this->operator()(bind[c->lit.val])); 114 | 115 | argstack.clear(); 116 | } 117 | } 118 | 119 | 120 | return make_pair(res, env); 121 | } 122 | -------------------------------------------------------------------------------- /codegen2.cpp: -------------------------------------------------------------------------------- 1 | 2 | StackLanguage 3 | codegen2::operator () (const shared_ptr c) { 4 | 5 | StackLanguage res {}; 6 | 7 | for (int i = c->args.size()-1; i >= 0; i--) { 8 | argstack.push_back(c->args[i]); 9 | } 10 | 11 | if (c->l) { 12 | // instant function call 13 | 14 | auto _argstack = this->argstack; 15 | unsigned kyomu = 0; 16 | for (auto argname : c->l->argnames) { 17 | if (_argstack.empty()) { 18 | cout << argname << endl; 19 | unbinded.push_back(argname); 20 | kyomu++; 21 | } else { 22 | cout << argname << ":" << *_argstack.back() << endl << endl; 23 | 24 | outprg(res.env, ":" + argname); 25 | is_root = true; 26 | this->argstack.clear(); 27 | outenv(res, this->operator()(_argstack.back())); 28 | if (_argstack.back()->arity != 0) { 29 | outprg(res.env, "decbsp"+to_string(_argstack.back()->arity)); 30 | outprg(res.env, "rewind"+to_string(_argstack.back()->arity)); 31 | } 32 | outprg(res.env, ";"); 33 | 34 | bind[argname] = _argstack.back(); 35 | _argstack.pop_back(); 36 | } 37 | defined.insert(argname); 38 | } 39 | this->argstack = _argstack; 40 | 41 | // reverse(unbinded.end()-kyomu, unbinded.end()); 42 | 43 | is_root = true; 44 | outroot(res, this->operator()(c->l->body)); 45 | 46 | return res; 47 | } 48 | else if (c->lit.val == "fuse") { 49 | // fuse 50 | 51 | // NOTE: only see direct arguments 52 | Guard guard = get_guard(c->args); 53 | GuardType gtype = get_guard_type(c->args); 54 | 55 | switch (gtype) { 56 | case GTYPE_COUNTABLE_FINITE: { 57 | // fuseのargumentは関係ないので消しておく 58 | // TODO: これだと、最初のstackに詰める処理が無駄... 59 | for (int i = 0; i < c->args.size(); i++) 60 | argstack.pop_back(); 61 | 62 | // for (auto a : argstack) { 63 | // outprg(res, ":)"); 64 | // stringstream ss; 65 | // ss << *a; 66 | // outprg(res, ss.str()); 67 | // } 68 | 69 | // TODO: ここでもしargstackが空であれば、スタックから読み込むべき 70 | 71 | // run first arg to patternmatch 72 | // TODO: 関数の時は? 73 | // { 74 | // auto _argstack = this->argstack; 75 | // this->argstack.clear(); 76 | // outprg(res, env, this->operator()(_argstack.back())); 77 | // this->argstack = _argstack; 78 | // } 79 | outprg(res.root, "dup1"); 80 | 81 | 82 | for (pair> fnt : guard.finites) { 83 | outprg(res.root, fnt.first); 84 | outprg(res.root, "=="); 85 | outprg(res.root, "if"); 86 | outprg(res.root, "drop"); 87 | { 88 | auto _argstack = this->argstack; 89 | this->argstack.clear(); 90 | outroot(res, this->operator()(fnt.second)); 91 | this->argstack = _argstack; 92 | } 93 | outprg(res.root, "else"); 94 | 95 | conditional_counter++; 96 | } 97 | 98 | // outprg(res.root, "call __pop"); 99 | outprg(res.root, "pop"); 100 | // NOTE: これより内部の引数はcodegen内で実行されるので皮だけでok 101 | for (auto argname : guard.countable->l->argnames) 102 | defined.insert(argname); 103 | outroot(res, this->operator()(guard.countable)); 104 | 105 | for (int w = 0; w < guard.finites.size(); ++w) { 106 | outprg(res.root, "then"); 107 | // outprg(res.root, ";"); 108 | } 109 | } break; 110 | 111 | case GTYPE_FINITE: { 112 | } break; 113 | } 114 | 115 | argstack.clear(); 116 | } 117 | else if (builtin_functions.contains(c->lit.val)) { 118 | // builtin-function call 119 | 120 | if (bf2arity.at(c->lit.val) != argstack.size()) 121 | return res; 122 | 123 | cout << "buitin-function call" << endl; 124 | cout << *c <operator()(arg)); 133 | // copy(argstack.begin(), argstack.end(), back_inserter(_argstack)); 134 | } 135 | argstack.clear(); 136 | 137 | const map forth_builtin = { 138 | { "add", "+" }, 139 | { "negate", "negate" }, 140 | { "sub", "-" }, 141 | { "mul", "*" }, 142 | { "div", "/" }, 143 | }; 144 | 145 | outprg(res.root, forth_builtin.at(c->lit.val)); 146 | } 147 | else if (is_literal(c->lit.val)) { 148 | // literal 149 | 150 | cout << "literal" << endl; 151 | cout << *c <operator()(arg)); 158 | // copy(argstack.begin(), argstack.end(), back_inserter(_argstack)); 159 | } 160 | argstack.clear(); 161 | 162 | outprg(res.root, c->lit.val); 163 | } 164 | else { 165 | // general function call 166 | 167 | // NOTE: spill counter cuz it's grobval 168 | const unsigned fnidx = function_call_counter++; 169 | const unsigned argnum = argstack.size(); 170 | const bool is_recursive = !defined.contains(c->lit.val); 171 | 172 | cout << "general function call: " << c->lit.val << endl; 173 | cout << "current stack: "; 174 | SCOUT(argstack); 175 | 176 | auto _argstack = argstack; 177 | for (auto arg : _argstack) { 178 | argstack = {}; 179 | is_root = false; 180 | if (arg->arity == 0) { 181 | outroot(res, this->operator()(arg)); 182 | } else { 183 | this->insfunc_counter++; 184 | outprg(res.root, "'F"+to_string(this->insfunc_counter)); 185 | outprg(res.env, ": F"+to_string(this->insfunc_counter)); 186 | outenv(res, this->operator()(arg)); 187 | // outprg(res.env, "decbsp"+to_string(arg->l->argnames.size())); 188 | outprg(res.env, ";"); 189 | } 190 | // copy(argstack.begin(), argstack.end(), back_inserter(_argstack)); 191 | } 192 | argstack.clear(); 193 | 194 | // call actual function 195 | if (find(unbinded.begin(), unbinded.end(), c->lit.val) != unbinded.end()) { 196 | // if it's unbinded arg, let it get from fstack 197 | int dist = abs(distance(unbinded.begin(), find(unbinded.begin(), unbinded.end(), c->lit.val))) + 1; 198 | 199 | if (c->args.size() == 0) { 200 | outprg(res.root, "dup" + to_string(dist)); 201 | } else { 202 | outprg(res.root, "!dup" + to_string(dist)); 203 | } 204 | } else { 205 | outprg(res.root, c->lit.val); 206 | } 207 | } 208 | 209 | 210 | return res; 211 | } 212 | -------------------------------------------------------------------------------- /codegen3.cpp: -------------------------------------------------------------------------------- 1 | /*** 2 | * codegen ver.3 3 | * C備え付けのスタックと、一本のスタックを用いて計算する 4 | * 5 | * (|args ...| 6 | * body 7 | * ) a b c ... 8 | * 関数と引数らで構成されるコードを翻訳する。 9 | * 基本は、まずは関数のarityを確かめて関数が食う分の引数だけ実行時メモリに実体を作らせてポインタを積む、 10 | * 内部でargstackに残りの引数は入れておく。関数内部へと移る前に内部で束縛の処理をやっておく。 11 | * できたら、bodyを同様に翻訳していく。argstackは食う引数を云々してる時に足りない場合に補充する(部分適用)。 12 | * 13 | * (|x| add x) 3 7 14 | * 15 | * 例えば上のコードを翻訳していく。[実行時スタック]{束縛情報}[argstack]で状況を書いていく。 16 | * まずは、外側の引数の3、7をargstackに積む。 17 | * []{}[7 3] 18 | * xを取る関数がarity1であることを確認してargstackを削って、束縛の処理及び実行時メモリに実体を作る。 19 | * [3]{x=3}[7] 20 | * ここで内部に移る。ここでは関数がaddで引数がx。まずは引数をargstackへ 21 | * [3]{x=3}[x 7] 22 | * addがarity2であることを確認して、2つ食う。 23 | * [3 7 x]{x=3}[] 24 | * addが実行され、 25 | * [3 10]{x=3}[] 26 | * 関数抜け出し(束縛していたのはxだったので、これを開放して戻り値をコピー) 27 | * [10]{}[] 28 | ***/ 29 | 30 | 31 | #include "emelio.h" 32 | #include "util.h" 33 | #include "notation.h" 34 | #include "codegen.h" 35 | 36 | #include 37 | string 38 | codegen3::compress(const Compiled &&v) { 39 | return v.body + v.env; 40 | } 41 | 42 | void 43 | codegen3::paircat(Compiled &x, const Compiled &&v) { 44 | x.body += v.body; 45 | x.env += v.env; 46 | } 47 | 48 | void operator+=(Compiled& lhs, const Compiled&& rhs) { 49 | lhs.body += rhs.body; 50 | lhs.env += rhs.env; 51 | } 52 | 53 | void operator<<=(string& lhs, const Compiled&& rhs) { 54 | lhs += rhs.body + rhs.env; 55 | } 56 | 57 | vector hypes; 58 | 59 | // Offsetがrelのスタック内容を実行する 60 | Compiled codegen3::evoke_rel(int rel) { 61 | if (rel < 0) { 62 | return Compiled {"(SP+("+to_string(rel-stack_height)+"))->fp();\n"}; 63 | } else { 64 | return Compiled {"(MEM+("+to_string(rel-1)+"))->fp();\n"}; 65 | } 66 | } 67 | 68 | // Offsetがrelのスタック内容をコピーする 69 | Compiled codegen3::copy_rel(int rel) { 70 | return Compiled {"PUSHV(("+print_rel(rel)+")->val);\n"}; 71 | } 72 | 73 | // Offsetがrelのスタック内容 74 | string codegen3::print_rel(int rel) { 75 | if (rel < 0) { 76 | return "SP+("+to_string(rel-stack_height)+")"; 77 | } else { 78 | return "MEM+("+to_string(rel-1)+")"; 79 | } 80 | } 81 | 82 | Compiled 83 | codegen3::literal(const string lit) { 84 | if (is_number(lit)) { 85 | return Compiled {"PUSHV("+lit+");\n"}; 86 | } else { 87 | return Compiled {"PUSHS("+lit+");\n"}; 88 | } 89 | } 90 | 91 | 92 | Compiled 93 | codegen3::fuse(const vector> fns) { 94 | Compiled res; 95 | 96 | // NOTE: only see direct arguments 97 | Guard guard = get_guard(fns); 98 | GuardType gtype = get_guard_type(fns); 99 | 100 | switch (gtype) { 101 | case GTYPE_COUNTABLE_FINITE: { 102 | res.body += "if (false) ;\n"; 103 | for (auto p : guard.finites) { 104 | auto tmp_bind = this->bind; 105 | this->stack_height = 0; 106 | this->argstack = {}; 107 | res.body += "else if (("+print_rel(-1)+")->val=="+p.first+") {\n"; 108 | res += this->operator ()(p.second, nullptr/*TODO*/); 109 | res.body += "}\n"; 110 | this->bind = tmp_bind; 111 | } 112 | res.body += "else {\n"; 113 | auto tmp_bind = this->bind; 114 | res += this->operator ()(guard.countable, nullptr/*TODO*/); 115 | this->bind = tmp_bind; 116 | res.body += "}\n"; 117 | } break; 118 | 119 | case GTYPE_FINITE: { 120 | } break; 121 | } 122 | 123 | // argstack.clear(); 124 | return res; 125 | } 126 | 127 | Compiled 128 | codegen3::builtin(const string &name) { 129 | Compiled res; 130 | 131 | const map c_builtin = { 132 | { "add", "0" }, 133 | { "sub", "1" }, 134 | { "mul", "2" }, 135 | { "negate", "3" }, 136 | { "div", "4" }, 137 | }; 138 | res.body += name+"();\n"; 139 | int ar = bf2arity.at(name); 140 | this->stack_height -= ar-1; 141 | 142 | return res; 143 | } 144 | 145 | Compiled 146 | codegen3::all_arguments_evoked(const vector> &args) { 147 | Compiled res; 148 | 149 | while (!argstack.empty()) { 150 | if (argstack_code.back()->arity == 0) { 151 | res += copy_rel(argstack.back()); 152 | } else { 153 | res += evoke_rel(argstack.back()); 154 | } 155 | argstack.pop_back(); 156 | argstack_code.pop_back(); 157 | } 158 | 159 | auto tmp_bind = this->bind; 160 | for (int i = args.size()-1; i >= 0; i--) { 161 | // 引数もR1実行 162 | res += this->operator()(args[i], nullptr); 163 | this->bind = tmp_bind; 164 | } 165 | 166 | return res; 167 | } 168 | 169 | Compiled 170 | codegen3::argument_evoked(const shared_ptr &c) { 171 | Compiled res; 172 | 173 | auto tmp_bind = this->bind; 174 | res += this->operator()(c, nullptr); 175 | this->bind = tmp_bind; 176 | 177 | return res; 178 | } 179 | 180 | 181 | 182 | //Compiled 183 | //codegen3::argument_holded() { 184 | // while (!argstack.empty()) { 185 | // res.body += evoke_rel(argstack.back()); 186 | // argstack.pop_back(); 187 | // } 188 | 189 | // auto tmp_bind = this->bind; 190 | // for (int i = c->args.size()-1; i >= 0; i--) { 191 | // // 引数もR1実行 192 | // paircat(res, this->operator()(c->args[i])); 193 | // this->bind = tmp_bind; 194 | // } 195 | //} 196 | 197 | 198 | // TODO: いづれ型情報とかつけるときのことも考えてこれはスマートじゃないので、Lambdaとかを渡したほうが良い気がする 199 | // とにかく、codeを処理するのにその上の引数確保情報も必要ということ 200 | // そんなのcallして帰ってきてからで良いやんという意見もあるけど、名前callの場合面倒だし、そちらで綺麗に解決しないのがhypeを作らないといけなくなった根源かも 201 | Compiled 202 | codegen3::operator () (const shared_ptr c, const shared_ptr envl) { 203 | Compiled res; 204 | 205 | cout << *c << endl << endl; 206 | 207 | if (is_literal(c->lit.val)) { 208 | // const unsigned fnidx = function_call_counter++; 209 | 210 | // res.env += "void LIT"+to_string(fnidx)+"() {\n"; 211 | // res.env += "PUSHV("+c->lit.val+");\n"; 212 | // res.env += "return;\n"; 213 | // res.env += "}\n"; 214 | 215 | assert(c->args.size() == 0); 216 | this->stack_height++; 217 | res = literal(c->lit.val); 218 | } 219 | else if (builtin_functions.contains(c->lit.val)) { 220 | // res.body += "PUSHV(0); POP();\n"; 221 | if (c->lit.val == "fuse") { 222 | res = fuse(c->args); 223 | } else { 224 | res += all_arguments_evoked(c->args); 225 | 226 | res += builtin(c->lit.val); 227 | // res.body += "HP["+c_builtin.at(c->lit.val)+"]();\n"; 228 | } 229 | 230 | // res.body += "*STACK("+to_string(ar+2)+") = *TOP();\n"; 231 | // for (int i = ar-1 + (ar != 0 ? 1 : 0)/*いらない方の戻り値分*/; i >= 0; i--) { 232 | // res.body += "MPOP();\n"; 233 | // this->stack_height--; 234 | // } 235 | } 236 | else { 237 | const unsigned fnidx = function_call_counter++; 238 | 239 | hypes.emplace_back(0); 240 | 241 | // if (c->args.size() != 0 && c->arity == 0) { 242 | // res.body += "PUSHV(0); POP();\n"; 243 | // hypes.back()++; 244 | // this->stack_height++; 245 | // } 246 | 247 | map binded_with; // keyの位置にbindされるべきargnameのindex 248 | if (c->l) { 249 | auto tmp_stack = argstack; 250 | auto tmp_stackh = stack_height; 251 | for (int i = c->args.size()-1; i >= 0; i--) { 252 | tmp_stackh++; 253 | tmp_stack.emplace_back(tmp_stackh); 254 | } 255 | 256 | int i = 0, j =0; 257 | for (auto a : c->l->argnames) { 258 | if (tmp_stack.empty()) { 259 | i++; 260 | // bind[a] = BindInfo{-i}; 261 | } else { 262 | binded_with[tmp_stack.back()] = j; 263 | // bind[a] = BindInfo{tmp_stack.back()}; 264 | tmp_stack.pop_back(); 265 | } 266 | j++; 267 | } 268 | } 269 | 270 | 271 | auto tmp_bind = this->bind; 272 | auto tmp_stackh = stack_height; 273 | auto tmp_stack = argstack; 274 | auto tmp_stack_code = argstack_code; 275 | auto tmp_hypes = hypes; 276 | // cout << c->args.size() << " arguments {" << endl; 277 | for (int i = c->args.size()-1; i >= 0; i--) { 278 | // 引数はまとめながらラムダ抽象 - (HACK: arityが0ならR1実行) 279 | // 今はまとめはしない TODO: キャプチャーをやらないなら良さそう 280 | tmp_stackh++; 281 | hypes.clear(); 282 | tmp_hypes.back()++; 283 | this->stack_height = 0; 284 | this->argstack = {}; 285 | tmp_stack.emplace_back(tmp_stackh); 286 | tmp_stack_code.emplace_back(c->args[i]); 287 | 288 | if (c->args[i]->arity == 0) { 289 | res += this->operator()(c->args[i], nullptr); 290 | } else { 291 | int binded_with_arg = binded_with[tmp_stackh]; 292 | res.body += "PUSHF(F"+to_string(fnidx)+"A"+to_string(i)+");\n"; 293 | res.env += "void F"+to_string(fnidx)+"A"+to_string(i)+"() {\n"; 294 | res.env += "union memory_t *MEM = SP;\n"; 295 | if (c->l && c->l->argqualities[binded_with_arg].recursive) { 296 | // in_recursive.insert(c->l->argnames[binded_with_arg]); 297 | res.env += "static void(*"+c->l->argnames[binded_with_arg]+")() = F"+to_string(fnidx)+"A"+to_string(i)+";\n"; 298 | } 299 | res.env <<= this->operator()(c->args[i], nullptr); 300 | res.env += "return;\n"; 301 | res.env += "}\n"; 302 | } 303 | } 304 | // cout << "}" << endl; 305 | this->bind = tmp_bind; 306 | this->stack_height = tmp_stackh; 307 | this->argstack = tmp_stack; 308 | this->argstack_code = tmp_stack_code; 309 | hypes = tmp_hypes; 310 | 311 | // ここでhypeが解決されるかどうか 312 | // 解決されるなら0にしておいて以降のbodyを生成する 313 | // 奥から、解決条件で累積していくみたいな処理 314 | bool beHypeResolved = c->args.size() != 0 && c->arity == 0; 315 | int local_hype = hypes.size(); 316 | 317 | if (c->l) { 318 | int i = 0, j=0; 319 | for (auto a : c->l->argnames) { 320 | if (this->argstack.empty()) { 321 | i++; 322 | bind[a] = -i; 323 | bindinfo[a] = BindInfo{nullptr}; 324 | } else { 325 | bind[a] = this->argstack.back(); 326 | bindinfo[a] = BindInfo{this->argstack_code.back()}; 327 | this->argstack.pop_back(); 328 | this->argstack_code.pop_back(); 329 | } 330 | j++; 331 | } 332 | 333 | auto tmp_bind = this->bind; 334 | res += this->operator()(c->l->body, c->l); 335 | if (beHypeResolved) { 336 | // local_hypeまでhypeを折りたたむ 337 | for (int i = hypes.size()-1; i >= local_hype; i--) { 338 | hypes[local_hype-1] += hypes.back(); 339 | hypes.pop_back(); 340 | } 341 | } 342 | this->bind = tmp_bind; 343 | } 344 | else { 345 | // 文字参照 346 | 347 | // if (builtin_functions.contains(c->lit.val)) { 348 | // res.body += c->lit.val+"();\n"; 349 | // } else 350 | if (!bind.contains(c->lit.val)) { 351 | // とりあえず何もミスってなければ再帰 352 | res.body += c->lit.val + "("; 353 | 354 | res.body += ");\n"; 355 | // 参照先コードのarityを見て、0なら値をコピってスタックにのっけるだけ 356 | } else if (!bindinfo[c->lit.val].code || bindinfo[c->lit.val].code->arity == 0) { 357 | res += copy_rel(bind[c->lit.val]); 358 | // それ以外なら、ちゃんとcallする 359 | } else { 360 | res += evoke_rel(bind[c->lit.val]); 361 | } 362 | this->stack_height++; 363 | 364 | cout << "ll" << endl; 365 | cout << res.body << endl; 366 | } 367 | 368 | 369 | 370 | // 戻り値コピー 371 | // TODO: pointerより大きい時は、ヒープに実体を置いてとかしないと駄目かもね... 372 | // if (beHypeResolved) { 373 | // if (c->l) { 374 | // // 明日:hypeをメンバにして、解決するまでどんどん足していく。ここで解決。 375 | // res.body += "*STACK("+to_string(hypes.back()+1)+") = *TOP();\n"; 376 | // // 部分適用なら(c->args.size() == c->l->body->arityでないなら)、 377 | // // MPOPはc->l->body->arityを発行する 378 | // for (int i = hypes.back()/*TODO*/; i >= 1; i--) { 379 | // res.body += "MPOP();\n"; 380 | // this->stack_height--; 381 | // } 382 | // } else { 383 | // res.body += "*STACK("+to_string(1+2)+") = *TOP();\n"; 384 | // // NOTE: ここは内容不明のhikisuu文字。 385 | // // (|a b| a 3)とか 386 | // // arityは種システムを制作してarityを保証してから 387 | // // 今は値と信じて1と決め打ちしておく 388 | 389 | // for (int i = 1 + (1 == 0 ? 0 : 1)/*いらない方の戻り値分*/; i >= 1; i--) { 390 | // res.body += "MPOP();\n"; 391 | // this->stack_height--; 392 | // } 393 | // } 394 | // hypes.pop_back(); 395 | // } 396 | } 397 | 398 | // 戻り値コピーv.2 envlを用いたい! 399 | if (envl) { 400 | res.body += "*STACK("+to_string(envl->argnames.size()+1)+") = *TOP();\n"; 401 | for (int i = 0; i < (int)envl->argnames.size(); i++) { 402 | res.body += "MPOP();\n"; 403 | this->stack_height--; 404 | } 405 | } 406 | 407 | // cout << res.body << endl << res.env << endl; 408 | return res; 409 | } 410 | -------------------------------------------------------------------------------- /codegen4.cpp: -------------------------------------------------------------------------------- 1 | /*** 2 | * codegen ver.3 3 | * C備え付けのスタックと、一本のスタックを用いて計算する 4 | * 5 | * (|args ...| 6 | * body 7 | * ) a b c ... 8 | * 関数と引数らで構成されるコードを翻訳する。 9 | * 基本は、まずは関数のarityを確かめて関数が食う分の引数だけ実行時メモリに実体を作らせてポインタを積む、 10 | * 内部でargstackに残りの引数は入れておく。関数内部へと移る前に内部で束縛の処理をやっておく。 11 | * できたら、bodyを同様に翻訳していく。argstackは食う引数を云々してる時に足りない場合に補充する(部分適用)。 12 | * 13 | * (|x| add x) 3 7 14 | * 15 | * 例えば上のコードを翻訳していく。[実行時スタック]{束縛情報}[argstack]で状況を書いていく。 16 | * まずは、外側の引数の3、7をargstackに積む。 17 | * []{}[7 3] 18 | * xを取る関数がarity1であることを確認してargstackを削って、束縛の処理及び実行時メモリに実体を作る。 19 | * [3]{x=3}[7] 20 | * ここで内部に移る。ここでは関数がaddで引数がx。まずは引数をargstackへ 21 | * [3]{x=3}[x 7] 22 | * addがarity2であることを確認して、2つ食う。 23 | * [3 7 x]{x=3}[] 24 | * addが実行され、 25 | * [3 10]{x=3}[] 26 | * 関数抜け出し(束縛していたのはxだったので、これを開放して戻り値をコピー) 27 | * [10]{}[] 28 | ***/ 29 | 30 | 31 | #include "emelio.h" 32 | #include "util.h" 33 | #include "notation.h" 34 | #include "codegen.h" 35 | 36 | #include 37 | string 38 | codegen4::compress(const Compiled &&v) { 39 | return v.body + v.env; 40 | } 41 | 42 | void 43 | codegen4::paircat(Compiled &x, const Compiled &&v) { 44 | x.body += v.body; 45 | x.env += v.env; 46 | } 47 | 48 | // Offsetがrelのスタック内容を実行する 49 | Compiled codegen4::evoke_rel(int rel) { 50 | if (rel < 0) { 51 | return Compiled {"(SP+("+to_string(rel-stack_height)+"))->fp();\n"}; 52 | } else { 53 | return Compiled {"(MEM+("+to_string(rel-1)+"))->fp();\n"}; 54 | } 55 | } 56 | 57 | // Offsetがrelのスタック内容をコピーする 58 | Compiled codegen4::copy_rel(int rel) { 59 | return Compiled {"PUSHV(("+print_rel(rel)+")->val);\n"}; 60 | } 61 | 62 | // Offsetがrelのスタック内容 63 | // relがマイナスのときは直前の関数呼び出しまでの引数を表す 64 | // 関数呼び出し時にはstack_heightは0に初期化され、そこからまた追跡を始める 65 | string codegen4::print_rel(int rel) { 66 | if (rel < 0) { 67 | return "SP+("+to_string(rel-stack_height)+")"; 68 | } else { 69 | return "MEM+("+to_string(rel-1)+")"; 70 | } 71 | } 72 | 73 | Compiled 74 | codegen4::literal(const string lit) { 75 | if (is_number(lit)) { 76 | return Compiled {"PUSHV("+lit+");\n"}; 77 | } else { 78 | return Compiled {"PUSHS("+lit+");\n"}; 79 | } 80 | } 81 | 82 | 83 | Compiled 84 | codegen4::fuse(const vector> fns) { 85 | Compiled res; 86 | 87 | // NOTE: only see direct arguments 88 | Guard guard = get_guard(fns); 89 | GuardType gtype = get_guard_type(fns); 90 | 91 | 92 | 93 | switch (gtype) { 94 | case GTYPE_COUNTABLE_FINITE: { 95 | // TODO: 96 | // (|x| ... ) 97 | // (|3| ... ) 98 | // がfuseされていた時、引数は比較用に実体化する(計算する)が、計算した後3の方に行ったらxは使えないので最初の時点で開放するのもありかも(節約) 99 | 100 | int i = 0, j=0; 101 | for (auto a : guard.countable->l->argnames) { 102 | if (this->argstack.empty()) { 103 | i++; 104 | bind[a] = -i; 105 | bindinfo[a] = BindInfo{nullptr}; 106 | } else { 107 | auto arg = this->argstack.back(); 108 | 109 | res += argument_compiled(a, arg.second); 110 | this->argstack.pop_back(); 111 | 112 | bind[a] = stack_height; 113 | bindinfo[a] = BindInfo{arg.second}; 114 | } 115 | j++; 116 | } 117 | 118 | // fuseされた関数の呼び出しは (...) 3 のような即席関数のように感じますが、実行時にしかわからない比較がついてくるので関数呼び出しのような形に 119 | 120 | res.body += "if (false) ;\n"; 121 | for (auto p : guard.finites) { 122 | // TODO: fuse の即席実行では-1ではない。。。 123 | res.body += "else if (("+/*print_rel(-1)*/string("SP-1")+")->val=="+p.first+") {\n"; 124 | { 125 | auto tmp_bind = bind; 126 | auto tmp_stack = argstack; 127 | auto tmp_stackh = stack_height; 128 | argstack = {}; 129 | res += codegen4::operator()(p.second, guard.countable->l); 130 | bind = tmp_bind; 131 | argstack = tmp_stack; 132 | stack_height = tmp_stackh; 133 | } 134 | res.body += "}\n"; 135 | } 136 | 137 | res.body += "else {\n"; 138 | auto tmp_bind = this->bind; 139 | res += this->operator ()(guard.countable->l->body, guard.countable->l); 140 | this->bind = tmp_bind; 141 | res.body += "}\n"; 142 | } break; 143 | 144 | case GTYPE_FINITE: { 145 | } break; 146 | } 147 | 148 | // argstack.clear(); 149 | return res; 150 | } 151 | 152 | Compiled 153 | codegen4::builtin(const string &name) { 154 | Compiled res; 155 | 156 | const map c_builtin = { 157 | { "add", "0" }, 158 | { "sub", "1" }, 159 | { "mul", "2" }, 160 | { "negate", "3" }, 161 | { "div", "4" }, 162 | }; 163 | res.body += name+"();\n"; 164 | int ar = bf2arity.at(name); 165 | this->stack_height -= ar-1; 166 | 167 | return res; 168 | } 169 | 170 | Compiled 171 | codegen4::all_arguments_evoked(const vector> &args) { 172 | Compiled res; 173 | 174 | auto tmp_bind = bind; 175 | auto tmp_argstack = argstack; 176 | argstack = {}; 177 | while (!tmp_argstack.empty()) { 178 | auto arg = tmp_argstack.front(); 179 | // ほんとうはarg.secondコンパイルする前に自身はpopbackする 180 | // argとして参照があるので消えないはず 181 | tmp_argstack.pop_front(); 182 | res += this->operator()(arg.second, nullptr); 183 | } 184 | bind = tmp_bind; 185 | argstack = {}; 186 | 187 | 188 | return res; 189 | } 190 | 191 | 192 | // NOTE: argstackからとったなら解放忘れずに 193 | // argとして引数となるCodeを渡すと、関数呼び出しの際に引数の実体化として一般的に行われる処理をargで行います 194 | Compiled 195 | codegen4::argument_compiled(const string &ident , const shared_ptr &arg) { 196 | Compiled res; 197 | 198 | if (arg->arity == 0) { 199 | { 200 | auto tmp_bind = bind; 201 | auto tmp_stack = argstack; 202 | argstack = {}; 203 | res.body <<= codegen4::operator()(arg, nullptr); 204 | bind = tmp_bind; 205 | argstack = tmp_stack; 206 | } 207 | // res.body += "PUSHV("+arg.second->lit.val+");\n"; 208 | } else { 209 | res.body += "PUSHF("+ident+");\n"; 210 | stack_height++; 211 | 212 | res.env += "void "+ident+"() {\n"; 213 | res.env += "union memory_t *MEM = SP;\n"; 214 | // if (c->l && c->l->argqualities[binded_with_arg].recursive) { 215 | // // in_recursive.insert(c->l->argnames[binded_with_arg]); 216 | // res.env += "static void(*"+c->l->argnames[binded_with_arg]+")() = F"+to_string(fnidx)+"A"+to_string(i)+";\n"; 217 | // } 218 | { 219 | auto tmp_bind = bind; 220 | auto tmp_stackh = stack_height; 221 | auto tmp_stack = argstack; 222 | argstack = {}; 223 | stack_height = 0; 224 | res.env <<= codegen4::operator()(arg, nullptr); 225 | bind = tmp_bind; 226 | stack_height = tmp_stackh; 227 | argstack = tmp_stack; 228 | } 229 | res.env += "return;\n"; 230 | res.env += "}\n"; 231 | } 232 | 233 | return res; 234 | } 235 | 236 | 237 | 238 | //Compiled 239 | //codegen4::argument_holded() { 240 | // while (!argstack.empty()) { 241 | // res.body += evoke_rel(argstack.back()); 242 | // argstack.pop_back(); 243 | // } 244 | 245 | // auto tmp_bind = this->bind; 246 | // for (int i = c->args.size()-1; i >= 0; i--) { 247 | // // 引数もR1実行 248 | // paircat(res, this->operator()(c->args[i])); 249 | // this->bind = tmp_bind; 250 | // } 251 | //} 252 | 253 | 254 | // TODO: いづれ型情報とかつけるときのことも考えてこれはスマートじゃないので、Lambdaとかを渡したほうが良い気がする 255 | // とにかく、codeを処理するのにその上の引数確保情報も必要ということ 256 | // そんなのcallして帰ってきてからで良いやんという意見もあるけど、名前callの場合面倒だし、そちらで綺麗に解決しないのがhypeを作らないといけなくなった根源かも 257 | Compiled 258 | codegen4::operator () (const shared_ptr c, const shared_ptr envl) { 259 | Compiled res; 260 | 261 | cout << *c << endl << endl; 262 | 263 | const unsigned fnidx = function_call_counter++; 264 | for (int i = c->args.size()-1; i >= 0; i--) { 265 | if (c->args[i]->arity == 0) { 266 | argstack.emplace_back(make_pair("", c->args[i])); 267 | } else { 268 | //int binded_with_arg = binded_with[tmp_stackh]; 269 | argstack.emplace_back(make_pair("F"+to_string(fnidx)+"A"+to_string(i), c->args[i])); 270 | // res.body += "PUSHF(F"+to_string(fnidx)+"A"+to_string(i)+");\n"; 271 | 272 | } 273 | } 274 | 275 | 276 | if (is_literal(c->lit.val)) { 277 | // const unsigned fnidx = function_call_counter++; 278 | 279 | // res.env += "void LIT"+to_string(fnidx)+"() {\n"; 280 | // res.env += "PUSHV("+c->lit.val+");\n"; 281 | // res.env += "return;\n"; 282 | // res.env += "}\n"; 283 | 284 | assert(c->args.size() == 0); 285 | this->stack_height++; 286 | res = literal(c->lit.val); 287 | } 288 | else if (builtin_functions.contains(c->lit.val)) { 289 | // res.body += "PUSHV(0); POP();\n"; 290 | if (c->lit.val == "fuse") { 291 | // 無駄にargstack積んでるので崩す 292 | for (int i = 0; i < c->args.size(); i++) { 293 | // TODO: ここ大丈夫? 294 | argstack.pop_back(); 295 | } 296 | res = fuse(c->args); 297 | } else { 298 | res += all_arguments_evoked(c->args); 299 | 300 | res += builtin(c->lit.val); 301 | // res.body += "HP["+c_builtin.at(c->lit.val)+"]();\n"; 302 | } 303 | 304 | // res.body += "*STACK("+to_string(ar+2)+") = *TOP();\n"; 305 | // for (int i = ar-1 + (ar != 0 ? 1 : 0)/*いらない方の戻り値分*/; i >= 0; i--) { 306 | // res.body += "MPOP();\n"; 307 | // this->stack_height--; 308 | // } 309 | } 310 | else { 311 | 312 | // hypes.emplace_back(0); 313 | 314 | // if (c->args.size() != 0 && c->arity == 0) { 315 | // res.body += "PUSHV(0); POP();\n"; 316 | // hypes.back()++; 317 | // this->stack_height++; 318 | // } 319 | 320 | // map binded_with; // keyの位置にbindされるべきargnameのindex 321 | // if (c->l) { 322 | // auto tmp_stack = argstack; 323 | // auto tmp_stackh = stack_height; 324 | // for (int i = c->args.size()-1; i >= 0; i--) { 325 | // tmp_stackh++; 326 | // tmp_stack.emplace_back(tmp_stackh); 327 | // } 328 | 329 | // int i = 0, j =0; 330 | // for (auto a : c->l->argnames) { 331 | // if (tmp_stack.empty()) { 332 | // i++; 333 | //// bind[a] = BindInfo{-i}; 334 | // } else { 335 | // binded_with[tmp_stack.back()] = j; 336 | //// bind[a] = BindInfo{tmp_stack.back()}; 337 | // tmp_stack.pop_back(); 338 | // } 339 | // j++; 340 | // } 341 | // } 342 | 343 | 344 | if (c->l) { 345 | int i = 0, j=0; 346 | for (auto a : c->l->argnames) { 347 | if (this->argstack.empty()) { 348 | i++; 349 | bind[a] = -i; 350 | bindinfo[a] = BindInfo{nullptr}; 351 | } else { 352 | auto arg = this->argstack.back(); 353 | 354 | res += argument_compiled(a, arg.second); 355 | this->argstack.pop_back(); 356 | 357 | bind[a] = stack_height; 358 | bindinfo[a] = BindInfo{arg.second}; 359 | } 360 | j++; 361 | } 362 | 363 | auto tmp_bind = this->bind; 364 | res += this->operator()(c->l->body, c->l); 365 | this->bind = tmp_bind; 366 | } 367 | else { 368 | // 文字参照 369 | 370 | // if (builtin_functions.contains(c->lit.val)) { 371 | // res.body += c->lit.val+"();\n"; 372 | // } else 373 | if (!bind.contains(c->lit.val)) { 374 | 375 | // TODO: 引数のコンパイル 376 | for (int i = 0; i < argstack.size(); i++) { 377 | auto arg = this->argstack.front(); 378 | 379 | res += argument_compiled(arg.first, arg.second); 380 | this->argstack.pop_front(); 381 | } 382 | 383 | 384 | // とりあえず何もミスってなければ再帰 385 | res.body += c->lit.val + "("; 386 | 387 | res.body += ");\n"; 388 | // 参照先コードのarityを見て、0なら値をコピってスタックにのっけるだけ 389 | } else if (!bindinfo[c->lit.val].code || bindinfo[c->lit.val].code->arity == 0) { 390 | res += copy_rel(bind[c->lit.val]); 391 | stack_height++; 392 | // それ以外なら、ちゃんとcallする 393 | } else { 394 | for (int i = 0; i < bindinfo[c->lit.val].code->arity; i++) { 395 | auto arg = this->argstack.front(); 396 | 397 | res += argument_compiled(arg.first, arg.second); 398 | this->argstack.pop_front(); 399 | } 400 | 401 | res += evoke_rel(bind[c->lit.val]); 402 | stack_height++; 403 | } 404 | 405 | cout << "ll" << endl; 406 | cout << res.body << endl; 407 | } 408 | } 409 | 410 | // 戻り値コピーv.2 envlを用いたい! 411 | if (envl) { 412 | if (envl->argnames.size() != 0) 413 | // *STACK(1) = *TOP()は実際何の効果もないので省く 414 | { 415 | res.body += "*STACK("+to_string(envl->argnames.size()+1)+") = *TOP();\n"; 416 | } 417 | for (int i = 0; i < (int)envl->argnames.size(); i++) { 418 | res.body += "MPOP();\n"; 419 | this->stack_height--; 420 | } 421 | } 422 | 423 | // cout << res.body << endl << res.env << endl; 424 | return res; 425 | } 426 | -------------------------------------------------------------------------------- /codegen5.cpp: -------------------------------------------------------------------------------- 1 | /*** 2 | * codegen ver.3 3 | * C備え付けのスタックと、一本のスタックを用いて計算する 4 | * 5 | * (|args ...| 6 | * body 7 | * ) a b c ... 8 | * 関数と引数らで構成されるコードを翻訳する。 9 | * 基本は、まずは関数のarityを確かめて関数が食う分の引数だけ実行時メモリに実体を作らせてポインタを積む、 10 | * 内部でargstackに残りの引数は入れておく。関数内部へと移る前に内部で束縛の処理をやっておく。 11 | * できたら、bodyを同様に翻訳していく。argstackは食う引数を云々してる時に足りない場合に補充する(部分適用)。 12 | * 13 | * (|x| add x) 3 7 14 | * 15 | * 例えば上のコードを翻訳していく。[実行時スタック]{束縛情報}[argstack]で状況を書いていく。 16 | * まずは、外側の引数の3、7をargstackに積む。 17 | * []{}[7 3] 18 | * xを取る関数がarity1であることを確認してargstackを削って、束縛の処理及び実行時メモリに実体を作る。 19 | * [3]{x=3}[7] 20 | * ここで内部に移る。ここでは関数がaddで引数がx。まずは引数をargstackへ 21 | * [3]{x=3}[x 7] 22 | * addがarity2であることを確認して、2つ食う。 23 | * [3 7 x]{x=3}[] 24 | * addが実行され、 25 | * [3 10]{x=3}[] 26 | * 関数抜け出し(束縛していたのはxだったので、これを開放して戻り値をコピー) 27 | * [10]{}[] 28 | ***/ 29 | 30 | 31 | #include "emelio.h" 32 | #include "util.h" 33 | #include "notation.h" 34 | #include "codegen.h" 35 | 36 | #include 37 | string 38 | codegen5::compress(const Compiled &&v) { 39 | return v.body + v.env; 40 | } 41 | 42 | void 43 | codegen5::paircat(Compiled &x, const Compiled &&v) { 44 | x.body += v.body; 45 | x.env += v.env; 46 | } 47 | 48 | // Offsetがrelのスタック内容を実行する 49 | Compiled codegen5::evoke_rel(int rel) { 50 | if (rel < 0) { 51 | return Compiled {"(SP+("+to_string(rel-stack_height)+"))->fp();\n"}; 52 | } else { 53 | return Compiled {"(MEM+("+to_string(rel-1)+"))->fp();\n"}; 54 | } 55 | } 56 | 57 | // Offsetがrelのスタック内容をコピーする 58 | Compiled codegen5::copy_rel(int rel) { 59 | return Compiled {"PUSHV(("+print_rel(rel)+")->val);\n"}; 60 | } 61 | 62 | // Offsetがrelのスタック内容 63 | // relがマイナスのときは直前の関数呼び出しまでの引数を表す 64 | // 関数呼び出し時にはstack_heightは0に初期化され、そこからまた追跡を始める 65 | string codegen5::print_rel(int rel) { 66 | if (rel < 0) { 67 | return "SP+("+to_string(rel-stack_height)+")"; 68 | } else { 69 | return "MEM+("+to_string(rel-1)+")"; 70 | } 71 | } 72 | 73 | Compiled 74 | codegen5::literal(const string lit) { 75 | if (is_number(lit)) { 76 | return Compiled {string(lit)}; 77 | } else { 78 | return Compiled {"\""+lit+"\""}; 79 | } 80 | } 81 | 82 | Compiled 83 | codegen5::fuse(const vector> fns) { 84 | Compiled res; 85 | // NOTE: only see direct arguments 86 | Guard guard = get_guard(fns); 87 | GuardType gtype = get_guard_type(fns); 88 | 89 | switch (gtype) { 90 | case GTYPE_COUNTABLE_FINITE: { 91 | // TODO: 92 | // (|x| ... ) 93 | // (|3| ... ) 94 | // がfuseされていた時、引数は比較用に実体化する(計算する)が、計算した後3の方に行ったらxは使えないので最初の時点で開放するのもありかも(節約) 95 | 96 | const unsigned fnidx = function_call_counter++; 97 | int i = 0, j=0; 98 | 99 | for (auto a : guard.countable->l->argnames) { 100 | if (this->argstack.empty()) { 101 | i++; 102 | bind[a] = -i; 103 | bindinfo[a] = BindInfo{nullptr}; 104 | 105 | reserved_bind[a] = reserved.back(); 106 | reserved.pop_back(); 107 | } else { 108 | auto arg = this->argstack.back(); 109 | 110 | res.body += "int " + a + " = "; 111 | res += argument_compiled(a, arg.second); 112 | res.body += ";\n"; 113 | this->argstack.pop_back(); 114 | 115 | bind[a] = stack_height; 116 | bindinfo[a] = BindInfo{arg.second}; 117 | } 118 | j++; 119 | } 120 | 121 | // fuseされた関数の呼び出しは (...) 3 のような即席関数のように感じますが、実行時にしかわからない比較がついてくるので関数呼び出しのような形に 122 | 123 | res.body += "if (false) ;\n"; 124 | for (auto p : guard.finites) { 125 | // TODO: fuse の即席実行では-1ではない。。。 126 | res.body += "else if ("+guard.countable->l->argnames[0]+" == "+p.first+") {\n"; 127 | { 128 | auto tmp_bind = bind; 129 | auto tmp_stack = argstack; 130 | auto tmp_stackh = stack_height; 131 | argstack = {}; 132 | res += codegen5::operator()(p.second, guard.countable->l, true); 133 | bind = tmp_bind; 134 | argstack = tmp_stack; 135 | stack_height = tmp_stackh; 136 | } 137 | res.body += "}\n"; 138 | } 139 | 140 | res.body += "else {\n"; 141 | auto tmp_bind = this->bind; 142 | res += this->operator ()(guard.countable->l->body, guard.countable->l, true); 143 | this->bind = tmp_bind; 144 | res.body += "}\n"; 145 | } break; 146 | 147 | case GTYPE_FINITE: { 148 | } break; 149 | } 150 | 151 | // argstack.clear(); 152 | return res; 153 | } 154 | 155 | Compiled 156 | codegen5::builtin(const string &name) { 157 | Compiled res; 158 | const map c_builtin = { 159 | { "add", "+" }, 160 | { "sub", "-" }, 161 | { "mul", "*" }, 162 | { "negate", "-" }, 163 | { "div", "/" }, 164 | }; 165 | 166 | if (argstack.size() < bf2arity.at(name)) return res; 167 | 168 | if (bf2arity.at(name) == 2) { 169 | auto arg1 = argstack.front(); argstack.pop_front(); 170 | auto arg2 = argstack.front(); argstack.pop_front(); 171 | res += argument_evoked(arg1.second); 172 | res.body += c_builtin.at(name); 173 | res += argument_evoked(arg2.second); 174 | } else if (bf2arity.at(name) == 1) { 175 | auto arg1 = argstack.front(); argstack.pop_front(); 176 | res.body += c_builtin.at(name); 177 | res += argument_evoked(arg1.second); 178 | } 179 | 180 | int ar = bf2arity.at(name); 181 | this->stack_height -= ar-1; 182 | 183 | return res; 184 | } 185 | 186 | // arguments list 187 | Compiled 188 | codegen5::all_arguments_evoked() { 189 | Compiled res; 190 | 191 | auto tmp_bind = bind; 192 | auto tmp_argstack = argstack; 193 | argstack = {}; 194 | while (!tmp_argstack.empty()) { 195 | auto arg = tmp_argstack.front(); 196 | // ほんとうはarg.secondコンパイルする前に自身はpopbackする 197 | // argとして参照があるので消えないはず 198 | tmp_argstack.pop_front(); 199 | res += this->operator()(arg.second, nullptr, false); 200 | res.body += ","; 201 | } 202 | bind = tmp_bind; 203 | argstack = {}; 204 | 205 | // NOTE: 最後のコンマを消す 206 | res.body.erase(res.body.end()-1); 207 | 208 | return res; 209 | } 210 | 211 | Compiled 212 | codegen5::argument_evoked(const shared_ptr &arg) { 213 | Compiled res; 214 | 215 | auto tmp_bind = bind; 216 | auto tmp_argstack = argstack; 217 | argstack = {}; 218 | 219 | res += this->operator()(arg, nullptr, false); 220 | 221 | bind = tmp_bind; 222 | argstack = tmp_argstack; 223 | 224 | return res; 225 | } 226 | 227 | string 228 | codegen5::argdef(const TypeSignature &typesig, bool reserve) { 229 | const unsigned fnidx = function_call_counter++; 230 | string res = ""; 231 | 232 | for (int i = 0; i < typesig.from.size(); i++) { 233 | res += vardef("__" + to_string(fnidx) + "a" + to_string(i), typesig.from[i]) + ","; 234 | if (reserve) reserved.emplace_back("__" + to_string(fnidx) + "a" + to_string(i)); 235 | } 236 | res.erase(res.end()-1); 237 | 238 | return res; 239 | } 240 | 241 | string 242 | codegen5::vardef(const string &name, const TypeSignature &typesig) { 243 | const unsigned fnidx = function_call_counter++; 244 | string res = ""; 245 | const auto normalized = typesig.normalized(); 246 | 247 | if (typesig.from.size() == 0) { 248 | res += get(normalized.to) + " " + name; 249 | } else { 250 | res += get(normalized.to) + "(* " + name + ") ("; 251 | argdef(typesig, false); 252 | } 253 | return res; 254 | } 255 | 256 | //reserveを考慮した名前 257 | string 258 | codegen5::get_name(string name) { 259 | if (reserved_bind.contains(name)) { 260 | return reserved_bind.at(name); 261 | } 262 | return name; 263 | } 264 | 265 | // NOTE: argstackからとったなら解放忘れずに 266 | // argとして引数となるCodeを渡すと、関数呼び出しの際に引数の実体化として一般的に行われる処理をargで行います 267 | Compiled 268 | codegen5::argument_compiled(const string &ident , const shared_ptr &arg) { 269 | Compiled res; 270 | 271 | if (arg->arity == 0) { 272 | { 273 | auto tmp_bind = bind; 274 | auto tmp_stack = argstack; 275 | argstack = {}; 276 | res.body += "int " + ident + " = "; 277 | res.body <<= codegen5::operator()(arg, nullptr, false); 278 | res.body += ";\n"; 279 | bind = tmp_bind; 280 | argstack = tmp_stack; 281 | } 282 | // res.body += "PUSHV("+arg.second->lit.val+");\n"; 283 | } else { 284 | // res.body += ident + "();\n"; 285 | // stack_height++; 286 | 287 | const auto normalized = arg->type.normalized(); 288 | res.env += get(normalized.to) + " " + ident + "(" + argdef(normalized, true) + ") {"; 289 | 290 | // if (c->l && c->l->argqualities[binded_with_arg].recursive) { 291 | // // in_recursive.insert(c->l->argnames[binded_with_arg]); 292 | // res.env += "static void(*"+c->l->argnames[binded_with_arg]+")() = F"+to_string(fnidx)+"A"+to_string(i)+";\n"; 293 | // } 294 | { 295 | auto tmp_bind = bind; 296 | auto tmp_stackh = stack_height; 297 | auto tmp_stack = argstack; 298 | argstack = {}; 299 | stack_height = 0; 300 | res.env <<= codegen5::operator()(arg, nullptr, true); 301 | bind = tmp_bind; 302 | stack_height = tmp_stackh; 303 | argstack = tmp_stack; 304 | } 305 | res.env += "}\n"; 306 | } 307 | 308 | return res; 309 | } 310 | 311 | // TODO: いづれ型情報とかつけるときのことも考えてこれはスマートじゃないので、Lambdaとかを渡したほうが良い気がする 312 | // とにかく、codeを処理するのにその上の引数確保情報も必要ということ 313 | // そんなのcallして帰ってきてからで良いやんという意見もあるけど、名前callの場合面倒だし、そちらで綺麗に解決しないのがhypeを作らないといけなくなった根源かも 314 | Compiled 315 | codegen5::operator () (const shared_ptr c, const shared_ptr envl, bool whole_function) { 316 | Compiled res; 317 | 318 | cout << *c << endl << endl; 319 | 320 | const unsigned fnidx = function_call_counter++; 321 | for (int i = 0; i < c->args.size(); i++) { 322 | if (c->args[i]->arity == 0) { 323 | argstack.emplace_back(make_pair("", c->args[i])); 324 | } else { 325 | //int binded_with_arg = binded_with[tmp_stackh]; 326 | argstack.emplace_back(make_pair("F"+to_string(fnidx)+"A"+to_string(i), c->args[i])); 327 | // res.body += "PUSHF(F"+to_string(fnidx)+"A"+to_string(i)+");\n"; 328 | 329 | } 330 | } 331 | 332 | 333 | if (is_literal(c->lit.val)) { 334 | // const unsigned fnidx = function_call_counter++; 335 | 336 | // res.env += "void LIT"+to_string(fnidx)+"() {\n"; 337 | // res.env += "PUSHV("+c->lit.val+");\n"; 338 | // res.env += "return;\n"; 339 | // res.env += "}\n"; 340 | 341 | assert(c->args.size() == 0); 342 | this->stack_height++; 343 | if (whole_function) res.body += "return "; 344 | res += literal(c->lit.val); 345 | if (whole_function) res.body += ";\n"; 346 | } 347 | else if (builtin_functions.contains(c->lit.val)) { 348 | // res.body += "PUSHV(0); POP();\n"; 349 | if (c->lit.val == "fuse") { 350 | // 無駄にargstack積んでるので崩す 351 | for (int i = 0; i < c->args.size(); i++) { 352 | argstack.pop_back(); 353 | } 354 | res = fuse(c->args); 355 | } else { 356 | res += builtin(c->lit.val); 357 | // res.body += "HP["+c_builtin.at(c->lit.val)+"]();\n"; 358 | } 359 | 360 | // res.body += "*STACK("+to_string(ar+2)+") = *TOP();\n"; 361 | // for (int i = ar-1 + (ar != 0 ? 1 : 0)/*いらない方の戻り値分*/; i >= 0; i--) { 362 | // res.body += "MPOP();\n"; 363 | // this->stack_height--; 364 | // } 365 | } 366 | else { 367 | if (c->l) { 368 | // 即時関数 369 | 370 | int i = 0, j=0; 371 | for (auto a : c->l->argnames) { 372 | if (this->argstack.empty()) { 373 | i++; 374 | bind[a] = -i; 375 | bindinfo[a] = BindInfo{nullptr}; 376 | 377 | // reserved_bind[a] = reserved.back(); 378 | // reserved.pop_back(); 379 | } else { 380 | auto arg = this->argstack.back(); 381 | 382 | // 実体を作って、whole_function呼び 383 | // 関数なら、envを外部に作る 384 | res += argument_compiled(a, arg.second); 385 | 386 | this->argstack.pop_back(); 387 | 388 | bind[a] = stack_height; 389 | bindinfo[a] = BindInfo{arg.second}; 390 | } 391 | j++; 392 | } 393 | 394 | auto tmp_bind = this->bind; 395 | if (whole_function) res.body += "return "; 396 | res += this->operator()(c->l->body, c->l, false); 397 | if (whole_function) res.body += ";\n"; 398 | this->bind = tmp_bind; 399 | } 400 | else { 401 | // 文字参照 402 | 403 | // if (builtin_functions.contains(c->lit.val)) { 404 | // res.body += c->lit.val+"();\n"; 405 | // } else 406 | if (!bind.contains(c->lit.val)) { 407 | 408 | // TODO: 引数のコンパイル 409 | 410 | // とりあえず何もミスってなければ再帰 411 | res.body += get_name(c->lit.val) + "("; 412 | for (int i = argstack.size()-1; i >= 0; i--) { 413 | auto arg = this->argstack.front(); 414 | 415 | res += argument_evoked(arg.second); 416 | this->argstack.pop_front(); 417 | res.body += ","; 418 | } 419 | // NOTE: 最後のコンマを消す 420 | res.body.erase(res.body.end()-1); 421 | res.body += ")"; 422 | // 参照先コードのarityを見て、0なら値をコピってスタックにのっけるだけ 423 | } else if (!bindinfo[c->lit.val].code || bindinfo[c->lit.val].code->arity == 0) { 424 | // res += copy_rel(bind[c->lit.val]); 425 | res.body += get_name(c->lit.val); 426 | stack_height++; 427 | // それ以外なら、ちゃんとcallする 428 | } else { 429 | res.body += get_name(c->lit.val) + "("; 430 | for (int i = bindinfo[c->lit.val].code->arity-1; i >= 0; i--) { 431 | auto arg = this->argstack.front(); 432 | 433 | res += argument_evoked(arg.second); 434 | this->argstack.pop_front(); 435 | res.body += ","; 436 | } 437 | // NOTE: 最後のコンマを消す 438 | res.body.erase(res.body.end()-1); 439 | res.body += ")"; 440 | 441 | // res += evoke_rel(bind[c->lit.val]); 442 | stack_height++; 443 | } 444 | 445 | cout << "ll" << endl; 446 | cout << res.body << endl; 447 | } 448 | } 449 | 450 | // 戻り値コピーv.2 envlを用いたい! 451 | if (envl) { 452 | if (envl->argnames.size() != 0) 453 | // *STACK(1) = *TOP()は実際何の効果もないので省く 454 | { 455 | // res.body += "*STACK("+to_string(envl->argnames.size()+1)+") = *TOP();\n"; 456 | } 457 | for (int i = 0; i < (int)envl->argnames.size(); i++) { 458 | // res.body += "MPOP();\n"; 459 | this->stack_height--; 460 | } 461 | } 462 | 463 | // cout << res.body << endl << res.env << endl; 464 | return res; 465 | } 466 | -------------------------------------------------------------------------------- /codegen6.cpp: -------------------------------------------------------------------------------- 1 | map> codegen6::bind; 2 | map> codegen6::type_constructors; 3 | //map codegen6::data_bind; 4 | 5 | string 6 | codegen6::compress(const Compiled &&v) { 7 | return v.body + v.env; 8 | } 9 | void 10 | codegen6::paircat(Compiled &x, const Compiled &&v) { 11 | x.body += v.body; 12 | x.env += v.env; 13 | } 14 | 15 | string 16 | codegen6::print_type_to(const TypeSignature &ty) { 17 | if (MATCH(string)(ty)) { 18 | return PURE(string)(ty); 19 | } else { 20 | return print_type_to(get>(ty)->to); 21 | } 22 | } 23 | 24 | string 25 | codegen6::print_type_from(const deque &tys, const shared_ptr &lam) { 26 | string res=""; 27 | for (int i = 0; i < tys.size(); ++i) { 28 | res += print_type_to(tys[i]) + " " + (lam == nullptr ? "" : lam->argnames[i]); 29 | if (tys.size()-1 != i) { 30 | res += ", "; 31 | } 32 | } 33 | return res; 34 | } 35 | 36 | string 37 | codegen6::print_def(string name, const shared_ptr& code) { 38 | string res = ""; 39 | if (code->type.functional()) { 40 | // c->argsはとりあえず無視して、ここの引数は出力しないようにしてみる 41 | res += print_type_to(code->type.to) + " " + name + " (" + print_type_from(code->type.from, code->l) + ") {\n"; 42 | Compiled v1 = codegen6()(code->l->body); 43 | res += v1.env; 44 | res += "return " + v1.body + ";\n"; 45 | res += "}\n"; 46 | } else { 47 | Compiled cmp = codegen6()(code); 48 | res += cmp.env; 49 | res += print_type_to(code->type.to) + " " + name + " = " + cmp.body + ";\n"; 50 | } 51 | return res; 52 | } 53 | 54 | string 55 | codegen6::print_decl(string name, const TypeSignature &type, bool pointer) { 56 | string res = ""; 57 | if (type.functional()) { 58 | res += print_type_to(type.to) + "(*" + name + ")(" + print_type_from(type.from, nullptr) + ");\n"; 59 | } else { 60 | res += print_type_to(type.to) + " " + name + ";\n"; 61 | } 62 | return res; 63 | } 64 | 65 | DataStructure 66 | codegen6::parse_data_structure(const shared_ptr &c) { 67 | DataStructure res; 68 | if (get_eventual_fnname(c)=="and") { 69 | AndDS andds; 70 | for (const auto &arg : c->args) { 71 | andds.ands.push_back(parse_data_structure(arg)); 72 | } 73 | res = make_shared(andds); 74 | } 75 | else if (get_eventual_fnname(c)=="or") { 76 | OrDS ords; 77 | for (const auto &arg : c->args) { 78 | ords.ors.push_back(parse_data_structure(arg)); 79 | } 80 | res = make_shared(ords); 81 | } 82 | else { 83 | 84 | res = make_pair(c->l->argnames[0], c->l->argtypes[0]); 85 | } 86 | return res; 87 | } 88 | 89 | string 90 | codegen6::print_data_structure(const DataStructure &ds) { 91 | string res = ""; 92 | if (holds_alternative>(ds)) { 93 | for (const auto &eds : get>(ds)->ands) { 94 | res += print_data_structure(eds); 95 | } 96 | } else if (holds_alternative>(ds)) { 97 | for (const auto &eds : get>(ds)->ors) { 98 | res += print_data_structure(eds); 99 | } 100 | } else { 101 | string name; 102 | TypeSignature type; 103 | tie(name, type) = get>(ds); 104 | res += print_decl(name, type); 105 | } 106 | return res; 107 | } 108 | 109 | Compiled 110 | codegen6::operator () (const shared_ptr &c) { 111 | cout << *c <lit.val)) { 113 | assert(c->args.size() == 0); 114 | return Compiled { c->lit.val, "" }; 115 | } else if (c->lit.val == "type") { 116 | type_constructors[c->args[0]->lit.val] = c->args[1]->l; 117 | data_bind[c->args[0]->lit.val] = parse_data_structure(c->args[1]->l->body); 118 | cout << to_string(data_bind[c->args[0]->lit.val]) << endl; 119 | 120 | Compiled res; 121 | res.env += "struct " + c->args[0]->lit.val + "{\n"; 122 | res.env += print_data_structure(data_bind[c->args[0]->lit.val]); 123 | res.env += "};\n"; 124 | 125 | Compiled v1 = operator()(c->args[2]); 126 | res.env += v1.env; 127 | res.body += v1.body; 128 | return res; 129 | } else if (type_constructors.contains(c->lit.val) 130 | || builtin_functions.contains(c->lit.val)) { 131 | Compiled res; 132 | res.body += c->lit.val + "("; 133 | // 1 2 3 ) 4 5 6 として、現在のargを逆順にstackしていけば良いことが分かる 134 | for (int i = c->args.size()-1; i >= 0; i--) { 135 | argstack.push(c->args[i]); 136 | } 137 | while (!argstack.empty()) { 138 | Compiled tmp = codegen6()(argstack.top()); 139 | 140 | argstack.pop(); 141 | res.env += tmp.env; 142 | res.body += tmp.body; 143 | if (argstack.size() != 0) res.body += ", "; 144 | } 145 | res.body += ")"; 146 | return res; 147 | } else if (c->l) { 148 | // bind > 149 | Compiled res; 150 | int i = 0; 151 | // while (!barstack.empty()) { 152 | // res.env += print_def(barstack.top(), c->args[i]); 153 | // barstack.pop(); 154 | // i++; 155 | // } 156 | for (int i = c->args.size()-1; i >= 0; i--) { 157 | argstack.push(c->args[i]); 158 | } 159 | for (int i = 0; i < c->l->argnames.size(); i++) { 160 | // func generator? 161 | if (argstack.top()->l && argstack.top()->type.arity() - (int)argstack.top()->l->argnames.size() > 0) { 162 | bind[c->l->argnames[i]] = argstack.top(); 163 | cout << c->l->argnames[i] << endl; 164 | } else { 165 | cout << c->l->argnames[i] << endl; 166 | res.env += print_def(c->l->argnames[i], argstack.top()); 167 | } 168 | argstack.pop(); 169 | } 170 | // TODO: v1.tmp と tmp の場所 171 | paircat(res, operator()(c->l->body)); 172 | return res; 173 | } else { 174 | Compiled res; 175 | for (int i = c->args.size()-1; i >= 0; i--) { 176 | argstack.push(c->args[i]); 177 | } 178 | if (bind.contains(c->lit.val)) { 179 | int pfcounter = pseudo_func_counter; 180 | res.env += "int __pseudo_"+to_string(pfcounter)+"() {\n"; 181 | auto cmp = operator()(bind[c->lit.val]); 182 | res.env += cmp.env; 183 | res.env += "return " + cmp.body + ";\n"; 184 | res.env += "}\n"; 185 | 186 | res.body += "__pseudo_"+to_string(pfcounter)+"()"; 187 | pseudo_func_counter++; 188 | } else { 189 | res.body += c->lit.val + "("; 190 | while (!argstack.empty()) { 191 | Compiled tmp = codegen6()(argstack.top()); 192 | 193 | argstack.pop(); 194 | res.env += tmp.env; 195 | res.body += tmp.body; 196 | if (argstack.size() != 0) res.body += ", "; 197 | } 198 | res.body += ")"; 199 | } 200 | return res; 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /codegen7.cpp: -------------------------------------------------------------------------------- 1 | map codegen7::data_bind; // TODO: スコープいいの? 2 | unsigned int codegen7::type_count = 0; 3 | unsigned int codegen7::dummy_count = 0; 4 | map codegen7::fuse_bind; 5 | pseudo_map codegen7::tmptypes; 6 | pseudo_map, string> codegen7::type_constrs; 7 | map> codegen7::spvals; 8 | 9 | 10 | // TODO: 名前をつける関数のトップレベルに引数が全てない場合ダメになる 11 | // (|foo| ...) ((|a b| ...))みたいなやつとか 12 | 13 | string 14 | codegen7::compress(const Compiled &&v) { 15 | return v.body + v.env; 16 | } 17 | string 18 | codegen7::compress(const Compiled &v) { 19 | return v.body + v.env; 20 | } 21 | void 22 | codegen7::paircat(Compiled &x, const Compiled &&v) { 23 | x.body += v.body; 24 | x.env += v.env; 25 | } 26 | void 27 | codegen7::paircat(Compiled &x, const Compiled &v) { 28 | x.body += v.body; 29 | x.env += v.env; 30 | } 31 | void codegen7::paircat(tuple &x, const tuple &&y) { 32 | get<0>(x) += get<0>(y); 33 | get<1>(x) += get<1>(y); 34 | get<2>(x) += get<2>(y); 35 | } 36 | 37 | string 38 | codegen7::c_type_name(string s, bool bPrefix) { 39 | string prefix = ""; 40 | if (bPrefix) { 41 | if (MATCHS(TypeSum)(data_bind[s])) prefix = "struct "; 42 | if (MATCHS(TypeProduct)(data_bind[s])) prefix = "struct "; 43 | } 44 | return prefix + "t_" + tolower(s); 45 | } 46 | 47 | string 48 | codegen7::typesig_to_typename(const TypeSignature &type) { 49 | if (tmptypes.contains(type)) { return tmptypes[type]; } 50 | else if (defined_polymos.contains(type)) { return defined_polymos[type]; } 51 | else if (MATCH(string)(type)) { 52 | return c_type_name(PURE(string)(type)); 53 | } else { 54 | ASSERT(false, "おかしいね"); 55 | } 56 | } 57 | 58 | string 59 | codegen7::typesig_to_constructor(const TypeSignature &type) { 60 | if (MATCH(string)(type)) { 61 | return PURE(string)(type); 62 | } else if (MATCHS(Parametered)(type)) { 63 | return PURES(Parametered)(type)->type; 64 | } else { 65 | ASSERT(false, "おかしいね"); 66 | } 67 | } 68 | 69 | string 70 | codegen7::new_tmptype(const TypeSignature type) { 71 | type_count++; 72 | tmptypes[type] = "t_"+to_string(type_count); 73 | return "t_"+to_string(type_count); 74 | } 75 | 76 | string 77 | codegen7::new_dummy_var() { 78 | dummy_count++; 79 | return "__x"+to_string(dummy_count); 80 | } 81 | 82 | bool 83 | codegen7::is_spval(string a) { 84 | for (auto &[_, e]: spvals) { 85 | for (auto &i : e) { 86 | if (a == i) return true; 87 | } 88 | } 89 | return false; 90 | } 91 | 92 | int 93 | codegen7::spval_to_int(SpecialValue sp) { 94 | for (auto &[_, e]: spvals) { 95 | int j = 0; 96 | for (auto &i : e) { 97 | if (sp.val == i) return j; 98 | j++; 99 | } 100 | } 101 | return 0; 102 | } 103 | 104 | string 105 | codegen7::print_polymos() { 106 | string res = ""; 107 | 108 | for (auto type : defined_polymos.get_keys()) { 109 | assert(MATCHS(Parametered)(type)); 110 | auto name = defined_polymos[type]; 111 | auto param = PURES(Parametered)(type); 112 | map _params; 113 | for (int i = 0; i < polymos[name].size(); i++) { 114 | _params[polymos[name][i]] = param->params[i]; 115 | } 116 | auto tmp = print_data_structure(data_bind[param->type], "", _params); 117 | res += get<0>(tmp)+get<1>(tmp)+get<2>(tmp) + "\n"; 118 | } 119 | return res; 120 | } 121 | 122 | // NOTE: 1つ目と2つ目を名前で挟む 123 | tuple 124 | codegen7::print_data_structure(const TypeSignature type, string type_name, const map ¶ms) { 125 | tuple res = make_tuple("","",""); 126 | bool bNewTmptype = type_name == ""; 127 | 128 | if (tmptypes.contains(type)) { 129 | get<1>(res) += tmptypes[type] + " "; 130 | return res; 131 | } 132 | 133 | if (MATCHS(TypeProduct)(type)) { 134 | const auto prod = PURES(TypeProduct)(type); 135 | const string tmptype = bNewTmptype ? new_tmptype(type) : type_name; 136 | get<0>(res) += "struct " + tmptype + "{\n"; 137 | for (int i = 0; i < prod->products.size(); i++) { 138 | auto tmp = print_data_structure(prod->products[i]); 139 | if (prod->names.size() == 0) { 140 | get<0>(res) += get<0>(tmp) + get<1>(tmp) + " e" + to_string(i) + get<2>(tmp) + ";\n"; 141 | } else { 142 | get<0>(res) += get<0>(tmp) + get<1>(tmp) + prod->names[i] + get<2>(tmp) + ";\n"; 143 | } 144 | } 145 | get<0>(res) += "};\n"; 146 | get<1>(res) += "struct " + tmptype + " "; 147 | } else if (MATCHS(TypeSum)(type)) { 148 | const auto sum = PURES(TypeSum)(type); 149 | const string tmptype = bNewTmptype ? new_tmptype(type) : type_name; 150 | get<0>(res) += "struct "+tmptype+" {\n"; 151 | get<0>(res) += "unsigned short rtti;\n"; 152 | get<0>(res) += "union {\n"; 153 | 154 | // get<0>(res) += "enum {"; 155 | for (int i = 0, len=sum->sums.size(); i < len; i++) if (MATCH(SpecialValue)(sum->sums[i])) { 156 | if (spvals.contains(tmptype)) spvals[tmptype] = {}; 157 | spvals[tmptype].emplace_back(PURE(SpecialValue)(sum->sums[i]).val); 158 | // get<0>(res) += PURE(SpecialValue)(sum->sums[i]).val + (i!=len-1?", ":""); 159 | } 160 | // get<0>(res) += "} sp;\n"; 161 | get<0>(res) += "int sp;\n"; 162 | 163 | for (int i = 0; i < sum->sums.size(); i++) { 164 | if (MATCH(SpecialValue)(sum->sums[i])) continue; 165 | auto tmp = print_data_structure(sum->sums[i]); 166 | get<0>(res) += get<0>(tmp) + get<1>(tmp) + " e" + to_string(i) + get<2>(tmp) + ";\n"; 167 | } 168 | get<0>(res) += "} uni;\n"; 169 | get<0>(res) += "};\n"; 170 | get<1>(res) += "struct " + tmptype + " "; 171 | } else if (MATCHS(TypeFn)(type)) { 172 | // to (*name) (args, ...); 173 | const auto fn = PURES(TypeFn)(type); 174 | paircat(res, print_data_structure(fn->to)); 175 | get<1>(res) += "(*"; 176 | get<2>(res) += ")("; 177 | for (int i = 0; i < fn->from.size(); ++i) { 178 | auto tmp = print_data_structure(fn->from[i]); 179 | get<0>(res) += get<0>(tmp); 180 | get<2>(res) += get<1>(tmp)+get<2>(tmp); 181 | if (i != fn->from.size()-1) get<2>(res) += ","; 182 | } 183 | get<2>(res) += ")"; 184 | } else if (MATCH(string)(type)) { 185 | auto str = PURE(string)(type); 186 | // if (params.contains(str)) { 187 | // return print_data_structure(params[str], params); 188 | // } else { 189 | get<1>(res) = (str == "int" ? str : c_type_name(str) + "*") + " "; 190 | // } 191 | } 192 | else if (MATCHS(Parametered)(type)) { 193 | auto param = PURES(Parametered)(type); 194 | if (!defined_polymos.contains(type)) { 195 | defined_polymos[type] = "t_"+param->type+to_string(defined_polymos.size()); 196 | } 197 | get<1>(res) = defined_polymos[type] + "* "; 198 | } 199 | // 特殊地はintとして扱われる 200 | else if (MATCH(SpecialValue)(type)) { return make_tuple("", "int ", ""); } 201 | return res; 202 | } 203 | 204 | // NOTE: print_defからしか呼んじゃダメ。ダミー変数を作ってargstackを操作します 205 | // 例えば、(|foo| ... ) ((|a b| ...) 3)<-ここ みたいな式について'<-ここ'の所の関数をfooと名付けるわけですが、この時 206 | // この内側にコンパイラを渡す際に、ダミー変数としてかぶらない名前(今は__x1みたいにしてます)をargstackに最初から突っ込んでおくことで、 207 | // 最終的にfooを呼ぶ時(引数は2つ渡すべき)の挙動を再現してコンパイルできます 208 | string 209 | codegen7::print_type_from(const deque &tys, const shared_ptr &lam) { 210 | string res=""; 211 | for (int i = 0; i < tys.size(); ++i) { 212 | auto tmp = print_data_structure(tys[i]); 213 | res += get<0>(tmp); 214 | if (lam->argnames.size() > i) { 215 | res += get<1>(tmp) + (lam == nullptr ? "" : lam->argnames[i]) + get<2>(tmp); 216 | } else { 217 | res += get<1>(tmp) + new_dummy_var() + get<2>(tmp); 218 | Code c = { nullptr, "__x"+to_string(dummy_count), {} }; 219 | deep_copy_from(c.type,tys[i]); 220 | dummy_argstack.push(make_shared(c)); 221 | } 222 | 223 | if (tys.size()-1 != i) { 224 | res += ", "; 225 | } 226 | } 227 | return res; 228 | } 229 | 230 | inline Compiled 231 | codegen7::print_decl(string name, const TypeSignature &typesig) { 232 | Compiled res; 233 | auto tmp = print_data_structure(typesig); 234 | res.global += get<0>(tmp); 235 | res.body += get<1>(tmp) + " " + name + get<2>(tmp); 236 | return res; 237 | } 238 | 239 | // TODO: global捨ててない? 240 | Compiled 241 | codegen7::define(string name, const shared_ptr& code) { 242 | Compiled res; 243 | if (MATCHS(TypeFn)(code->type)) { 244 | auto fn = PURES(TypeFn)(code->type); 245 | // c->argsはとりあえず無視して、ここの引数は出力しないようにしてみる 246 | auto tmp = print_data_structure(code->type); 247 | res.body += get<0>(tmp); 248 | 249 | const string type_to = get<1>(tmp).substr(0, get<1>(tmp).length()-2); 250 | const string prottype = type_to + name + "(" + print_type_from(fn->from, code->l) + ") "; 251 | // res.body += prottype + ";\n"; 252 | res.body += prottype + " {\n"; 253 | 254 | Compiled v1 = codegen7(dummy_argstack)(code->l->body); 255 | res.global += v1.global; 256 | res.body += v1.env; 257 | if (v1.return_required) res.body += "return " + v1.body + ";\n"; 258 | else res.body += v1.body; 259 | res.body += "}\n"; 260 | // } else if (MATCHS(TypeSum)(code->type) && MATCHS(TypeFn)(PURES.BODY(TypeSum)(code->type)->sums[0])) { 261 | // // fuseなら何もしない 262 | // Compiled v1 = codegen7()(code->l->body); 263 | // res.body += v1.env; 264 | // res.body += v1.body; 265 | // fuse_bind[name] = "__fuse" + to_string(fuse_bind.size()); 266 | } else { 267 | auto tmp = print_data_structure(code->type); 268 | res.env += get<0>(tmp); 269 | 270 | Compiled cmp = codegen7()(code); 271 | res.global += cmp.global; 272 | res.env += cmp.env; 273 | res.body += get<1>(tmp) + name + " = " + cmp.body + ";\n"; 274 | } 275 | return res; 276 | } 277 | 278 | Compiled codegen7::fuse(const shared_ptr &c) { 279 | Compiled res; 280 | res.return_required = false; 281 | int ari = arity(c->args[0]->type); 282 | deque dummies; 283 | stack> argstack_bkp = argstack; 284 | for (int i = 0; i < ari; i++) { 285 | dummies.emplace_back(argstack.top()->lit.val); 286 | // argstack.pop(); 287 | } 288 | 289 | cout << "yahoo " << to_string(PURES(TypeFn)(c->type)->from[0]) << endl; 290 | 291 | // 1個めの引数がわけられているかどうか 292 | if (MATCHS(TypeSum)(PURES(TypeFn)(c->type)->from[0])) { 293 | auto sum = PURES(TypeSum)(PURES(TypeFn)(c->type)->from[0])->sums; 294 | const string name = argstack.top()->lit.val; 295 | for (int i = 0; i < c->args.size(); i++) { 296 | int rtti = distance(sum.begin(), find(sum.begin(), sum.end(), PURES(TypeFn)(c->args[i]->type)->from[0])); 297 | bool bSpecialValue = MATCH(SpecialValue)(PURES(TypeFn)(c->args[i]->type)->from[0]); 298 | string downcast = bSpecialValue ? name+"->uni.sp" : name+"->uni.e"+to_string(rtti); 299 | argstack.top()->type = sum[rtti]; 300 | argstack.top()->lit.val = downcast; 301 | 302 | if (is_literal(c->args[i]->lit.val)) { 303 | res.body += "if ("+dummies[0]+"->rtti == "+to_string(rtti)+" && "+c->args[i]->lit.val+" == "+downcast+") {\n"; 304 | } else if (bSpecialValue) { 305 | res.body += "if ("+dummies[0]+"->rtti == "+to_string(rtti)+" && "+to_string(spval_to_int(PURE(SpecialValue)(PURES(TypeFn)(c->args[i]->type)->from[0]))) + "/*"+PURE(SpecialValue)(PURES(TypeFn)(c->args[i]->type)->from[0]).val+"*/ == "+name+"->uni.sp) {\n"; 306 | } else { 307 | res.body += "if ("+dummies[0]+"->rtti == "+to_string(rtti)+") {\n"; 308 | } 309 | Compiled v1 = operator()(c->args[i]); argstack = argstack_bkp; 310 | res.global += v1.global; 311 | res.body += v1.env; 312 | if (v1.return_required) res.body += "return " + v1.body + ";\n"; 313 | else res.body += v1.body; 314 | res.body += "}\n"; 315 | } 316 | } else { 317 | res.body += "if (false) {\n"; 318 | for (int i = 0; i < c->args.size(); i++) { 319 | if (is_literal(c->args[i]->l->argnames[0])) { 320 | res.body += "} else if ("+c->args[i]->l->argnames[0]+" == "+dummies[0]+") {\n"; 321 | } else { 322 | res.body += "} else {\n"; 323 | } 324 | Compiled v1 = operator()(c->args[i]); argstack = argstack_bkp; 325 | res.global += v1.global; 326 | res.body += v1.env; 327 | if (v1.return_required) res.body += "return " + v1.body + ";\n"; 328 | else res.body += v1.body; 329 | } 330 | res.body += "}"; 331 | } 332 | return res; 333 | } 334 | 335 | // body空白で返します, env,globalを使用しています 336 | Compiled 337 | codegen7::print_constructor(string type_name, const TypeSignature& newtype, int rtti/*=-1*/) { 338 | Compiled res; 339 | TypeSignature norm_newtype = normalized(newtype); 340 | 341 | cout << "heyy" << to_string(norm_newtype) << endl; 342 | 343 | // コンストラクタを出力 344 | if (MATCHS(TypeSum)(norm_newtype)) { 345 | auto sum = PURES(TypeSum)(norm_newtype); 346 | for (int i = 0; i < sum->sums.size(); i++) { 347 | paircat(res, print_constructor(type_name, sum->sums[i], i)); 348 | } 349 | 350 | // if (sum->special_values.size() != 0) { 351 | res.env += c_type_name(type_name)+"* "+type_name+"(int in) {\n"; 352 | res.env += c_type_name(type_name) + " *tmp = ("+c_type_name(type_name)+"*)malloc(sizeof("+c_type_name(type_name,false)+"));\n"; 353 | res.env += "tmp->uni.sp = in;\n"; 354 | res.env += "tmp->rtti = "+to_string(sum->sums.size())+";\n"; 355 | res.env += "return tmp;\n"; 356 | res.env += "}\n"; 357 | // } 358 | 359 | } else { 360 | if (MATCHS(TypeProduct)(norm_newtype)) { 361 | auto prod = PURES(TypeProduct)(norm_newtype); 362 | const string constr_name = type_name+to_string(type_constrs.size()); 363 | type_constrs[prod->products] = constr_name; 364 | res.env += c_type_name(type_name) + "* " + constr_name + "("; 365 | for (int i = 0; i < prod->products.size(); i++) { 366 | Compiled printed = print_decl(prod->names[i], prod->products[i]); 367 | res.global += printed.global; 368 | res.env += compress(printed); 369 | if (i != prod->products.size()-1) { 370 | res.env += ", "; 371 | } 372 | } 373 | res.env += ") {\n"; 374 | res.env += c_type_name(type_name) + " *tmp = ("+c_type_name(type_name)+"*)malloc(sizeof("+c_type_name(type_name,false)+"));\n"; 375 | if (rtti >= 0) res.env += "tmp->rtti = "+to_string(rtti)+";\n"; 376 | for (int i = 0; i < prod->names.size(); i++) { 377 | res.env += "tmp->"+(rtti>=0 ? "uni.e"+to_string(rtti)+"." : "")+prod->names[i]+" = "+prod->names[i]+";\n"; 378 | } 379 | res.env += "return tmp;\n"; 380 | res.env += "}\n"; 381 | } else { 382 | // TODO: string, Parametered(これはpolyで実装するはず), 383 | } 384 | } 385 | 386 | return res; 387 | } 388 | 389 | Compiled codegen7::type_def(const string newtype_name, const TypeSignature &newtype) { 390 | // const auto newtype_name = c->args[0]->lit.val; 391 | // const auto newtype = c->args[1]->rawtype; 392 | 393 | // if (c->args.size() == 4) { 394 | // polymos[newtype_name] = deque(c->args[2]->l->argnames.begin(), c->args[2]->l->argnames.end()); 395 | // } 396 | 397 | data_bind[newtype_name] = newtype; 398 | 399 | // 型定義を出力 400 | Compiled res; 401 | auto tmp = print_data_structure(newtype, c_type_name(newtype_name,false)); 402 | res.env += get<0>(tmp) + ";\n"; 403 | 404 | 405 | paircat(res, print_constructor(newtype_name, newtype)); 406 | // if (MATCHS(TypeSum)(newtype)) { 407 | // auto sum = PURES(TypeSum)(newtype); 408 | // for (int i = 0; i < sum->sums.size(); i++) { 409 | // if (MATCHS(Parametered)(sum->sums[i])) { 410 | // auto param = PURES(Parametered)(sum->sums[i]); 411 | 412 | // } else { 413 | // res.env += c_type_name(newtype_name) + "* " + newtype_name + "(" + tmptypes[sum->sums[i]] + "* in) {\n"; 414 | // // Sumを構成している型はすべてtmptypeとして実装されているはず...? 415 | // res.env += newtype_name + " *tmp = ("+c_type_name(newtype_name)+"*)malloc(sizeof("+c_type_name(newtype_name)+"));\n"; 416 | // res.env += "tmp->uni.e"+to_string(i)+" = in;\n"; 417 | // res.env += "tmp->rtti = "+to_string(i)+";\n"; 418 | // res.env += "return tmp;\n"; 419 | // res.env += "}\n"; 420 | // } 421 | // } 422 | // if (sum->special_values.size() != 0) { 423 | // res.env += c_type_name(newtype_name)+"* "+newtype_name+"(int in) {\n"; 424 | // res.env += newtype_name + " *tmp = ("+c_type_name(newtype_name)+"*)malloc(sizeof("+c_type_name(newtype_name)+"));\n"; 425 | // res.env += "tmp->uni.sp = in;\n"; 426 | // res.env += "tmp->rtti = "+to_string(sum->sums.size())+";\n"; 427 | // res.env += "return tmp;\n"; 428 | // res.env += "}\n"; 429 | // } 430 | // } 431 | // if (MATCHS(TypeProduct)(newtype)) { 432 | // auto prod = PURES(TypeProduct)(newtype); 433 | // for (int i = 0; i < prod->products.size(); i++) { 434 | // Compiled printed = print_decl(prod->names[i], prod->products[i]); 435 | // res.global += printed.global; 436 | // res.env += compress(printed); 437 | // if (i != prod->products.size()-1) { 438 | // res.env += ", "; 439 | // } 440 | // } 441 | // res.env += ") {\n"; 442 | // res.env += newtype_name + " *tmp = ("+c_type_name(newtype_name)+"*)malloc(sizeof("+c_type_name(newtype_name)+"));\n"; 443 | // for (int i = 0; i < prod->names.size(); i++) { 444 | // res.env += "tmp->"+prod->names[i]+" = "+prod->names[i]+";\n"; 445 | // } 446 | // res.env += "return tmp;\n"; 447 | // res.env += "}\n"; 448 | // } 449 | 450 | return res; 451 | } 452 | 453 | Compiled 454 | codegen7::operator () (const shared_ptr &c) { 455 | cout << *c <lit.val)) { 457 | assert(c->args.size() == 0); 458 | return Compiled { c->lit.val, "" }; 459 | 460 | } else if (c->lit.val == "_get") { 461 | Compiled tmp = codegen7()(c->args[0]); 462 | return Compiled { "("+tmp.env+tmp.body+")"+"->"+c->args[1]->lit.val, "", tmp.global }; 463 | } else if (c->lit.val == "type") { 464 | Compiled res; 465 | paircat(res, type_def(c->args[0]->lit.val, c->args[1]->rawtype)); 466 | paircat(res, operator()(c->args[2])); 467 | return res; 468 | } else if (c->lit.val == "fuse") { 469 | return fuse(c); 470 | 471 | } else if (builtin_functions.contains(c->lit.val)) { 472 | Compiled res; 473 | const map sym = { { "add", "+" }, {"sub","-"}, {"mul","*"}, {"div","/"} }; 474 | res.body += "("; 475 | // 1 2 3 ) 4 5 6 として、現在のargを逆順にstackしていけば良いことが分かる 476 | for (int i = c->args.size()-1; i >= 0; i--) { 477 | argstack.push(c->args[i]); 478 | } 479 | while (!argstack.empty()) { 480 | Compiled tmp = codegen7()(argstack.top()); 481 | 482 | argstack.pop(); 483 | res.global += tmp.global; 484 | res.env += tmp.env; 485 | res.body += tmp.body; 486 | if (argstack.size() != 0) res.body += sym.at(c->lit.val); 487 | } 488 | res.body += ")"; 489 | return res; 490 | } else if (c->l) { 491 | Compiled res; 492 | int i = 0; 493 | for (int i = c->args.size()-1; i >= 0; i--) { 494 | argstack.push(c->args[i]); 495 | } 496 | 497 | // vector free; NOTE: つまりocamlgenでは使っていたこれがいらない 498 | for (int i = 0; i < c->l->argnames.size(); i++) { 499 | // NOTE: 上に書いたようにダミー変数を使ってコンパイルするため、ココでargstackが空であることは無いはずです 500 | assert(!argstack.empty()); 501 | 502 | if (!is_literal(c->l->argnames[i])) { 503 | auto tmp = define(c->l->argnames[i], argstack.top()); 504 | res.global += tmp.global; 505 | res.env += compress(tmp); 506 | } 507 | argstack.pop(); 508 | // func generator? 509 | } 510 | 511 | // TODO: v1.tmp と tmp の場所 512 | Compiled tmp = operator()(c->l->body); 513 | paircat(res, tmp); 514 | res.return_required = tmp.return_required; 515 | res.global += tmp.global; 516 | 517 | for (int i = 0; i < c->l->argnames.size(); i++) { 518 | if (!is_literal(c->l->argnames[i]) && arity(c->l->argtypes[i])==0) 519 | res.env += "delete "+c->l->argnames[i]+";\n"; 520 | } 521 | 522 | return res; 523 | } else if (MATCH(SpecialValue)(c->type)) { 524 | return Compiled { to_string(spval_to_int(PURE(SpecialValue)(c->type)))+"/*"+PURE(SpecialValue)(c->type).val+"*/", "" }; 525 | } else { 526 | Compiled res; 527 | for (int i = c->args.size()-1; i >= 0; i--) { 528 | argstack.push(c->args[i]); 529 | } 530 | 531 | if (c->cRawtype) { 532 | int i = 0; 533 | // res.body += typesig_to_constructor(c->rawtype) + "("; 534 | // cout << "heyyyooo" << to_string(c->type) << endl; 535 | deque idx; 536 | for (auto e : c->args) { idx.emplace_back(e->type); } 537 | res.body += (type_constrs.contains(idx) ? type_constrs[idx] :typesig_to_constructor(c->rawtype)) + "("; 538 | while (!argstack.empty()) { 539 | // Compiled tmp = codegen7()(argstack.top()); 540 | auto tmp = define("tmp"+to_string(i), argstack.top()); 541 | res.global += tmp.global; 542 | res.env += compress(tmp); 543 | 544 | argstack.pop(); 545 | res.global += tmp.global; 546 | // res.env += tmp.env; 547 | res.body += /*records->names[i]+"="+*/"tmp"+to_string(i)+", "; 548 | i++; 549 | } 550 | 551 | if (res.body.size() >= 2) res.body = res.body.substr(0, res.body.length()-2); 552 | res.body += ")"; 553 | } else { 554 | string destruct_buffer = ""; 555 | if (fuse_bind.contains(c->lit.val)) { 556 | res.body += fuse_bind[c->lit.val]; 557 | } else { 558 | res.body += c->lit.val; 559 | } 560 | if (argstack.size() != 0) { 561 | int i = 0; 562 | res.body += "("; 563 | while (!argstack.empty()) { 564 | // Compiled tmp = codegen7()(argstack.top()); 565 | // NOTE: 引数を用意する時にポインタを確保しておいて、あとでデストラクタを呼ぶ 566 | auto tmp = define("tmp"+to_string(i), argstack.top()); 567 | res.global += tmp.global; 568 | res.env += compress(tmp); 569 | if (MATCH(string)(argstack.top()->type) && PURE(string)(argstack.top()->type) != "int") { 570 | destruct_buffer += "delete "s + "tmp"+to_string(i) + ";\n"; 571 | } 572 | 573 | argstack.pop(); 574 | // res.global += tmp.global; 575 | // res.env += tmp.env; 576 | // res.body += tmp.body; 577 | res.body += "tmp"+to_string(i)+", "; 578 | // } 579 | i++; 580 | } 581 | if (res.body.size() >= 2) res.body = res.body.substr(0, res.body.length()-2); 582 | res.body += ")"; 583 | res.body = destruct_buffer; 584 | } 585 | } 586 | 587 | 588 | 589 | return res; 590 | } 591 | } 592 | -------------------------------------------------------------------------------- /compile.sh: -------------------------------------------------------------------------------- 1 | ./emelio c test.em > compiled/code.inc 2 | pushd compiled 3 | fasm lib.s 4 | gcc lib.o -o a.out -m32 -g 5 | ./a.out 6 | popd 7 | -------------------------------------------------------------------------------- /compiled/flat.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import sys 5 | import re 6 | 7 | FUNC_START_REGEXP = r'void\s?\w' 8 | FUNC_END_REGEXP = r'}' 9 | 10 | content = "" 11 | with open(sys.argv[1], 'r') as f: 12 | content = f.read() 13 | 14 | continues = True 15 | while continues == True: 16 | nest = 0 17 | func = "" 18 | result = "" 19 | result_header = "" 20 | recording = False 21 | continues = False 22 | for l in content.split("\n"): 23 | if re.search(FUNC_START_REGEXP, l): 24 | if nest == 1: 25 | recording = True 26 | 27 | if nest == 2: continues = True 28 | nest += 1 29 | elif re.search(FUNC_END_REGEXP, l): 30 | nest -= 1 31 | if nest == 1: 32 | recording = False 33 | result_header += l + "\n" 34 | continue 35 | 36 | if recording == True: 37 | result_header += l + "\n" 38 | else: 39 | result += l + "\n" 40 | content = result_header + result 41 | 42 | 43 | #print(content) 44 | 45 | with open(sys.argv[1]+'.new', 'w') as f: 46 | f.write(content) 47 | 48 | -------------------------------------------------------------------------------- /compiled/output: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emelio-lang/intprt-cpp/e1f498fdeb88fee761db23f70755aa0bbaee7c62/compiled/output -------------------------------------------------------------------------------- /compiled/output.c: -------------------------------------------------------------------------------- 1 | /* 2 | Memory map: 3 | 4 | SP 5 | AP 6 | Hash 7 | Stack 8 | 9 | SP,AP作戦は複雑な関数の部分適用で壊れないことを確認するべき. 10 | 11 | hashの必要な大きさは予想できそう 12 | */ 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | #define uint unsigned int 19 | #define PUSHF(x) AP->fp = x; AP++; SP = AP; 20 | #define PUSHV(x) AP->val = x; AP++; SP = AP; 21 | #define PUSHS(x) AP->str = x; AP++; SP = AP; 22 | #define PUSHP(x) AP->ptr = x; AP++; SP = AP; 23 | #define STACK(x) (AP-(x)) 24 | #define TOP() (SP-1) 25 | #define MPOP() AP--; SP = AP; 26 | #define POP() SP--; 27 | 28 | 29 | 30 | #define mallocate malloc 31 | 32 | 33 | // 今はstackをvoid*固定としましょうか 34 | 35 | // 番兵を使わないタイプのメモリ 36 | typedef struct { 37 | void *ptr; 38 | unsigned int size; 39 | unsigned int sizeexpo; 40 | } ptr_t; 41 | 42 | union memory_t { 43 | void(*fp)(); 44 | int val; 45 | // 番兵を使うタイプのメモリ(文字列) 46 | char *str; 47 | // 番兵を使わないタイプのメモリ 48 | ptr_t *ptr; 49 | }; 50 | 51 | union memory_t *SP, *AP, ACC; 52 | void(*HP[256])(); 53 | union memory_t *MEM; 54 | 55 | ptr_t *ALLOCATE(unsigned int size) { 56 | ptr_t *res = mallocate(sizeof(ptr_t)); 57 | res->ptr = mallocate(size); 58 | res->size = size; 59 | res->sizeexpo = 3; 60 | return res; 61 | } 62 | 63 | void FREE(ptr_t *ptr) { 64 | free(ptr->ptr); 65 | free(ptr); 66 | } 67 | 68 | 69 | void negate() { 70 | int a = TOP()->val; MPOP(); 71 | PUSHV(-a); 72 | return; 73 | } 74 | void sub() { 75 | int a = TOP()->val; MPOP(); 76 | int b = TOP()->val; MPOP(); 77 | PUSHV(a - b); 78 | return; 79 | } 80 | void add() { 81 | // (SP+(-1))->fp(); 82 | // (SP+(-3))->fp(); 83 | 84 | int a = TOP()->val; MPOP(); 85 | int b = TOP()->val; MPOP(); 86 | 87 | // MPOP();MPOP(); // 関数の方も削除 88 | 89 | PUSHV(a + b); 90 | return; 91 | } 92 | void mul() { 93 | int a = TOP()->val; MPOP(); 94 | int b = TOP()->val; MPOP(); 95 | 96 | PUSHV(a * b); 97 | return; 98 | } 99 | 100 | void concat() { 101 | // (SP+(-1))->fp(); 102 | // (SP+(-3))->fp(); 103 | 104 | char *a = TOP()->str; MPOP(); 105 | char *b = TOP()->str; MPOP(); 106 | 107 | // TODO: ここのメモリを開放する手段がないのでまだ遣っちゃダメ 108 | ptr_t *new = ALLOCATE(strlen(a) + strlen(b) + 1); 109 | 110 | strcpy(new->ptr, a); 111 | strcat(new->ptr, b); 112 | // MPOP();MPOP(); // 関数の方も削除 113 | 114 | PUSHP(new); 115 | return; 116 | } 117 | 118 | 119 | #include "env.c" 120 | // #include "env.c.new" 121 | 122 | 123 | int main() { 124 | stack_init: 125 | MEM = calloc(256, sizeof(union memory_t)); 126 | AP = SP = MEM; 127 | // HP[0] = ADD; 128 | // HP[1] = SUB; 129 | // HP[2] = MUL; 130 | // HP[3] = NEG; 131 | 132 | start: 133 | #include "code.c" 134 | 135 | printf("%d\n", SP-MEM); 136 | printf("%d\n", STACK(1)->val); 137 | 138 | exit: 139 | free(MEM); 140 | 141 | funcs: 142 | 143 | return 0; 144 | } 145 | 146 | -------------------------------------------------------------------------------- /emelio-util.cpp: -------------------------------------------------------------------------------- 1 | /* ======================================================================== 2 | $File: emelio-util.cpp $ 3 | $Date: Jul 07 2020 $ 4 | $Revision: $ 5 | $Creator: Creative GP $ 6 | $Notice: (C) Copyright 2020 by Creative GP. All Rights Reserved. $ 7 | ======================================================================== */ 8 | 9 | /* 10 | emelio.hで定義されている、emelioで使用するデータ構造に対するユーティリィー関数をここに書いていく 11 | */ 12 | 13 | #include "emelio.h" 14 | #include "util.h" 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | bool is_computed(const shared_ptr &c) { 21 | return (c && !c->l); 22 | } 23 | 24 | // Code::Code(const Code& other) { 25 | // lit = other.lit; 26 | // src = other.src; 27 | 28 | // if (other.l) { 29 | // l = unique_ptr(new Lambda); 30 | // *l = *other.l; 31 | // } else { 32 | // l = unique_ptr(nullptr); 33 | // } 34 | 35 | // for (Code c : other.args) { 36 | // args.push_back(Code(c)); 37 | // } 38 | // } 39 | 40 | 41 | string get_eventual_fnname(shared_ptr c) { 42 | if (!c->l) { return c->lit.val; } 43 | else return get_eventual_fnname(c->l->body); 44 | } 45 | 46 | vector Code::plain_string() { 47 | vector res = {}; 48 | 49 | if (this->lit.val != "") { 50 | res.push_back(this->lit.val); 51 | } else if (this->cRawtype) { 52 | res.push_back(":(" + join(this->cRawtype->plain_string()) + ")"); 53 | } 54 | 55 | if (this->l) { 56 | vector const tmp = this->l->body->plain_string(); 57 | res.reserve(res.size() + distance(tmp.begin(),tmp.end())); 58 | if (this->args.size() != 0) res.emplace_back("("); 59 | res.insert(res.end(),tmp.begin(),tmp.end()); 60 | if (this->args.size() != 0) res.emplace_back(")"); 61 | } 62 | 63 | for (auto a : this->args) { 64 | vector const tmp = a->plain_string(); 65 | res.reserve(res.size() + distance(tmp.begin(),tmp.end())); 66 | res.emplace_back(" "); 67 | res.insert(res.end(),tmp.begin(),tmp.end()); 68 | } 69 | 70 | return res; 71 | } 72 | 73 | 74 | void Code::deep_copy_from(const Code& other) { 75 | lit = other.lit; 76 | src = other.src; 77 | arity = other.arity; 78 | ::deep_copy_from(type, other.type); 79 | 80 | // TODO: srcもコピーしないと 81 | 82 | // もうすでにnullでないptrを持っているならそれを活かす 83 | if (other.l) { 84 | if (!l) l = shared_ptr(new Lambda); 85 | l->deep_copy_from(*other.l); 86 | } else { 87 | l = shared_ptr(nullptr); 88 | } 89 | 90 | args.clear(); 91 | for (const shared_ptr &c : other.args) { 92 | shared_ptr copied (new Code); 93 | copied->deep_copy_from(*c); 94 | args.push_back(copied); 95 | } 96 | 97 | } 98 | 99 | bool Code::is_type() const { 100 | return !MATCHS(TypeNull)(rawtype); 101 | } 102 | 103 | void Lambda::deep_copy_from(const Lambda& other) { 104 | argnames = other.argnames; 105 | argarities = other.argarities; 106 | argqualities = other.argqualities; 107 | ::deep_copy_from(type, other.type); 108 | 109 | if (other.body) { 110 | if (!body) body = shared_ptr(new Code); 111 | body->deep_copy_from(*other.body); 112 | } 113 | 114 | // fused.clear(); 115 | // for (const shared_ptr &l : other.fused) { 116 | // shared_ptr copied (new Lambda); 117 | // copied->deep_copy_from(*l); 118 | // fused.push_back(copied); 119 | // } 120 | } 121 | 122 | 123 | ostream& operator<<(ostream& stream, const Literal& lit) { 124 | stream << "<" << lit.val << ">"; 125 | return stream; 126 | } 127 | 128 | ostream& operator<<(ostream& stream, Lambda *l) { 129 | stream << "(λ:" << to_string(l->type) << " "; 130 | for (auto a : l->argnames) stream << a << " "; 131 | stream << *l->body << ")" << endl; 132 | return stream; 133 | } 134 | 135 | ostream& operator<<(ostream& stream, const Code& c) { 136 | stream << c.arity; 137 | 138 | if (c.l) { 139 | stream << *c.l; 140 | } else if (c.lit.val != "") { 141 | stream << "(λ " << c.lit << ")"; 142 | } else if (c.is_type()) { 143 | stream << "#" << to_string(c.rawtype); 144 | } 145 | 146 | stream << "["; 147 | for (const auto &a : c.args) stream << *a << ","; 148 | stream << "]"; 149 | 150 | stream << ":" << to_string(c.type); 151 | return stream; 152 | } 153 | 154 | ostream& operator<<(ostream& stream, const pair&& p) { 155 | stream << "(" << p.first << ", " << p.second << ")" << endl; 156 | return stream; 157 | } 158 | 159 | ostream& operator<<(ostream& stream, const Lambda& l) { 160 | // if (l.fused.size() == 0) { 161 | stream << "(λ "; 162 | for (auto a : l.argnames) stream << a << " "; 163 | if (l.body) stream << *l.body << ")" << endl; 164 | else stream << "--NO BODY LAMBDA--" << ")" << endl; 165 | // } else { 166 | // stream << "(λ-fuse "; 167 | // for (const shared_ptr fus : l.fused) { 168 | // stream << *fus; 169 | // } 170 | // stream << ")" << endl; 171 | // } 172 | return stream; 173 | } 174 | -------------------------------------------------------------------------------- /emelio.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "emelio.h" 3 | #include "util.h" 4 | #include "codegen.h" 5 | 6 | int main(int argc, char **argv) { 7 | Tokenizer tkn; 8 | // メンバアクセスのために.をなくした 9 | tkn.set("specials", "!#$%&()-^\\@[;:],/=~|{+*}<>?."); 10 | tkn.set("escaper", "\"'`"); 11 | tkn.set("ignores", ""); 12 | tkn.set("ignoresplit", " \t\n"); 13 | 14 | if (argc == 2) { 15 | tkn.tokenize(argv[1]); 16 | ParserFlow pf = {tkn.tokenvals, 0}; 17 | shared_ptr root = code(pf); 18 | reduction(root, true); 19 | 20 | cout << root->lit.val << endl; 21 | 22 | return stoi(root->lit.val); 23 | } else if (argc == 3) { 24 | auto back = cout.rdbuf(); 25 | cout.rdbuf(NULL); 26 | 27 | tkn.tokenize_file(argv[2]); 28 | ParserFlow pf = {tkn.tokenvals, 0}; 29 | shared_ptr root = code(pf); 30 | extract_all_notations(root, true); 31 | 32 | // rename_variables(root); 33 | // auto tmp = codegen2()(root); 34 | // auto body = fasm(tmp.root); 35 | // auto env = fasm(tmp.env); 36 | 37 | // ofstream ofs1("compiled/code.inc"); 38 | // ofstream ofs2("compiled/env.inc"); 39 | 40 | // ofs1 << body << endl; 41 | // ofs2 << env << endl; 42 | 43 | cout.rdbuf(back); 44 | 45 | // cout << e << endl; 46 | } else if (argc > 2) { 47 | std::cin >> std::noskipws; 48 | std::istream_iterator it(std::cin); 49 | std::istream_iterator end; 50 | string input(it, end); 51 | 52 | tkn.tokenize(input); 53 | ParserFlow pf = {tkn.tokenvals, 0}; 54 | shared_ptr root = code(pf); 55 | reduction(root, true); 56 | 57 | cout << root->lit.val << endl; 58 | 59 | return stoi(root->lit.val); 60 | } else { 61 | 62 | tkn.tokenize_file("test.em"); 63 | 64 | // showv(tkn.tokenvals); 65 | 66 | ParserFlow pf = {tkn.tokenvals, 0}; 67 | 68 | shared_ptr root = code(pf); 69 | // set_type()(root); 70 | // cout << *root << endl; フル時計 71 | 72 | extract_all_notations(root, true); 73 | { 74 | Tokenizer tmptkn = tkn; 75 | reparse_types(root, tmptkn); 76 | } 77 | cout << "pang"; 78 | cout << *root << endl; 79 | rename_variables(root); 80 | set_arity()(root); 81 | set_type()(root); 82 | 83 | cout << *root << endl; 84 | 85 | cout << 'a' << endl; 86 | // cout << transpile(root, "c"); 87 | Compiled result; 88 | codegen7 codegen; 89 | result = codegen(root); 90 | result.global += codegen.print_polymos(); 91 | 92 | // cout << "prepare name hash:\n"; 93 | // Compiled result; 94 | // result = codegen6()(root); 95 | 96 | // result = codegen5()(root, nullptr, true); 97 | 98 | 99 | // ofstream ofs1("compiled/code.c"); 100 | // ofstream ofs2("compiled/env.c"); 101 | // ofs1 << result.body << endl; 102 | // ofs2 << result.env << endl; 103 | 104 | ofstream ofs3("compiled/code7.c"); 105 | ofs3 << "#include " << endl; 106 | ofs3 << "#include " << endl; 107 | ofs3 << result.global << endl << endl; 108 | ofs3 << "int __main__() { " << endl; 109 | ofs3 << result.env << endl; 110 | if (result.return_required) ofs3 << "return " << result.body << ";" << endl; 111 | else ofs3 << result.body << endl; 112 | ofs3 << "}" << endl; 113 | ofs3 << "int main() { printf(\"%d\\n\", __main__()); return 0; }" << endl << endl; 114 | 115 | // cout << "#include " << endl; 116 | // cout << "int __main__() { " << endl; 117 | cout << result.global << endl; 118 | cout << result.env << endl; 119 | if (result.return_required) cout << "return " << result.body << ";" << endl; 120 | else cout << result.body << endl; 121 | // cout << "}" << endl; 122 | // cout << "void main() { printf(\"%d\\n\", __main__()); }" << endl << endl; 123 | 124 | 125 | // cout << *root << endl; 126 | 127 | 128 | return 0; 129 | } 130 | } 131 | 132 | /* 133 | ((|f g| (|x| f (g x))) negate negate) 3 134 | 135 | */ 136 | -------------------------------------------------------------------------------- /emelio.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef EMELIO_H 3 | /* ======================================================================== 4 | $File: emelio.h $ 5 | $Date: Jul 07 2019 $ 6 | $Revision: $ 7 | $Creator: Creative GP $ 8 | $Notice: (C) Copyright 2019 by Creative GP. All Rights Reserved. $ 9 | ======================================================================== */ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "Tokenizer/util.h" 29 | #include "Tokenizer/tokenizer.h" 30 | 31 | 32 | #define CONTAINS(c,v) ((c).find(v) != (c).end()) 33 | #define REFEQUAL(a,b) (&(a) == &(b)) 34 | #define INDEXOF(c,v) (distance((c).begin(), find((c).begin(), (c).end(), v))) 35 | #define FOR(i,a,b) for(int i=a;i 38 | #define MATCHS(t) holds_alternative> 39 | #define PURE(t) get 40 | #define PURES(t) get> 41 | #define ELIMINATE(v,x,y) ((v) == (x) ? (y) : (v)) 42 | 43 | 44 | #define internal_global static 45 | #define persistent static 46 | 47 | #define ARG(x) const x& 48 | #define MUT_ARG(x) x& 49 | 50 | 51 | struct ParserFlow { 52 | vector &tknvals; 53 | int idx; 54 | map> polymos; 55 | }; 56 | struct Code; 57 | struct Literal; 58 | struct Lambda; 59 | 60 | 61 | 62 | // Type = String | shared_ptr 63 | // TypeSignature = { from: [Type], to: Type } 64 | 65 | // struct TypeSignature; 66 | // // typedef deque AndType; 67 | // // typedef deque OrType; 68 | // typedef variant/*, AndType, OrType*/> Type; 69 | struct SpecialValue; struct Parametered; struct TypeProduct; struct TypeSum; struct TypeFn; struct TypeNull { int dummy; /*なんかvariantは空の型無理な奴らしいから*/ }; 70 | struct SpecialValue { 71 | string val; 72 | }; 73 | typedef variant,string,SpecialValue,shared_ptr,shared_ptr,shared_ptr,shared_ptr> TypeSignature; 74 | struct TypeSum { 75 | deque sums; 76 | // TODO: いまはこれだけ特別扱いする感じで実装してるけど、TypeSignatureにあたらしくTypeSpecialみたいなの導入して、sumsにまとめてしまったほうが見通しが良いかも(normalizeの処理とか) 77 | void add_type(TypeSignature ts) { 78 | if (find(sums.begin(), sums.end(), ts) == sums.end()) { 79 | sums.emplace_back(ts); 80 | } 81 | } 82 | }; 83 | struct TypeProduct { 84 | deque products; 85 | deque names; 86 | }; 87 | struct TypeFn { 88 | deque from; 89 | TypeSignature to; 90 | }; 91 | struct Parametered { 92 | string type; 93 | deque params; 94 | }; 95 | bool equal(const TypeSignature &ts1, const TypeSignature &ts2, const map &bind = {}, int lvl = 0); 96 | bool verify(const TypeSignature &ts1, const TypeSignature &ts2, const map &bind = {}, int lvl = 0); 97 | //bool verify(const TypeSignature &ts1, const TypeSignature &ts2, const map &bind = {}); 98 | bool is_functional(const TypeSignature &ts1); 99 | bool arity(const TypeSignature &ts); 100 | bool operator==(const TypeSignature &ts1, const TypeSignature &ts2); 101 | void deep_copy_from(TypeSignature &ts_dst, const TypeSignature &ts_src); 102 | string to_string(const TypeSignature &typesig); 103 | TypeSignature sumfactor(const shared_ptr &sumtype); 104 | void _normalize(TypeSignature &typesig); 105 | void normalize(TypeSignature &typesig); 106 | TypeSignature normalized(const TypeSignature &typesig); 107 | TypeSignature arg(const TypeSignature &typesig, int n); 108 | void apply(TypeSignature &typesig, const int n); 109 | void wrap(TypeSignature &typesig, const TypeSignature &wrp); 110 | 111 | //typedef deque>> DataStructure; 112 | 113 | // struct TypeSignature { 114 | // shared_ptr type_code; 115 | 116 | // TypeSignature() {} 117 | // ~TypeSignature() {} 118 | // TypeSignature(shared_ptr c) : type_code(c) {} 119 | // TypeSignature outcome() const; 120 | // int arity() const; 121 | // bool functional() const; 122 | // bool funcgen() const; 123 | // void apply(int n); 124 | // void wrap(const TypeSignature &typesig); 125 | // void normalize(); 126 | // void normalized(shared_ptr c) const; 127 | // string to_string(const shared_ptr c) const; 128 | // string to_string() const; 129 | // void deep_copy_from(const TypeSignature& src); 130 | // }; 131 | 132 | 133 | struct Literal { 134 | string val; 135 | }; 136 | 137 | struct TknvalsRegion { 138 | vector::iterator beg, end; 139 | 140 | size_t size() const { 141 | return distance(this->beg, this->end); 142 | } 143 | }; 144 | 145 | struct Code { 146 | shared_ptr l; 147 | Literal lit; 148 | deque> args; 149 | 150 | // NOTE: tknvalsは変更されないことを想定しています 151 | TknvalsRegion src; 152 | 153 | TypeSignature rawtype; // Codeとして型注釈が書いてある場合 :Type 154 | TypeSignature type; 155 | 156 | 157 | int arity = 0; 158 | 159 | shared_ptr cRawtype; 160 | 161 | void deep_copy_from(const Code& other); 162 | vector plain_string(); 163 | bool is_type() const; 164 | }; 165 | 166 | struct ArgQuality { 167 | bool recursive = false; 168 | }; 169 | 170 | 171 | struct Lambda { 172 | vector argnames {}; 173 | shared_ptr body; 174 | vector argarities {}; 175 | vector argqualities {}; 176 | vector argtypes {}; 177 | vector> cArgtypes {}; 178 | 179 | TypeSignature type; 180 | 181 | vector freevars {}; 182 | 183 | // vector> fused; 184 | 185 | void deep_copy_from(const Lambda& other); 186 | }; 187 | 188 | struct CodegenFlow { 189 | shared_ptr c; 190 | deque unbinded; 191 | deque> argstack; 192 | set defined; 193 | unsigned fstack_offset = 0; // for recursion 194 | set in_recursion; 195 | map> bind; 196 | }; 197 | 198 | unique_ptr code(ParserFlow& p); 199 | //pair parse(ARG(vector) tknvals, int initial_idx = 0, string basename = ""); 200 | TypeSignature type_signature(ParserFlow& p); 201 | void reduction(shared_ptr code, bool silent = false); 202 | void extract_all_notations(shared_ptr &c, bool silent = false); 203 | void reparse_types(shared_ptr &code, Tokenizer &tkn); 204 | 205 | bool is_computed(const shared_ptr &c); 206 | std::string get_eventual_fnname( shared_ptr ); 207 | 208 | ostream& operator<<(ostream& stream, const Literal&); 209 | ostream& operator<<(ostream& stream, const Code&); 210 | ostream& operator<<(ostream& stream, const Lambda&); 211 | ostream& operator<<(ostream& stream, Lambda*); 212 | 213 | ostream& operator<<(ostream& stream, const pair&&); 214 | 215 | 216 | #define EMELIO_H 1 217 | #endif 218 | -------------------------------------------------------------------------------- /lab.em: -------------------------------------------------------------------------------- 1 | 2 | ・型システム 3 | ・fuse, notationをもっと自由な関数らしい関数に 4 | (これは無理かも)・C or C++に変換して簡易コンパイラ 5 | それ以降 6 | ・importシステム 7 | ・メモリ見直し 8 | ・boostを使ってみる 9 | ・その他実用において欲しいシステム... 10 | 11 | fuseは関数の定義域を合わせる。 12 | 13 | 14 | +--------------+ 15 | | | 16 | | Raw String | 17 | | | 18 | +------+-------+ 19 | | 20 | |tokenize 21 | | 22 | +------v-------+ 23 | | | 24 | | Tokens | 25 | | | 26 | +------+-------+ 27 | | 28 | |parse 29 | | 30 | +------v-------+ 31 | | | 32 | | Code(unnoted)| 33 | | | 34 | +------+-------+ 35 | | 36 | |notation 37 | v 38 | +------+-------+ 39 | | | 40 | | Code | 41 | | | 42 | +------+-------+ 43 | | 44 | |codegen 45 | v 46 | +------+-------+ 47 | | | 48 | | C++ | 49 | | | 50 | +--------------+ 51 | 52 | 53 | マクロ. codeに適用するnotationと、type signatureに適用するtotation(type notation)がある. 54 | まずはnotationについて。 55 | notationはCodeとして与えられるソースに対して、書換を行う。 56 | 入力はラムダ式の形で書かれているので、全体が条件にマッチするならば書換を行えばよい。 57 | 条件の書き方が問題になる。 58 | 例えば、足し算ならば 59 | A + Bs -> add A Bs 60 | でも良いし、 61 | As + B -> add As B 62 | でも良い。 63 | 単項演算子なら、 64 | - A -> negate A 65 | とする。これは 66 | create -2 3 67 | のように使いたいので、 68 | 69 | 70 | 71 | 型の書き方は基本的に、関数の引数の名前に:(コロン)をつけてその後に型を書く感じ。 72 | 型の書き方は、疑似関数を使って、通常の関数と同じようにCodeで解析できるものを書く。 73 | notationは型用のnotationを用意してそれだけ適用するようにする(種類増えるけど、余計なやつ毎回マッチ確かめるよりはいいよね) 74 | 75 | 型は値の集合を表しているということにしておいた。 76 | でも、これはHaskellとは違う。 77 | data Alpha = A Int 78 | で定義されたAlphaと、Intは違う。 79 | これのメリットは何だろうか。 80 | 81 | 82 | validな型注釈もいろいろある. 83 | :List 84 | :(A B C) 85 | :(A (B|C)) 86 | :((A-B->B) C) 87 | ※:(first:A second:(A->A)) 88 | :List 89 | :List> 90 | 91 | これに独自記法をいれる(もちろんカオスになる) 92 | :[A] で :List を表すとすれば 93 | :[A [A]] 94 | 95 | [ , A [ A ] ] 96 | 97 | もvalidになる. 98 | 99 | 100 | 101 | (add (negate 5) (negate 5)) 102 | 103 | type Either(a) = a | Null 104 | 105 | grow: Seed -> Either(Vegetable) 106 | 107 | 108 | Bind nomi 109 | a 3 3; 110 | b 6; 111 | c 2 112 | 113 | | 114 | v 115 | 116 | notation A ; B = (|x| B) (A) 117 | 118 | (|x| c 2) ((|x| b 6) (a 3 3)) 119 | 120 | 121 | 122 | 123 | let :: Bind #Symbol a -> a Bind 124 | :: Bind /#Symbol a -> a/ 125 | 126 | (|x| (let (get_bind x) b 2)) (let _bind a 3) 127 | 128 | (add (negate 2) (negate 3)) 129 | 130 | (|bind| (|bind| add a b) (let a 3)) (let b 8) 131 | 132 | Bind { let b 3 133 | ; let a 3 134 | ; add a b 135 | } 136 | 137 | 138 | Bindは変数があるなら全て必要。 139 | 140 | 積型を[a1 a2 a3 a4...]みたいに書くことにすると、 141 | add [negate 1 negate 3] 142 | のようになる。関数適用のspaceと、積型のspaceが一緒なので見にくい気もするし、関数の横だけ見れば良いので大丈夫という気もする。 143 | ex) 144 | add [negate 1 3] 145 | add [add [1 3] 3] 146 | 147 | (|x y| x + y) [1 3] 148 | 149 | 150 | (|x| let [get_bind x b 2]) let [_bind a 3] 151 | 152 | (add [negate 2 negate 3]) 153 | 154 | (|bind| (|bind| add [a b]) let [a 3]) let [b 8] 155 | 156 | Bind { let [b 3] 157 | ; let [a 3] 158 | ; add [a b] 159 | } 160 | いろいろ書いてみて分かったけど、やっぱりわかりにくい。関数名が変数っぽかったら終わる 161 | foo [x a b c] -- 完全に4つ撮ってるように見えるけど、実際は3つ(x:fn) 162 | foo (x a) b c -- よくわかる(括弧とかの最初が関数) 163 | 164 | add [negate 1 negate 3] 165 | 166 | 167 | 168 | <関数適用> 169 | このプログラミング言語においてエッセンシャルな部分としては集合(関数としても実装可能)と関数になる。 170 | 関数は作ることが出来て、適用することができれば十分だ。 171 | なので、まず作り方と適用のやりかたを表す関数を作る。(ここがややこしい、循環???) 172 | 173 | 作り方(記法) 174 | (|引数| 返り値) 175 | 176 | 適用とは 177 | (|x y| x + y) 1 2 --> 1 + 2 178 | 文字列的な処理なので、 179 | apply: (a -> b) a -> b 180 | apply: #Fn a -> #Fn 181 | と二通りに書ける。前者は書いたはそこまでで実装は出来ないけど、後者は実装することが出来る。 182 | この違いは何だろうか. 183 | 184 | <文字列でないと表現できないプログラムがあった> 185 | それはそう。ただ、ラムダ計算の理論が言っていることは、関数の生成と適用さえあればOKということだと思うので(違う??) 186 | これ以外の意味を変更するようなnotationを禁止するようにする。もっと言えば、関数の適用に対するnotationしか認めないようにするとOKということOK。 187 | 188 | 189 | <本質的な循環> 190 | コンパイラ・インタプリタという代物について考えてみる。 191 | コンパイラは[#Symbol] -> 192 | 193 | 194 | 195 | composition: (b -> c) (a -> b) -> (a -> c) = (|g f| g f) 196 | (composition inc negate) 3 -- -2 197 | inc negate 3 -- -2 198 | 199 | は?ラムダ抽象を使う. 200 | 201 | composition: (b -> c) (a -> b) -> (a -> c) = \g f -> \x -> g (f x) 202 | (composition inc negate) 3 -- -2 203 | (\x -> inc (negate x)) 3 204 | inc (negate 3) 205 | 206 | 207 | <関数の記法についての考察> 208 | 209 | Haskellでは関数を 210 | \引数 -> 項 211 | のように書いている。 212 | 213 | Emelioでは 214 | (|引数| 項) 215 | のように書く予定だったが、実際何が一番良いのか考えてみる。 216 | 217 | <<<括弧をつけることが意味することとは>>> 218 | 括弧、つけすぎるとlispみたいになってミスが起こったり書きにくかったりするのも確かです。変更もやりにくい。 219 | どんな時に括弧がいるのでしょう。 220 | ずばり、範囲を決めないといけないときです。始点・終点のみを決めないといけない時には括弧は必要ありません。 221 | この場合は 222 | 223 | 224 | ((|f g| (|x| f (g x))) negate negate) 3 225 | 226 | (add 2 3) 227 | 228 | add 229 | 2 3 230 | 231 | (|x y| add x y) 232 | ((|z1| negate z1) 3) 233 | ((|z2| 3) (add 2 3)) 234 | 235 | <<<簡約>>> 236 | 基本的にやることは変数の置き換え。 237 | 238 | 239 | <<<シンボルを取る関数は必要か>>> 240 | (notation (A ; B) ((|x| B) (A)) ( 241 | add 3 2; 242 | add 4 7 243 | )) 244 | 245 | 246 | <<<言語の指針>>> 247 | ・何が悪い言語か 248 | まずは自分の意見を書く。 249 | プログラミング言語は目的があって使われる。当然選択するプログラミング言語も、今書こうと思っているプログラムによって使い分ける。 250 | 今回作ろうと思っている言語は汎用言語である。色々な目的で使えるぜ!っていう言語。 251 | では、プログラミング言語がそのプログラムにマッチしているとはどのようなことを言うのか。 252 | たとえば、「競技プログラミングに向いている言語」といったときには。 253 | 「競プロで書くプログラムの集合」にたいして、それぞれその言語で表現をした時に、 254 | その長さとか可読性、書きやすさ、Customizabilityとか色々あるんでしょう。 255 | なので、評価関数E(r)を定義しておくと、 256 | Σ E(r in 競プロで書くプログラムの表現の集合) 257 | みたいなものが大きいプログラミング言語のことを言うのでしょう。 258 | 259 | ではこれをどうやって測るのかと言うのが問題になってくる。結局そこが人間によるのでしょう。 260 | 261 | 色々な人の意見を聞く。 262 | [https://medium.com/smalltalk-talk/the-three-worst-programming-languages-b1ec25a232c1] 263 | 264 | 265 | 266 | <<[Bytes]を取る関数はできるか、作ったほうが良いか>> 267 | プログラムなど、PCの全てはByte * Byte * ... = [Byte]として表現されます。 268 | 型なし言語はこのようなこの型しか搭載していない言語と言えます。 269 | 今のところは[Byte]しか実装していないので、この上で考えていきます。型の導入仕方についても考えたいと思います。 270 | 271 | さて、今作っているのは関数として捉えるとどのような関数化でしょう? 272 | インタプリタは関数を簡約化する作業です。 273 | 274 | parser: [Byte] -> (a -> a) 275 | interpreter: World (a -> a) -> World (a -> a) 276 | applier: a (a -> a) -> a 277 | ref: [Byte] -> (a -> a) 278 | 279 | ここで、今私たちは記法について扱いたいわけです。 280 | parserをかましてからは全て関数の表現になっているので、parserのような関数となるわけです。 281 | 282 | 作って良いでしょう。 283 | 284 | <<優先順位、結合方向>> 285 | 大体の場合、記法を使う時は演算子のような関数のときか、初期化子を作るときなのではないかと思います。 286 | この内、演算子のような記法はすなわち 3 f 2 --> f 3 2 のような変換なわけですが、3 f 2 f 5と書かれたときの解釈の仕方として、 287 | 結合方向を決定しなければならないという問題があります。 288 | 289 | 3 f 2 f 5 ---> f 3 (f 2 5) -or- (f (f 3 2) 5) 290 | 291 | 規則は、A f B ---> f (A) (B)のような形で書かれます。変換後は関数のような形をしてなければなりません。 292 | これは一種の機能制限ですが、これを許してしまうとかなり変な書き方になります。 293 | 基本的には関数で出来るので、記法の改造も関数のシノニムに過ぎないとしても大丈夫だと踏んでます。(名前結合子の存在は?) 294 | 295 | まぁこれはそういうこととして、話を戻します。A f B ---> f (A) (B)変換があった時、 296 | 3 f 2 f 5 297 | はどのように変換されるべきでしょうか。 298 | 前から変換していくと、 299 | 300 | ,A f B, --> f (A) (B) 301 | 302 | ,(|x y| ,x f y,) f (3 f 2), 303 | 304 | lexer: [Byte] -> [#Symbol] 305 | parser: [#Symbol] -> (a -> a) 306 | intprt: (a -> a) -> (a -> a) /World 307 | notation: [#Symbol] (a -> a) (a -> a) -> (a -> a) 308 | 309 | <結合性とnotation> 310 | (As f Bs) = (f As Bs) 311 | という規則があったら、現行の実装(gnotation)では 312 | 3 f 5 f 7 f 2 は 313 | 3 f (5 f 7 f 2) 314 | f 3 (5 f 7 f 2) 315 | f 3 (f 5 (7 f 2)) 316 | f 3 (f 5 (f 7 2)) 317 | というように変換される 318 | 3 f 5 f 7 f 2 は 319 | 3 f (5 f 7 f 2) 320 | f (5 f 7 f 2) 3 321 | f (f (7 f 2) 5) 3 322 | f (f (f 2 7) 5) 3 323 | 324 | notationは 325 | (As f Bs) = (f As Bs) 326 | という規則があったら 327 | 3 f 5 f 7 f 2 は 328 | (3 f 5) f 7 f 2 329 | (f 3 5) f 7 f 2 330 | (f (f 3 5) 7) f 2 331 | f (f (f 3 5) 7) 2 332 | というように変形される 333 | 334 | 335 | (notation (A = B ; C) ((|A| C) (B)) ( 336 | (notation (A ; B) ((|x| B) (A)) ( 337 | c = 8; 338 | add c 7; 339 | add 3 2; 340 | add 4 c 341 | )))) 342 | 343 | (notation (A ; B) ((|x| B) (A)) ( 344 | add c 7; 345 | add 3 2; 346 | add 4 c 347 | )) 348 | 349 | (notation (As $ Bs) (As (Bs)) ( 350 | (notation (let A = Bs ; Cs) ((|A| Cs) (Bs)) ( 351 | (notation (As ; Bs) ((|x| Bs) (As)) ( 352 | let c = (|x y| add x y) 2 (negate 3); 353 | add 3 2; 354 | add 2 c 355 | )) 356 | )) 357 | )) 358 | 359 | 360 | 361 | let c = 3 ; add c 7 ; add 3 2 ; add 4 c 362 | (|c| (|x| (|x| add 4 c)) 3 363 | 364 | (|x| B) (A) 365 | 366 | (notation (PREDICTs ? TRUEs else FALSEs) ((fuse (|1| TRUEs) (|otherwise| FALSEs)) PREDICTs) ( 367 | (notation (As == Bs) ((fuse (|Bs| 1) (|otherwise| 0)) As) ( 368 | 3 == 3 ? yes else no 369 | )) 370 | )) 371 | 372 | 373 | 374 | (gnotation (notation As =>> Bs ; Cs) (notation As Bs Cs) ( 375 | (gnotation (let A = Bs ; Cs) ((|A| Cs) (Bs)) ( 376 | (gnotation (As ; Bs) ((|x| Bs) (As)) ( 377 | notation PREDICTs ? TRUEs else FALSEs =>> (fuse (|1| TRUEs) (|otherwise| FALSEs)) PREDICTs; 378 | notation As == Bs =>> (fuse (|Bs| 1) (|otherwise| 0)) As; 379 | notation As $ Bs =>> As Bs; 380 | notation As + Bs =>> add As Bs; 381 | notation As - Bs =>> subtract As Bs; 382 | 383 | let subtract = (|a b| 384 | add a $ negate b 385 | ); 386 | let mul = (|a b| 387 | b == 0 ? 388 | 1 389 | else 390 | add a $ mul a (b - 1) 391 | ); 392 | 393 | mul 4 5 394 | )) 395 | )) 396 | )) 397 | 398 | (gnotation (notation As =>> Bs ; Cs) (notation As Bs Cs) ( 399 | (gnotation (let A = Bs ; Cs) ((|A| Cs) (Bs)) ( 400 | notation PREDICTs ? TRUEs else FALSEs =>> (fuse (|1| TRUEs) (|otherwise| FALSEs)) PREDICTs; 401 | notation As == Bs =>> (fuse (|Bs| 1) (|otherwise| 0)) As; 402 | let mul = (|a b| b == 0 ? 0 else add a (mul a (add b (negate 1)))); 403 | mul 4 5 404 | )) 405 | )) 406 | 407 | (notation (PREDICTs ? TRUEs else FALSEs) ((fuse (|1| TRUEs) (|otherwise| FALSEs)) PREDICTs) ( 408 | (notation (As == Bs) ((fuse (|Bs| 1) (|otherwise| 0)) As) ( 409 | (|mul| mul 7 8) (|a b| b == 0 ? 0 else add a (mul a (add b (negate 1)))) 410 | )) 411 | )) 412 | 413 | (notation (PREDICTs ? TRUEs else FALSEs) ((fuse (|1| TRUEs) (|otherwise| FALSEs)) PREDICTs) ( 414 | (notation (As == Bs) ((fuse (|Bs| 1) (|otherwise| 0)) As) ( 415 | 3 == 3 ? yes else no 416 | )) 417 | )) 418 | 419 | 420 | (gnotation (notation As =>> Bs ; Cs) (notation As Bs Cs) ( 421 | (gnotation (let A = Bs ; Cs) ((|A| Cs) (Bs)) ( 422 | (gnotation (As ; Bs) ((|x| Bs) (As)) ( 423 | notation PREDICTs ? TRUEs else FALSEs =>> (fuse (|1| TRUEs) (|otherwise| FALSEs)) PREDICTs; 424 | notation As == Bs =>> (fuse (|Bs| 1) (|otherwise| 0)) As; 425 | notation As + Bs =>> add As Bs; 426 | notation As - Bs =>> subtract As Bs; 427 | notation As * Bs =>> multiplicate As Bs; 428 | notation As $ Bs =>> As Bs; 429 | 430 | let subtract = (|a b| 431 | add a $ negate b 432 | ); 433 | let multiplicate = (|a b| 434 | b == 0 ? 435 | 0 436 | else 437 | add a $ multiplicate a (b - 1) 438 | ); 439 | let mulWord = (|a b| 440 | b == 0 ? 441 | . 442 | else 443 | concat a $ mulWord a (b - 1) 444 | ); 445 | 446 | let fib = (|n| 447 | n == 1 ? 1 448 | else ( 449 | n == 2 ? 1 450 | else fib (n - 1) + fib (n - 2) 451 | ) 452 | ); 453 | 454 | fib 6 455 | )) 456 | )) 457 | )) 458 | 459 | 460 | 461 | 心配なコード 462 | 463 | (|f| f 2 3) add 464 | 465 | (|f| f 3) 466 | (fuse (|2| 1) (|otherwise| 0)) 467 | (gnotation (notation As =>> Bs ; Cs) (notation As Bs Cs) ( 468 | (gnotation (let A = Bs ; Cs) ((|A| Cs) (Bs)) ( 469 | (gnotation (As ; Bs) ((|x| Bs) (As)) ( 470 | notation PREDICTs ? TRUEs else FALSEs =>> (fuse (|1| TRUEs) (|otherwise| FALSEs)) PREDICTs; 471 | notation As == Bs =>> (fuse (|Bs| 1) (|otherwise| 0)) As; 472 | notation As + Bs =>> add As Bs; 473 | notation As - Bs =>> subtract As Bs; 474 | notation As * Bs =>> multiplicate As Bs; 475 | notation As $ Bs =>> As Bs; 476 | 477 | let subtract = (|a b| 478 | add a $ negate b 479 | ); 480 | let multiplicate = (|a b| 481 | b == 0 ? 482 | 0 483 | else 484 | add a $ multiplicate a (b - 1) 485 | ); 486 | let mulWord = (|a b| 487 | b == 0 ? 488 | . 489 | else 490 | concat a $ mulWord a (b - 1) 491 | ); 492 | 493 | let fib = (|n| 494 | n == 1 ? 1 495 | else ( 496 | n == 2 ? 1 497 | else fib (n - 1) + fib (n - 2) 498 | ) 499 | ); 500 | 501 | 502 | p 503 | )) 504 | )) 505 | )) 506 | 507 | (gnotation (notation As =>> Bs ; Cs) (notation As Bs Cs) ( 508 | (gnotation (let A: TYPEs = Bs ; Cs) ((|A| Cs) (Bs)) ( 509 | (gnotation (let A = Bs ; Cs) ((|A| Cs) (Bs)) ( 510 | (gnotation (As ; Bs) ((|x| Bs) (As)) ( 511 | notation PREDICTs ? TRUEs else FALSEs =>> (fuse (|1| TRUEs) (|otherwise| FALSEs)) PREDICTs; 512 | notation As == Bs =>> (fuse (|Bs| 1) (|otherwise| 0)) As; 513 | notation As + Bs =>> add As Bs; 514 | notation As - Bs =>> subtract As Bs; 515 | notation As * Bs =>> multiplicate As Bs; 516 | notation As $ Bs =>> As Bs; 517 | 518 | let subtract = (|a b| 519 | add a $ negate b 520 | ); 521 | let multiplicate = (|a b| 522 | b == 0 ? 523 | 0 524 | else 525 | add a $ multiplicate a (b - 1) 526 | ); 527 | let mulWord = (|a b| 528 | b == 0 ? 529 | . 530 | else 531 | concat a $ mulWord a (b - 1) 532 | ); 533 | 534 | let fib = (|n| 535 | n == 1 ? 1 536 | else ( 537 | n == 2 ? 1 538 | else fib (n - 1) + fib (n - 2) 539 | ) 540 | ); 541 | 542 | 543 | p 544 | )) 545 | )) 546 | )) 547 | 548 | let multiplicate = (|a b| 549 | 550 | notation PREDICTs ? TRUEs else FALSEs =>> (fuse (|1| TRUEs) (|otherwise| FALSEs)) PREDICTs; 551 | notation As == Bs =>> (fuse (|Bs| 1) (|otherwise| 0)) As; 552 | notation As + Bs =>> add As Bs; 553 | notation As - Bs =>> subtract As Bs; 554 | notation As * Bs =>> multiplicate As Bs; 555 | gnotation As $ Bs =>> As Bs; 556 | 557 | b == 0 ? 558 | 0 559 | else 560 | add a $ multiplicate a (b - 1) 561 | ); 562 | let mulWord = (|a b| 563 | b == 0 ? 564 | . 565 | else 566 | concat a $ mulWord a (b - 1) 567 | ); 568 | 569 | let fib = (|n| 570 | n == 1 ? 1 571 | else ( 572 | n == 2 ? 1 573 | else fib (n - 1) + fib (n - 2) 574 | ) 575 | ); 576 | 577 | 578 | p 579 | 580 | (|sub| 581 | 582 | (|sub| 583 | 584 | (|ass| ass 5) 585 | (|n| 586 | (fuse 587 | (|0| 0) 588 | (|x| add x (ass (sub x 1)))) n 589 | ) 590 | ) 591 | (|a b| add a (negate b)) 592 | 593 | (|acc| acc 5) (|f| (fuse (|1| 1) (|x| add x (acc (sub x 1)))) f) 594 | 595 | 596 | -------------------------------------------------------------------------------- /notation.cpp: -------------------------------------------------------------------------------- 1 | /* ======================================================================== 2 | $File: notation.cpp $ 3 | $Date: Sep 09 2019 $ 4 | $Revision: $ 5 | $Creator: Creative GP $ 6 | $Notice: (C) Copyright 2019 by Creative GP. All Rights Reserved. $ 7 | ======================================================================== */ 8 | 9 | #include "emelio.h" 10 | #include "util.h" 11 | #include "notation.h" 12 | 13 | // 変数の名前かどうか 14 | inline bool is_notation_variable(const string& s) { 15 | bool res = true; 16 | for (char c : s) if (!isupper(c)) res = false; 17 | return res; 18 | } 19 | 20 | // 自由変数の名前かどうか 21 | inline bool is_notation_free_variable(const string& s) { 22 | bool res = true; 23 | for (int i = 0; i < s.size()-1; ++i) 24 | if (!isupper(s[i])) res = false; 25 | if (s.back() != 's') res = false; 26 | return res; 27 | } 28 | 29 | 30 | // 自由変数が最初にある時以外、定義が(λ )[(λ <4>)[],(λ <8>)[],]として解釈しなければならないところが、 31 | // [(λ )[],(λ <4>)[],(λ <8>)[],]として流れてくるのを修正する 32 | void fix_defs_fv(map> &defs) { 33 | for (auto& [key, val] : defs) { 34 | if (is_notation_free_variable(key) && val->lit.val == "" && !val->l) { 35 | shared_ptr newcode = make_shared(*val->args[0]); 36 | copy(val->args.begin()+1, 37 | val->args.end(), 38 | back_inserter(newcode->args)); 39 | val = newcode; 40 | } 41 | } 42 | } 43 | 44 | // 変数名で記述されたコード c に定義セット d を代入していく 45 | void replace_code(shared_ptr c, const map> &d) { 46 | if (c->l) { 47 | for (string &a : c->l->argnames) { 48 | if (CONTAINS(d, a)) { 49 | /* 引数名も変える(おそらく、ただの変数として定義されているはずなのでそのままlitを引っ張り出す) 50 | 51 | ex. 52 | (|A| ... ) { A => (λ )[] } 53 | を 54 | (|windows| ...) 55 | に変換 56 | */ 57 | a = d.at(a)->lit.val; 58 | } 59 | } 60 | 61 | replace_code(c->l->body, d); 62 | } else if (c->lit.val != "") { 63 | if (CONTAINS(d, c->lit.val) && (is_notation_variable(c->lit.val) || is_notation_free_variable(c->lit.val))) { 64 | /* 65 | 変数の書換 66 | ・引数がない場合はそのまま置き換える 67 | ・引数があれば(つまり、Code { lit = 変数名, args = 存在, l = null }になっているはず) 68 |  lに新しくLambdaを作って、そのbodyとして定義を代入する 69 | */ 70 | if (c->args.size() == 0) { 71 | *c = *d.at(c->lit.val); 72 | return; 73 | } else { 74 | if (c->l) cout << "[GIWAKU] どうやってやったんだ..." << endl; 75 | 76 | c->l = shared_ptr(new Lambda); 77 | c->l->body = make_shared(*d.at(c->lit.val)); 78 | } 79 | } 80 | } 81 | 82 | 83 | // for (auto &a : c->args) { 84 | for (int i = 0; i < c->args.size(); ++i) { 85 | replace_code(c->args[i], d); // ?; 86 | } 87 | } 88 | 89 | // [notationのマッチ関数] 変数にマッチ 90 | shared_ptr match_variable(shared_ptr &c, int &index, bool checkonly) { 91 | 92 | if (index == 0) { 93 | cout << "variable: " << *c << endl; 94 | index++; 95 | return c; 96 | } else { 97 | if (c->args.size() < index) 98 | { 99 | index = -1; 100 | return c; 101 | } else { 102 | cout << "variable: " << *c->args[index-1] << endl; 103 | return c->args[(index++)-1]; 104 | } 105 | } 106 | } 107 | 108 | // [notationのマッチ関数] 自由変数にマッチ 109 | shared_ptr 110 | match_free_variable(shared_ptr &c, const vector &rest_config, int &index, bool checkonly) { 111 | shared_ptr tmp; 112 | 113 | if (!checkonly) { 114 | if (index == 0) { 115 | tmp = make_shared(); 116 | tmp->l = c->l; 117 | tmp->lit = c->lit; 118 | 119 | // TODO: srcを変えるなら前と同じようにここで 120 | 121 | index++; 122 | 123 | if (check_match_notation(c, rest_config, index)) { 124 | if (!checkonly) 125 | cout << "Free variable: " << *tmp << endl; 126 | return tmp; 127 | } 128 | } else { 129 | tmp = make_shared(); 130 | // tmp = make_shared(*c->args[index-1]); 131 | } 132 | } 133 | 134 | for (auto e = next(c->args.begin(), index-1); e != c->args.end(); e++) { 135 | 136 | if (!checkonly) tmp->args.push_back(*e); 137 | index++; 138 | 139 | if (check_match_notation(c, rest_config, index)) { 140 | break; 141 | } 142 | } 143 | 144 | if (!checkonly) 145 | cout << "Free variable: " << *tmp << endl; 146 | 147 | return tmp; 148 | } 149 | 150 | // [notationのマッチ関数] 変数に貪欲にマッチ 151 | shared_ptr 152 | match_free_variable_greedily(shared_ptr &c, int &index, bool checkonly) { 153 | // 最後までtmpという新しいCodeを作ってその引数に入れていく 154 | shared_ptr tmp; 155 | if (!checkonly) tmp = make_shared(); 156 | 157 | if (index == 0) { 158 | if (!checkonly) tmp->args.push_back(c); 159 | index ++; 160 | } 161 | 162 | for (auto e = next(c->args.begin(), index-1); e != c->args.end(); e++) { 163 | if (!checkonly) tmp->args.push_back(*e); 164 | index++; 165 | } 166 | 167 | if (!checkonly) cout << "Free variable: " << *tmp << endl; 168 | 169 | return tmp; 170 | } 171 | 172 | // [notationのマッチ関数] 指定されたトークンにマッチ 173 | shared_ptr match_token(shared_ptr &c, string token, int &index, bool checkonly) { 174 | if (index == 0) { 175 | if (c->lit.val != token) { 176 | index = -1; 177 | return c; 178 | } else { 179 | cout << "Token: " << *c << endl; 180 | 181 | index ++; 182 | return c; 183 | } 184 | } else { 185 | if (c->args.size() < index || 186 | c->args[index-1]->lit.val != token) 187 | { 188 | index = -1; 189 | return c; 190 | } else { 191 | 192 | cout << "Token: " << *c->args[index-1] << endl; 193 | return c->args[(index++)-1]; 194 | } 195 | } 196 | } 197 | 198 | // notationがcodeにマッチするかどうか 199 | // するなら(定義セット, 残った要素, true)を返す 200 | tuple>, vector>, bool> 201 | match_notation(shared_ptr &code, const vector &config, bool greedily = false) { 202 | map> d; 203 | int hayidx = 0; 204 | 205 | for (auto c = config.begin(); c != config.end(); ++c) { 206 | if (is_notation_variable(*c)) { 207 | d[*c] = match_variable(code, hayidx, false); 208 | } else if (is_notation_free_variable(*c)) { 209 | if (c == prev(config.end())) { 210 | if (greedily) { 211 | d[*c] = match_free_variable_greedily(code, hayidx, false); 212 | } else { 213 | vector tmp = config; 214 | if (is_notation_free_variable(tmp[0])) 215 | tmp.erase(tmp.begin()); 216 | d[*c] = match_free_variable(code, tmp, hayidx, false); 217 | } 218 | 219 | // TODO: マッチするコードがなかったときのチェックはすべき 220 | break; 221 | } else { 222 | d[*c] = match_free_variable( 223 | code, vector(next(c), config.end()), hayidx, false); 224 | } 225 | } else { 226 | d[*c] = match_token(code, *c, hayidx, false); 227 | } 228 | 229 | if (hayidx == -1) return make_tuple(d, vector>(), false); 230 | } 231 | 232 | cout << "doen" << endl; 233 | 234 | return make_tuple(d, vector>(next(code->args.begin(), hayidx-1), code->args.end()), true); 235 | } 236 | 237 | // codeにnotation/gnotationを適用する 238 | bool apply_notation(shared_ptr &code, const Notation ¬ation, bool greedily) { 239 | // length check ? 240 | 241 | map> defs; 242 | vector> remains; 243 | 244 | { 245 | auto tmp = match_notation(code, notation.config, greedily); 246 | if (!get<2>(tmp)) return false; 247 | defs = get<0>(tmp); 248 | remains = get<1>(tmp); 249 | } 250 | 251 | code = make_shared(); 252 | code->deep_copy_from(*notation.to); 253 | 254 | cout << "before" << endl; 255 | cout << *code << endl << endl; 256 | 257 | fix_defs_fv(defs); 258 | 259 | for (auto it = defs.begin(); it != defs.end(); it++) { 260 | cout << "{" << it->first << "}" << endl; 261 | cout << *it->second << endl << endl; 262 | } 263 | 264 | replace_code(code, defs); 265 | // TDOO: gnotationならば全体としてマッチしたときのみ適用すべきという話もある 266 | copy(remains.begin(), remains.end(), std::back_inserter(code->args)); 267 | 268 | 269 | cout<< "after" << endl; 270 | cout << *code << endl << endl; 271 | 272 | if (!greedily) { 273 | apply_notation(code, notation, greedily); 274 | } 275 | 276 | return true; 277 | } 278 | 279 | bool 280 | check_match_notation (shared_ptr &code, const vector &config, int index) { 281 | // // length check ? 282 | 283 | cout << "Check ... " << index << endl; 284 | cout << *code << endl; 285 | cout << "with match "; for (auto c : config) cout << c << " "; 286 | 287 | int hayidx = index; 288 | 289 | for (auto c = config.begin(); c != config.end(); ++c) { 290 | if (is_notation_variable(*c)) { 291 | match_variable(code, hayidx, true); 292 | } else if (is_notation_free_variable(*c)) { 293 | if (c == prev(config.end())) { 294 | match_free_variable_greedily(code, hayidx, true); 295 | } else { 296 | match_free_variable(code, vector(c, config.end()), hayidx, true); 297 | } 298 | 299 | // NOTE: ここは、notation/gnotationにかかわらず強制的にgreedyが呼ばれるので、どうせhayidxは最後まで行ってるでしょう 300 | break; 301 | } else { 302 | match_token(code, *c, hayidx, true); 303 | } 304 | 305 | if (hayidx == -1) { 306 | cout << "Checked." << endl; 307 | return false; 308 | } 309 | } 310 | 311 | cout << "Checked." << endl; 312 | return true; 313 | } 314 | -------------------------------------------------------------------------------- /notation.h: -------------------------------------------------------------------------------- 1 | #if !defined(NOTATION_H) 2 | /* ======================================================================== 3 | $File: notation.h $ 4 | $Date: Sep 09 2019 $ 5 | $Revision: $ 6 | $Creator: Creative GP $ 7 | $Notice: (C) Copyright 2019 by Creative GP. All Rights Reserved. $ 8 | ======================================================================== */ 9 | 10 | struct Notation { 11 | vector config; 12 | shared_ptr to; 13 | }; 14 | 15 | inline bool is_notation_variable(const string& s); 16 | inline bool is_notation_free_variable(const string& s); 17 | 18 | // void replace_code(shared_ptr c, const map> &d); 19 | 20 | bool apply_notation(shared_ptr &code, const Notation& notation, bool greedily = false); 21 | // bool apply_notation_greedily(shared_ptr &code, const Notation& notation); 22 | 23 | shared_ptr match_variable(shared_ptr &c, int &index, bool checkonly = false); 24 | shared_ptr match_free_variable(shared_ptr &c, const vector &rest_config, int &index, bool checkonly = false); 25 | shared_ptr match_free_variable_greedily(shared_ptr &c, int &index, bool checkonly = false); 26 | shared_ptr match_token(shared_ptr &c, string token, int &index, bool checkonly = false); 27 | tuple>, vector>, bool> match_notation_greedily(shared_ptr &code, const vector &config); 28 | bool check_match_notation(shared_ptr &code, const vector &config, int index = 0); 29 | 30 | #define NOTATION_H 31 | #endif 32 | -------------------------------------------------------------------------------- /ocamlgen.cpp: -------------------------------------------------------------------------------- 1 | map ocamlgen::data_bind; // TODO: スコープいいの? 2 | 3 | // TODO: 名前をつける関数のトップレベルに引数が全てない場合ダメになる 4 | // (|foo| ...) ((|a b| ...))みたいなやつとか 5 | 6 | string 7 | ocamlgen::compress(const Compiled &&v) { 8 | return v.body + v.env; 9 | } 10 | void 11 | ocamlgen::paircat(Compiled &x, const Compiled &&v) { 12 | x.body += v.body; 13 | x.env += v.env; 14 | } 15 | 16 | string 17 | ocamlgen::ocaml_type_name(string s) { 18 | return "t_" + tolower(s); 19 | } 20 | 21 | string 22 | ocamlgen::print_data_structure(const TypeSignature type) { 23 | string res = ""; 24 | cout << "heyyy" << endl; 25 | cout << to_string(type) << endl; 26 | if (MATCHS(TypeProduct)(type)) { 27 | auto prod = PURES(TypeProduct)(type); 28 | for (int i = 0; i < prod->names.size(); i++) { 29 | res += prod->names[i] + " : " + to_string(prod->products[i]) + "; "; 30 | } 31 | } 32 | return res; 33 | } 34 | 35 | 36 | string 37 | ocamlgen::print_type_from(const deque &tys, const shared_ptr &lam) { 38 | string res=""; 39 | for (int i = 0; i < tys.size(); ++i) { 40 | res += ((lam == nullptr || lam->argnames.size() <= i) ? "" : lam->argnames[i]) + " "; 41 | } 42 | return res; 43 | } 44 | 45 | 46 | string 47 | ocamlgen::print_def(string name, const shared_ptr& code) { 48 | string res = ""; 49 | if (is_functional(code->type)) { 50 | // c->argsはとりあえず無視して、ここの引数は出力しないようにしてみる 51 | res += "let " + name + " " + print_type_from(PURES(TypeFn)(code->type)->from, code->l) + " = "; 52 | cout << res << endl; 53 | Compiled v1 = ocamlgen()(code->l->body); 54 | res += v1.env + v1.body + " in\n"; 55 | } else { 56 | Compiled cmp = ocamlgen()(code); 57 | res += cmp.env; 58 | res += "let " + name + " = " + cmp.body + " in\n"; 59 | } 60 | return res; 61 | } 62 | 63 | 64 | Compiled 65 | ocamlgen::operator () (const shared_ptr &c) { 66 | cout << *c <lit.val)) { 68 | assert(c->args.size() == 0); 69 | return Compiled { c->lit.val, "" }; 70 | } else if (c->lit.val == "_get") { 71 | Compiled tmp = ocamlgen()(c->args[0]); 72 | return Compiled { "("+tmp.env+tmp.body+")"+"."+c->args[1]->lit.val, "" }; 73 | } else if (c->lit.val == "type") { 74 | data_bind[c->args[0]->lit.val] = c->args[1]->rawtype; 75 | // type_constructors[c->args[0]->lit.val] = c->args[1]->l; 76 | // data_bind[c->args[0]->lit.val] = parse_data_structure(c->args[1]->l->body); 77 | // cout << to_string(data_bind[c->args[0]->lit.val]) << endl; 78 | 79 | Compiled res; 80 | res.env += "type " + ocaml_type_name(c->args[0]->lit.val) + " = { "; 81 | res.env += print_data_structure(c->args[1]->rawtype); 82 | res.env += "};;\n"; 83 | 84 | // if (MATCHS(TypeProduct)(c->args[1]->rawtype)) { 85 | // auto &product = PURES(TypeProduct)(c->args[1]->rawtype); 86 | // for (int i = 0; i < product->products.size(); i++) { 87 | // res.env += "let "+product->names[i]+" = " 88 | // } 89 | // } 90 | 91 | Compiled v1 = operator()(c->args[2]); 92 | res.env += v1.env; 93 | res.body += v1.body; 94 | return res; 95 | } else if (c->lit.val == "fuse") { 96 | Compiled res; 97 | // なんかOcaml、Emelioほど型が自由じゃないみたいなので、型ごとに別々に関数を作っておきます 98 | Guard guard = get_guard(c->args); 99 | GuardType gtype = get_guard_type(c->args); 100 | 101 | switch (gtype) { 102 | case GTYPE_COUNTABLE_FINITE: { 103 | // TODO: finiteとcountableが混ざったやつはどう処理されるんだろう 104 | const unsigned fnidx = function_call_counter++; 105 | { 106 | // NOTE: 仮のmatchlist (fun *** -> match *** withの***の部分を埋めるだけの変数名をcountable[0]から取って作る 107 | int i = 0; 108 | string matchlist = ""; 109 | for (auto a : guard.countables[0]->l->argnames) { 110 | matchlist += a; 111 | if (i == guard.countables[0]->l->argnames.size()) { 112 | matchlist += ", "; 113 | } 114 | i++; 115 | } 116 | 117 | res.body += "(fun " + matchlist + " -> match " + matchlist + " with\n"; 118 | } 119 | 120 | // NOTE: 有限定義域の関数を出力 121 | for (auto p : guard.finites) { 122 | cout << p.first << " = " << *p.second << endl; 123 | Compiled v1 = operator()(p.second); 124 | res.body += "| " + p.first + " -> " + v1.body + "\n"; 125 | } 126 | 127 | // 無限定義域の関数を出力(型が異なれば別々に) 128 | for (auto c : guard.countables) { 129 | int i = 0; 130 | string matchlist = ""; 131 | for (int j = 0; j < c->l->argnames.size(); j++) { 132 | // TODO: parametered対応 133 | assert(MATCH(string)(PURES(TypeFn)(c->type)->from[j])); 134 | const string name = c->l->argnames[j]; 135 | const string type = PURE(string)(PURES(TypeFn)(c->type)->from[j]); 136 | 137 | matchlist += ocaml_type_name(type) + " " + name; 138 | if (i == c->l->argnames.size()) { 139 | matchlist += ", "; 140 | } 141 | i++; 142 | } 143 | 144 | Compiled v1 = operator()(c->l->body); 145 | res.body += "| " + matchlist + " -> " + v1.body + "\n"; 146 | } 147 | res.body += ")\n"; 148 | } break; 149 | 150 | case GTYPE_FINITE: { 151 | } break; 152 | } 153 | return res; 154 | } else if (builtin_functions.contains(c->lit.val)) { 155 | Compiled res; 156 | res.body += c->lit.val; 157 | // 1 2 3 ) 4 5 6 として、現在のargを逆順にstackしていけば良いことが分かる 158 | for (int i = c->args.size()-1; i >= 0; i--) { 159 | argstack.push(c->args[i]); 160 | } 161 | while (!argstack.empty()) { 162 | Compiled tmp = ocamlgen()(argstack.top()); 163 | 164 | res.body += " "; 165 | argstack.pop(); 166 | res.env += tmp.env; 167 | res.body += "(" + tmp.body + ")"; 168 | } 169 | return res; 170 | } else if (c->l) { 171 | // bind > 172 | Compiled res; 173 | int i = 0; 174 | // while (!barstack.empty()) { 175 | // res.env += print_def(barstack.top(), c->args[i]); 176 | // barstack.pop(); 177 | // i++; 178 | // } 179 | for (int i = c->args.size()-1; i >= 0; i--) { 180 | argstack.push(c->args[i]); 181 | } 182 | 183 | vector free; 184 | for (int i = 0; i < c->l->argnames.size(); i++) { 185 | if (argstack.empty()) free.push_back(c->l->argnames[i]); 186 | else { 187 | cout << c->l->argnames[i] << endl; 188 | res.env += print_def(c->l->argnames[i], argstack.top()); 189 | argstack.pop(); 190 | } 191 | 192 | // func generator? 193 | // if (argstack.top()->l && arity(argstack.top()->type) - (int)argstack.top()->l->argnames.size() > 0) { 194 | // // bind[c->l->argnames[i]] = argstack.top(); 195 | // cout << c->l->argnames[i] << endl; 196 | // } else { 197 | // cout << c->l->argnames[i] << endl; 198 | // res.env += print_def(c->l->argnames[i], argstack.top()); 199 | // } 200 | } 201 | 202 | // TODO: v1.tmp と tmp の場所 203 | paircat(res, operator()(c->l->body)); 204 | 205 | if (free.size() > 0) { 206 | string tmp = "fun "; 207 | for (auto e : free) { 208 | tmp += e + " "; 209 | } 210 | tmp += "-> "; 211 | res.body = tmp + res.body; 212 | } 213 | 214 | return res; 215 | } else { 216 | Compiled res; 217 | for (int i = c->args.size()-1; i >= 0; i--) { 218 | argstack.push(c->args[i]); 219 | } 220 | // if (bind.contains(c->lit.val)) { 221 | // int pfcounter = pseudo_func_counter; 222 | // res.env += "int __pseudo_"+to_string(pfcounter)+"() {\n"; 223 | // auto cmp = operator()(bind[c->lit.val]); 224 | // res.env += cmp.env; 225 | // res.env += "return " + cmp.body + ";\n"; 226 | // res.env += "}\n"; 227 | 228 | // res.body += "__pseudo_"+to_string(pfcounter)+"()"; 229 | // pseudo_func_counter++; 230 | // } else { 231 | if (data_bind.contains(c->lit.val)) { 232 | int i = 0; 233 | auto records = PURES(TypeProduct)(data_bind[c->lit.val]); 234 | res.body += "{"; 235 | while (!argstack.empty()) { 236 | Compiled tmp = ocamlgen()(argstack.top()); 237 | 238 | argstack.pop(); 239 | res.body += " "; 240 | // res.env += tmp.env; 241 | res.body += records->names[i]+"="+tmp.body+"; "; 242 | i++; 243 | } 244 | res.body += "}"; 245 | } else { 246 | res.body += c->lit.val; 247 | while (!argstack.empty()) { 248 | Compiled tmp = ocamlgen()(argstack.top()); 249 | 250 | argstack.pop(); 251 | res.body += " "; 252 | res.env += tmp.env; 253 | res.body += "(" + tmp.body + ")"; 254 | // } 255 | } 256 | } 257 | return res; 258 | } 259 | } 260 | -------------------------------------------------------------------------------- /parse.cpp: -------------------------------------------------------------------------------- 1 | /* ======================================================================== 2 | $File: parse.cpp $ 3 | $Date: Aug 08 2019 $ 4 | $Revision: $ 5 | $Creator: Creative GP $ 6 | $Notice: (C) Copyright 2019 by Creative GP. All Rights Reserved. $ 7 | ======================================================================== */ 8 | 9 | #include "emelio.h" 10 | #include "util.h" 11 | 12 | #define NOW p.tknvals[p.idx] 13 | #define NEXT p.tknvals[p.idx+1] 14 | #define NEXT2 p.tknvals[p.idx+2] 15 | #define PASER(type, name) 16 | 17 | // {!MONAD <> e <> t <> u <> {const pair<#t, ParserFlow&> tmp1 = #u(p); #e = tmp1.first; /*p = tmp1.second;*/}!} 18 | // {!MONAD_P <> e <> t <> u <> {const pair<#t, ParserFlow&> tmp1 = #u(p); #e = &tmp1.first; /*p = tmp1.second;*/}!} 19 | // {!MONAD_F <> e <> t <> u <> {const pair<#t, ParserFlow&> tmp1 = #u(p); #e(tmp1.first); /*p = tmp1.second;*/}!} 20 | // {!SKIP <> s <> if (p.tknvals[p.idx] == #s) p.idx++; else cout << "Expects " << #s << " but " << p.tknvals[p.idx] << endl; !} 21 | // {!PARSE <> type <> name <> pair<#type, ParserFlow&> #name(ParserFlow& p) !} 22 | 23 | {!MONAD <> e <> t <> u <> {#e = #u(p); /*p = tmp1.second;*/}!} 24 | {!MONAD_P <> e <> t <> u <> {#e = &#u(p); /*p = tmp1.second;*/}!} 25 | {!MONAD_F <> e <> t <> u <> {#e(#u(p)); /*p = tmp1.second;*/}!} 26 | {!SKIP <> s <> if (p.tknvals[p.idx] == #s) p.idx++; else cout << "Expects " << #s << " but " << p.tknvals[p.idx] << endl; !} 27 | {!PARSE <> type <> name <> #type #name(ParserFlow& p) !} 28 | 29 | {- PARSE <> Literal <> literal -} 30 | { 31 | Literal l; 32 | l.val = NOW; 33 | p.idx++; 34 | 35 | return l; 36 | } 37 | 38 | {- PARSE <> unique_ptr <> argument -} 39 | ; 40 | 41 | 42 | TypeSignature named_ts(ParserFlow& p); 43 | TypeSignature type_signature(ParserFlow& p); 44 | 45 | {- PARSE <> TypeSignature <> named_ts -} 46 | { 47 | TypeSignature typesig = make_shared(TypeProduct {}); 48 | while (true) { 49 | PURES(TypeProduct)(typesig)->names.emplace_back(NOW); 50 | p.idx++; 51 | {- SKIP <> ":" -} 52 | TypeSignature tmp; 53 | {- MONAD <> tmp <> TypeSignature <> type_signature -} 54 | PURES(TypeProduct)(typesig)->products.emplace_back(tmp); 55 | if (NOW == ")") { 56 | return typesig; 57 | } 58 | } 59 | } 60 | 61 | // TODO: 関数分けてみても良いかも 62 | // TypeSignature 種類 63 | // And = Ty Ty Ty ... 64 | // Or = Ty | Ty | *Ty ... 65 | // Fn = Ty - Ty - Ty -> Ty 66 | // Ty = ( Ty ) 67 | // Ty = name1:Ty name2:Ty ... 68 | // Ty = String < Ty ... > 69 | // Ty = String 70 | {- PARSE <> TypeSignature <> type_signature -} 71 | { 72 | TypeSignature typesig; 73 | enum { PRODUCT, SUM, FUNCTION, ATOM, PATOM, PARAM } type; 74 | 75 | if (NEXT == ":") { 76 | TypeSignature tmp; 77 | {- MONAD <> tmp <> TypeSignature <> named_ts -} 78 | return tmp; 79 | } 80 | 81 | if (NOW == "(") { 82 | type = PATOM; 83 | p.idx++; 84 | } else if (NOW == "*") { 85 | p.idx++; 86 | typesig = SpecialValue{NOW}; 87 | p.idx++; 88 | return typesig; 89 | } else { 90 | typesig = NOW; 91 | p.idx++; 92 | return typesig; 93 | } 94 | 95 | { 96 | TypeSignature tmp; 97 | {- MONAD <> tmp <> TypeSignature <> type_signature -} 98 | if (NOW == ")" && type==PATOM) { 99 | {- SKIP <> ")" -} 100 | return tmp; 101 | } else if (NOW == ")") { 102 | // type == ATOM 103 | {- SKIP <> ")" -} 104 | return tmp; 105 | } else if (NOW == "|") { 106 | type = SUM; 107 | typesig = make_shared(TypeSum { {tmp} }); 108 | p.idx++; 109 | } else if (NOW == "-") { 110 | type = FUNCTION; 111 | typesig = make_shared(TypeFn { {tmp} }); 112 | p.idx++; 113 | } else if (NOW == "<") { 114 | type = PARAM; 115 | assert(MATCH(string)(tmp)); 116 | typesig = make_shared(Parametered { PURE(string)(tmp), {} }); 117 | p.idx++; 118 | } else { 119 | type = PRODUCT; 120 | typesig = make_shared(TypeProduct { {tmp} }); 121 | } 122 | } 123 | 124 | while (true) { 125 | TypeSignature tmp; 126 | 127 | bool type_fn_to = false; 128 | if (type==FUNCTION && NOW==">") { 129 | type_fn_to = true; 130 | p.idx++; 131 | } 132 | // bool special_value = false; 133 | // if (type==SUM && NOW=="*") { // 特殊値 134 | // special_value = true; 135 | // {- SKIP <> "*" -} 136 | // } 137 | 138 | {- MONAD <> tmp <> TypeSignature <> type_signature -} 139 | switch (type) { 140 | case SUM: 141 | // if (special_value) { 142 | // ASSERT(MATCH(string)(tmp), "特殊値なら文字列を指定してください " + to_string(tmp)); 143 | // PURES(TypeSum)(typesig)->add_type(SpecialValue {tmp}); 144 | // } else { 145 | PURES(TypeSum)(typesig)->add_type(tmp); 146 | // } 147 | break; 148 | case PRODUCT: PURES(TypeProduct)(typesig)->products.push_back(tmp);break; 149 | case FUNCTION: 150 | if (type_fn_to) { 151 | PURES(TypeFn)(typesig)->to = tmp; 152 | p.idx++; 153 | return typesig; 154 | } else { 155 | PURES(TypeFn)(typesig)->from.push_back(tmp); 156 | } 157 | break; 158 | case PARAM: 159 | PURES(Parametered)(typesig)->params.emplace_back(tmp); 160 | if (NOW == ">") { 161 | {- SKIP <> ">" -} 162 | return typesig; 163 | } 164 | break; 165 | } 166 | 167 | if (NOW == ")") { 168 | {- SKIP <> ")" -} 169 | return typesig; 170 | } 171 | 172 | switch (type) { 173 | case SUM: 174 | {- SKIP <> "|" -} 175 | break; 176 | case FUNCTION: 177 | {- SKIP <> "-" -} 178 | break; 179 | } 180 | } 181 | } 182 | 183 | 184 | {- PARSE <> shared_ptr <> lambda -} 185 | { 186 | shared_ptr l(new Lambda); 187 | 188 | {- SKIP <> "(" -} 189 | 190 | // 引数 191 | if (NOW == "|") { 192 | {- SKIP <> "|" -} 193 | 194 | for (; p.idx < p.tknvals.size(); p.idx++) { 195 | if (NOW == "|") { 196 | {- SKIP <> "|" -} 197 | break; 198 | } else { 199 | l->argnames.emplace_back(NOW); 200 | l->argarities.emplace_back(-1); 201 | l->argqualities.emplace_back(ArgQuality {}); 202 | 203 | if (NEXT == ":") { 204 | p.idx++; 205 | {- SKIP <> ":" -} 206 | // TypeSignature tmp; 207 | // {- MONAD <> tmp <> TypeSignature <> type_signature -} 208 | // l->argtypes.emplace_back(tmp); 209 | shared_ptr tmp; 210 | {- MONAD <> tmp <> shared_ptr <> argument -} 211 | l->cArgtypes.push_back(tmp); 212 | 213 | } else { 214 | p.idx++; 215 | } 216 | 217 | p.idx--; 218 | // codegen4用 219 | // if (NEXT == "*") { 220 | // // 再帰 221 | // {- SKIP <> NOW -} 222 | // l->argqualities.back().recursive = true; 223 | // } 224 | 225 | // // 種システム:酒の指定があればパース 226 | // if (NEXT == "(") { 227 | // {- SKIP <> NOW -} 228 | // {- SKIP <> "(" -} 229 | // l->argarities.emplace_back(stoi(NOW)); 230 | // {- SKIP <> NOW -} 231 | // } else { 232 | // l->argarities.emplace_back(-1); 233 | // } 234 | } 235 | } 236 | } 237 | 238 | {- MONAD <> l->body <> shared_ptr <> code -} 239 | 240 | {- SKIP <> ")" -} 241 | 242 | return l; 243 | } 244 | 245 | {- PARSE <> unique_ptr <> argument -} 246 | { 247 | unique_ptr c (new Code); 248 | 249 | c->src.beg = next(p.tknvals.begin(), (int) p.idx); 250 | 251 | // {- SKIP <> "(" -} 252 | 253 | if (NOW == "(") { 254 | {- MONAD <> c->l <> shared_ptr <> lambda -} 255 | } else { 256 | {- MONAD <> c->lit <> Literal <> literal -} 257 | } 258 | 259 | // {- SKIP <> ")" -} 260 | 261 | c->src.end = next(p.tknvals.begin(), p.idx); 262 | 263 | return c; 264 | } 265 | 266 | // ( add 2 3 ) 267 | // ( (|x y| x + y) 2 3 ) 268 | {- PARSE <> unique_ptr <> code -} 269 | { 270 | unique_ptr c (new Code); 271 | c->src.beg = next(p.tknvals.begin(), p.idx); 272 | 273 | // {- SKIP <> "(" -} 274 | if (NOW != ")") { 275 | if (NOW == ":") { 276 | {- SKIP <> ":" -} 277 | // 式のはじめに(適用する関数の位置に)型注釈がある場合(つまり、コンストラクタ) 278 | // NOTE: tnotationで記法を変更されている場合もあるので、ここはcodeとしてパースしておいて、reparse_types@reduction.cppでtnotationを適用しながらパースし直す 279 | {- MONAD <> c->cRawtype <> shared_ptr <> argument -} 280 | } else if (NOW == "(") { 281 | {- MONAD <> c->l <> shared_ptr <> lambda -} 282 | } else { 283 | {- MONAD <> c->lit <> Literal <> literal -} 284 | } 285 | 286 | while (p.idx < p.tknvals.size()) { 287 | if (NOW == ")" || NOW == "") { 288 | break; 289 | } 290 | 291 | // NOTE: (↑と同様) tnotationで記法を変更されている場合もあるので、ここはcodeとしてパースしておいて、reparse_types@reduction.cppでtnotationを適用しながらパースし直す 292 | if (NOW == ":") { 293 | {- SKIP <> ":" -} 294 | 295 | shared_ptr newcode = shared_ptr(new Code); 296 | // TypeSignature tmp; 297 | // {- MONAD <> tmp <> TypeSignature <> type_signature -} 298 | shared_ptr tmp; 299 | {- MONAD <> tmp <> Code <> argument -} 300 | // newcode->rawtype = tmp; 301 | // c->args.emplace_back(newcode); 302 | newcode->cRawtype = tmp; 303 | c->args.emplace_back(newcode); 304 | continue; 305 | } 306 | 307 | {- MONAD_F <> c->args.emplace_back <> shared_ptr <> argument -} 308 | } 309 | } 310 | 311 | 312 | // {- SKIP <> ")" -} 313 | c->src.end = next(p.tknvals.begin(), p.idx); 314 | 315 | return c; 316 | } 317 | -------------------------------------------------------------------------------- /pp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import sys 5 | 6 | bind = {} 7 | contentl = [] 8 | 9 | with open(sys.argv[1]) as f: 10 | content = f.readlines() 11 | 12 | for line in content: 13 | pline = line 14 | line = line.strip() 15 | try: 16 | if line[0] == '{' and line[1] == '!' and line[-2] == '!' and line[-1] == '}': 17 | tmp = line.split('<>') 18 | bind[tmp[0].strip()[2:].strip()] = { 'args':list(map(lambda x: x.strip(), tmp[1:-1])), 'body':tmp[-1][:-2].strip() } 19 | 20 | elif line[0] == '{' and line[1] == '-': 21 | tmp = line.split('<>') 22 | args = list(map(lambda x: x.strip(), tmp[1:-1])) 23 | args.append(tmp[-1][:-2].strip()) 24 | name = tmp[0].strip()[2:].strip() 25 | tmp1 = bind[name]['body'] 26 | for i in range(0, len(args)): 27 | tmp1 = tmp1.replace('#'+bind[name]['args'][i], args[i]) 28 | contentl.append('// ' + line) 29 | contentl.append(tmp1) 30 | 31 | else: 32 | contentl.append(line) 33 | 34 | except IndexError: 35 | contentl.append(pline) 36 | 37 | with open(sys.argv[1] + '.cc', 'w') as fw: 38 | fw.writelines(list(map(lambda x: x + '\n', contentl))) 39 | -------------------------------------------------------------------------------- /reduction.cpp: -------------------------------------------------------------------------------- 1 | /* ======================================================================== 2 | $File: reduction.cpp $ 3 | $Date: Aug 08 2019 $ 4 | $Revision: $ 5 | $Creator: Creative GP $ 6 | $Notice: (C) Copyright 2019 by Creative GP. All Rights Reserved. $ 7 | ======================================================================== */ 8 | 9 | #include "emelio.h" 10 | #include "util.h" 11 | #include "notation.h" 12 | 13 | int ReductionCounter = 0; 14 | 15 | {! BUILTIN_1 <> name <> shared_ptr #name_p = std::make_shared(Lambda { {"a1"}, {} }); Code c_#name {#name_p, Literal {"#name"}, deque> {}, TknvalsRegion {}}; !} 16 | {! BUILTIN_2 <> name <> shared_ptr #name_p = std::make_shared(Lambda { {"a1", "a2"}, {} }); Code c_#name {#name_p, Literal {"#name"}, deque> {}, TknvalsRegion {}}; !} 17 | 18 | {- BUILTIN_1 <> negate -} 19 | {- BUILTIN_2 <> add -} 20 | {- BUILTIN_2 <> concat -} 21 | 22 | enum NotationType { LEFT, RIGHT, TYPE }; 23 | 24 | struct ReductionFlow { 25 | map> bind = { 26 | { "add", make_shared(c_add) }, 27 | { "negate", make_shared(c_negate) }, 28 | { "concat", make_shared(c_concat) }, 29 | }; 30 | stack> argstack; 31 | // NOTE: 未計算のままshadowingするために必要 32 | map shadower; 33 | vector> notations; 34 | }; 35 | 36 | 37 | // trim from end (in place) 38 | template 39 | static inline void crtrim(std::vector &v, T target) { 40 | v.erase(std::find_if(v.rbegin(), v.rend(), [&](T ch) { 41 | return ch != target; 42 | }).base(), v.end()); 43 | } 44 | 45 | // trim from end (in place) 46 | template 47 | static inline void cltrim(std::vector &v, T target) { 48 | v.erase(v.begin(), std::find_if(v.begin(), v.end(), [&](T ch) { 49 | return ch != target; 50 | })); 51 | } 52 | 53 | // trim from end (in place) 54 | static inline void rmvparen(std::vector &v) { 55 | if (v.size() == 0) return; 56 | 57 | if (v.front() == "(") v.erase(v.begin()); 58 | if (v.back() == ")") v.pop_back(); 59 | } 60 | static inline void rmvparen(TknvalsRegion &r) { 61 | if (distance(r.beg, r.end) == 0) return; 62 | 63 | if (*r.beg == "(") r.beg++; 64 | if (*prev(r.end) == ")") r.end--; 65 | } 66 | 67 | pair read_int_litcode(const shared_ptr c) { 68 | if (!is_computed(c)) { 69 | if (c) { 70 | cout << "[ERROR] (TODO:カインド) 次のようなCodeをIntリテラルとして読もうとしました" << endl; 71 | cout << *c << endl; 72 | } 73 | return make_pair(0, false); 74 | } 75 | 76 | return make_pair(stoi(c->lit.val), true); 77 | } 78 | 79 | pair read_string_litcode(const shared_ptr c) { 80 | if (!is_computed(c)) { 81 | if (c) { 82 | cout << "[ERROR] (TODO:カインド) 次のようなCodeをStringリテラルとして読もうとしました" << endl; 83 | cout << *c << endl; 84 | } 85 | return make_pair("", false); 86 | } 87 | 88 | return make_pair(c->lit.val, true); 89 | } 90 | 91 | // unique_ptr make_procedural_code(shared_ptr from, shared_ptr to) { 92 | // return make_unique(Code { 93 | // make_shared(Lambda{{"_"}, to}), 94 | // "", 95 | // { from }, 96 | // TknvalsRegion { from.src.beg, to.src.end } // TODO: これ大丈夫? 97 | // }); 98 | // } 99 | 100 | Code make_int_litcode(int n) { 101 | return Code {0, Literal { to_string(n) }}; 102 | } 103 | 104 | Code make_string_litcode(string n) { 105 | return Code {0, Literal { n }}; 106 | } 107 | 108 | shared_ptr ref(string name, ReductionFlow &rf) { 109 | if (CONTAINS(rf.shadower, name)) { 110 | string probe = rf.bind[rf.shadower[name]]->lit.val; 111 | if (CONTAINS(rf.shadower, probe)) { 112 | return rf.bind[probe]; 113 | } 114 | // while (CONTAINS(rf.shadower, probe)) { 115 | // name = probe; 116 | // probe = rf.bind[probe]->lit.val; 117 | // } 118 | 119 | return rf.bind[rf.shadower[name]]; 120 | } 121 | return rf.bind[name]; 122 | } 123 | #define ref(a) ref(a,rf) 124 | 125 | 126 | bool apply_all_notations(shared_ptr &code, 127 | const vector> ¬ations, 128 | bool rv = false 129 | ) 130 | { 131 | bool reapply = false; 132 | { 133 | auto n = notations.begin(); 134 | while (n != notations.end()) { 135 | switch (n->second) { 136 | case RIGHT: 137 | reapply = apply_notation(code, n->first, true); 138 | break; 139 | case LEFT: 140 | reapply = apply_notation(code, n->first); 141 | break; 142 | case TYPE: 143 | if (code->l) { 144 | for (auto &e : code->l->cArgtypes) { 145 | reapply = apply_notation(e, n->first); 146 | auto tmp = e->plain_string(); 147 | cout << join(tmp) << endl; 148 | } 149 | } 150 | if (code->cRawtype) { 151 | cout << "hewwo " << *code->cRawtype->l->body; 152 | reapply = apply_notation(code->cRawtype->l->body, n->first); 153 | auto tmp = code->cRawtype->plain_string(); 154 | cout << join(tmp) << endl; 155 | } 156 | break; 157 | } 158 | n++; 159 | } 160 | } 161 | 162 | if (reapply) apply_all_notations(code, notations, true); 163 | return rv; 164 | } 165 | 166 | 167 | void resolve_fusion(shared_ptr &code, const ReductionFlow &rf) { 168 | stack> _argstack = rf.argstack; 169 | // 0, 1を残してargがあるなら降順に詰めていく 170 | // for (auto arg = prev(code->args.end()); 171 | // std::distance(code->args.begin(), arg) > 1; 172 | // arg--) 173 | // { 174 | // _argstack.push(*arg); 175 | // } 176 | 177 | int go1 = 0, go2 = 0; 178 | bool go1_proh = false, go2_proh = false; 179 | for (int i = 0; i < code->args[0]->l->argnames.size(); ++i) { 180 | string argname1 = code->args[0]->l->argnames[i]; 181 | string argname2 = code->args[1]->l->argnames[i]; 182 | 183 | if (is_number(argname1)) { 184 | if (argname1 == _argstack.top()->lit.val) 185 | go1++; 186 | else 187 | go1_proh = true; 188 | } 189 | if (is_number(argname2)) { 190 | if (argname2 == _argstack.top()->lit.val) 191 | go2++; 192 | else 193 | go2_proh = true; 194 | } 195 | } 196 | 197 | if (go1_proh && go2_proh) { 198 | cerr << "[ERROR] fusionの解決が出来ません" << endl; 199 | cerr << *code << endl; 200 | } else if (!go1_proh && !go2_proh) { 201 | if (go1 == go2) { 202 | cerr << "[ERROR] fusionの解決が出来ません" << endl; 203 | cerr << *code << endl; 204 | } else if (go1 < go2) { 205 | code = code->args[1]; 206 | } else if (go2 < go1) { 207 | code = code->args[0]; 208 | } 209 | } 210 | else if (!go1_proh) code = code->args[0]; 211 | else if (!go2_proh) code = code->args[1]; 212 | } 213 | 214 | 215 | ReductionFlow S_reduction(shared_ptr code, ReductionFlow rf) { 216 | shared_ptr given_p = code; 217 | 218 | while ( true ) { 219 | continue_reduction_loop: 220 | 221 | cout << "Reductioning ... " << endl; 222 | cout << *code << endl << endl; 223 | ReductionCounter++; 224 | 225 | // Apply notations 226 | apply_all_notations(code, rf.notations); 227 | // { 228 | // auto n = rf.notations.end(); 229 | // while (n != rf.notations.begin()) { 230 | // n--; 231 | // apply_notation(code, *n); 232 | // } 233 | // } 234 | 235 | if (!code->l) { 236 | if (is_literal(code->lit.val)) { 237 | *given_p = *code; 238 | return rf; 239 | } else { 240 | if (CONTAINS(rf.bind, code->lit.val)) { 241 | // NOTE: while内refでの代入時にちゃんと切り替わるため 242 | Code res = *ref(code->lit.val); 243 | while (!res.l) { 244 | if (is_literal(res.lit.val)) { 245 | *given_p = res; 246 | return rf; 247 | } 248 | 249 | // NOTE: つまり前の階層と同じようなことをする 250 | // ここのcontinueは例えばfuseとかはbindにないので、continueすることで再ロードできる 251 | // TODO: fuseの場合はこれじゃ駄目だけど、とりあえず一貫性を保っておく 252 | if (!CONTAINS(rf.bind, res.lit.val)) { 253 | *given_p = res; 254 | return rf; 255 | } 256 | res = *ref(res.lit.val); // DEBUG: check its counter ここでは消されないはず 257 | } 258 | 259 | // deep copy res's lambda 260 | if (res.l) { 261 | if (!code->l) 262 | code->l = shared_ptr(new Lambda); 263 | code->l->deep_copy_from(*res.l); 264 | } else res.l = shared_ptr(nullptr); 265 | code->lit = res.lit; 266 | for (const shared_ptr &arg : res.args) { 267 | code->args.push_back(make_shared(*arg)); 268 | } 269 | 270 | // copy(res.args.begin(), res.args.begin(), back_inserter(code->args)); //? 271 | 272 | } else if (code->lit.val == "notation" || code->lit.val == "gnotation" || code->lit.val == "totation") { 273 | // 表記の書き換え 274 | // 書き換え規則を取得して、第三引数のコードをソース情報から書き換える。 275 | // 再度パースしてできたCodeのreductionを今回の結果とする 276 | // NOTE: 実行順序は関係あるの?まとめてやったら?何度もパースしたくないし 277 | if (code->args.size() != 3) { 278 | cout << "[ERROR] notationの引数の数が違います"; 279 | *given_p = make_int_litcode(0); 280 | return rf; // NOTE: エラー値として 281 | } 282 | 283 | 284 | // TODO: validity check of configuration (splash off something like 'A B ; C') 285 | 286 | 287 | // vector to = vector(code->args[1]->src.beg, code->args[1]->src.end); 288 | // rmvparen(to); 289 | shared_ptr to_code = make_shared(*code->args[1]); 290 | // { 291 | 292 | // ParserFlow pf = {to, 0}; 293 | // to_code = ::code(pf); 294 | // } 295 | 296 | vector conf = code->args[0]->plain_string(); 297 | // rmvparen(conf); 298 | 299 | if (code->lit.val == "notation") { 300 | rf.notations.push_back(make_pair(Notation {conf, to_code}, LEFT)); 301 | } else if (code->lit.val == "gnotation") { 302 | rf.notations.push_back(make_pair(Notation {conf, to_code}, RIGHT)); 303 | } else if (code->lit.val == "totation") { 304 | rf.notations.push_back(make_pair(Notation {conf, to_code}, TYPE)); 305 | } 306 | 307 | // DEBUG 308 | *given_p = *code->args[2]; 309 | return S_reduction(given_p, rf); 310 | } else if (code->lit.val == "add") { 311 | code->l.reset(add_p.get()); 312 | } else if (code->lit.val == "negate") { 313 | code->l.reset(negate_p.get()); 314 | } else if (code->lit.val == "concat") { 315 | code->l.reset(concat_p.get()); 316 | } else if (code->lit.val == "fuse") { 317 | // // fusionの解決 318 | // // fusionされている関数の引数の数は一緒であるはずなので、 319 | // // どちらの関数か決定できれば解決される 320 | // if (rf.argstack.size() >= code->args[0]->l->argnames.size()) { 321 | // resolve_fusion(code, rf); 322 | // continue; 323 | // } 324 | // else 325 | // { 326 | // *given_p = *code; 327 | // return rf; 328 | // } 329 | } else if (code->lit.val == "nothing") { 330 | 331 | } else { 332 | cout << "[ERROR] '" << code->lit.val << "'というような名前は見つかりません" << endl; 333 | *given_p = *code; 334 | return rf; 335 | } 336 | } 337 | } 338 | 339 | ReductionFlow oldrf = rf; 340 | oldrf.argstack = stack>(); 341 | for (int i = code->args.size()-1; i >= 0; i--) { 342 | S_reduction(code->args[i], oldrf); // TODO: ここのrfいらない? 343 | rf.argstack.push(code->args[i]); 344 | } 345 | 346 | // if (code->lit.val == "fuse" && 347 | // (rf.argstack.size()+maxzero((int)code->args.size()-2)) >= code->args[0]->l->argnames.size()) 348 | // { 349 | // resolve_fusion(code, rf); 350 | // continue; 351 | // } 352 | 353 | for (string argname : code->l->argnames) { 354 | if (rf.argstack.empty()) { 355 | // TODO: 部分適用 ? 356 | cout << "[ERROR] 引数の数が足りません" << endl; 357 | return rf; 358 | } else { 359 | if (argname != "_") { 360 | rf.bind[argname] = rf.argstack.top(); 361 | } 362 | rf.argstack.pop(); 363 | } 364 | } 365 | 366 | 367 | if (code->lit.val == "add") { 368 | pair tmp1 = read_int_litcode(ref("a1")); 369 | pair tmp2 = read_int_litcode(ref("a2")); 370 | 371 | 372 | if (tmp1.second && tmp2.second) { 373 | cout << "add " << tmp1.first << " " << tmp2.first << endl << endl; 374 | *given_p = make_int_litcode(tmp1.first + tmp2.first); 375 | return rf; 376 | } else { 377 | *given_p = *code; 378 | return rf; 379 | } 380 | } else if (code->lit.val == "negate") { 381 | pair tmp1 = read_int_litcode(ref("a1")); 382 | 383 | if (tmp1.second) { 384 | cout << "negate " << tmp1.first << endl << endl; 385 | *given_p = make_int_litcode(-tmp1.first); 386 | return rf; 387 | } else { 388 | *given_p = *code; 389 | return rf; 390 | } 391 | } else if (code->lit.val == "concat") { 392 | pair tmp1 = read_string_litcode(ref("a1")); 393 | pair tmp2 = read_string_litcode(ref("a2")); 394 | 395 | if (tmp1.second && tmp2.second) { 396 | cout << "concat " << tmp1.first << " " << tmp2.first << endl << endl; 397 | *given_p = make_string_litcode(tmp1.first + tmp2.first); 398 | return rf; 399 | } else { 400 | *given_p = *code; 401 | return rf; 402 | } 403 | } else if (code->lit.val == "fuse") { 404 | // TODO: a1 とか a2 とか必要? 405 | shared_ptr tmp1 = ref("a1"); 406 | shared_ptr tmp2 = ref("a2"); 407 | 408 | cout << "fuse " << tmp1 << " " << tmp2 << endl << endl; 409 | 410 | 411 | 412 | if (// is_fusable(tmp1) && is_fusable(tmp2) && 413 | tmp1->l->argnames.size() == tmp2->l->argnames.size() ) { 414 | *given_p = *code; 415 | return rf; 416 | } else { 417 | cerr << "[ERROR] fusableじゃないのでどうにかしよう" << endl; 418 | *given_p = *code; 419 | return rf; 420 | } 421 | } 422 | 423 | if (!code->l->body->l && code->l->body->lit.val == "") { 424 | *given_p = *code; 425 | return rf; 426 | } 427 | 428 | code = code->l->body; // DEBUG! 429 | } 430 | return rf; 431 | } 432 | 433 | void reduction(shared_ptr code, bool silent) { 434 | auto back = cout.rdbuf(); 435 | if (silent) { 436 | cout.rdbuf(NULL); 437 | } 438 | 439 | ReductionFlow rf = {}; 440 | S_reduction(code, rf); 441 | 442 | cout << ReductionCounter << " reductions." << endl; 443 | 444 | if (silent) { 445 | cout.rdbuf(back); 446 | } 447 | } 448 | 449 | 450 | ReductionFlow extract_all_notations(shared_ptr &code, ReductionFlow rf) { 451 | cout << *code << endl << endl; 452 | 453 | // これはまだ続くのかどうか TODO 一貫性 454 | // if (check_all_notations(code, rf.notations, rf.greedy_notations)) return rf; 455 | 456 | 457 | // Apply notations 458 | apply_all_notations(code, rf.notations); 459 | 460 | if (!code->l) { 461 | if (is_literal(code->lit.val)) { 462 | // *given_p = *code; 463 | return rf; 464 | } else { 465 | if (code->lit.val == "notation" || code->lit.val == "gnotation" || code->lit.val == "totation") { 466 | // 表記の書き換え 467 | // 書き換え規則を取得して、第三引数のコードをソース情報から書き換える。 468 | // 再度パースしてできたCodeのreductionを今回の結果とする 469 | // NOTE: 実行順序は関係あるの?まとめてやったら?何度もパースしたくないし 470 | if (code->args.size() != 3) { 471 | cout << "[ERROR] notationの引数の数が違います"; 472 | return rf; // NOTE: エラー値として 473 | } 474 | 475 | 476 | // TODO: validity check of configuration (splash off something like 'A B ; C') 477 | 478 | 479 | // vector to = vector(code->args[1]->src.beg, code->args[1]->src.end); 480 | // rmvparen(to); 481 | shared_ptr to_code = make_shared(*code->args[1]); 482 | // { 483 | 484 | // ParserFlow pf = {to, 0}; 485 | // to_code = ::code(pf); 486 | // } 487 | 488 | vector conf = code->args[0]->plain_string(); 489 | for (auto e : conf) cout << e << " "; 490 | cout << endl; 491 | // rmvparen(conf); 492 | 493 | if (code->lit.val == "notation") { 494 | rf.notations.push_back(make_pair(Notation {conf, to_code}, LEFT)); 495 | } else if (code->lit.val == "gnotation") { 496 | rf.notations.push_back(make_pair(Notation {conf, to_code}, RIGHT)); 497 | } else if (code->lit.val == "totation") { 498 | rf.notations.push_back(make_pair(Notation {conf, to_code}, TYPE)); 499 | } 500 | 501 | cout << "There now notations like: \n"; 502 | for (auto notation : rf.notations) { 503 | for (auto i_notval = notation.first.config.begin(); 504 | i_notval != notation.first.config.end(); 505 | i_notval++) 506 | cout << *i_notval << " "; 507 | cout << endl; 508 | } 509 | cout << endl; 510 | 511 | 512 | // DEBUG 513 | // TODO: ここで前のやつと繋げないといけなさそう 514 | // 先に引数の方を展開して、手続き結合をして返す 515 | extract_all_notations(code->args[2], rf); 516 | code = code->args[2]; 517 | // *code = *code->args[2]; 518 | return rf; 519 | } 520 | 521 | for (int i = code->args.size()-1; i >= 0; i--) { 522 | extract_all_notations(code->args[i], rf); 523 | } 524 | 525 | return rf; 526 | } 527 | } 528 | 529 | for (int i = code->args.size()-1; i >= 0; i--) { 530 | // if (check_all_notations(code->args[i], rf.notations, rf.greedy_notations)) { 531 | extract_all_notations(code->args[i], rf); 532 | // } 533 | } 534 | 535 | if (!code->l->body->l && code->l->body->lit.val == "") { 536 | // *given_p = *code; 537 | return rf; 538 | } 539 | 540 | extract_all_notations(code->l->body, rf); 541 | return rf; 542 | } 543 | 544 | 545 | void extract_all_notations(shared_ptr &code, bool silent) { 546 | auto back = cout.rdbuf(); 547 | if (silent) { 548 | cout.rdbuf(NULL); 549 | } 550 | 551 | ReductionFlow rf = {}; 552 | extract_all_notations(code, rf); 553 | 554 | if (silent) { 555 | cout.rdbuf(back); 556 | } 557 | } 558 | 559 | void reparse_types(shared_ptr &code, Tokenizer &tkn) { 560 | if (code->cRawtype) { 561 | reparse_types(code->cRawtype, tkn); 562 | 563 | tkn.clear(); 564 | tkn.tokenize("("+join(code->cRawtype->plain_string())+")"); 565 | cout << *code->cRawtype << endl; 566 | cout << join(code->cRawtype->plain_string()) << endl; 567 | ParserFlow pf = {tkn.tokenvals, 0}; 568 | code->rawtype = type_signature(pf); 569 | } 570 | if (code->l) { 571 | for (auto e : code->l->cArgtypes) { 572 | reparse_types(e, tkn); 573 | 574 | cout << *e << endl; 575 | cout << join(e->plain_string()) << endl; 576 | 577 | tkn.clear(); 578 | tkn.tokenize("("+join(e->plain_string())+")"); 579 | ParserFlow pf = {tkn.tokenvals, 0}; 580 | code->l->argtypes.emplace_back(type_signature(pf)); 581 | cout << to_string(code->l->argtypes.back()) << endl; 582 | } 583 | if (code->l->body) reparse_types(code->l->body, tkn); 584 | } 585 | 586 | for (auto e : code->args) reparse_types(e, tkn); 587 | } 588 | -------------------------------------------------------------------------------- /test.em: -------------------------------------------------------------------------------- 1 | tnotation ([A]) 2 | type List :((car:int cdr:List)|*Nil) ( 3 | (|foo:(List->int)| 4 | foo (:List 3 (:List Nil)) 5 | ) (fuse (|x:(car:int cdr:List)| _get x car) (|x:(*Nil)| 0)) 6 | ) 7 | 8 | 9 | -------------------------------------------------------------------------------- /testcases/dollar.em: -------------------------------------------------------------------------------- 1 | Dollar($) Notation 2 | -7 3 | (gnotation (As $ Bs) (As Bs) ( 4 | add 3 $ add 2 $ negate $ add 4 8 5 | )) -------------------------------------------------------------------------------- /testcases/imperative_semantics.em: -------------------------------------------------------------------------------- 1 | Imperative Semantics (; Notaion) 2 | 17 3 | (notation (As ; Bs) ((|x| Bs) (As)) ( 4 | add 5 7; 5 | add 8 3; 6 | add 2 ((add 4 6; add 7) 8) 7 | )) 8 | -------------------------------------------------------------------------------- /testcases/let.em: -------------------------------------------------------------------------------- 1 | Let Notation (;もあるよ) 2 | 5 3 | (gnotation (let A = As ; Bs) ((|A| Bs) (As)) ( 4 | (gnotation (As ; Bs) ((|x| Bs) (As)) ( 5 | let subtract = (|a b| add a (negate b)); 6 | add 2 3; 7 | let c = subtract 2 4; 8 | let d = add 7 c; 9 | add c 4; 10 | d 11 | )) 12 | )) -------------------------------------------------------------------------------- /testcases/meta-notation.em: -------------------------------------------------------------------------------- 1 | Meta Notation 2 | -17 3 | (gnotation (notation As = Bs ; Cs) (notation As Bs Cs) ( 4 | (gnotation (let A = Bs ; Cs) ((|A| Cs) (Bs)) ( 5 | (gnotation (As ; Bs) ((|x| Bs) (As)) ( 6 | notation As $ Bs = As Bs; 7 | let subtract = (|a b| 8 | add a $ negate b 9 | ); 10 | 11 | notation As + Bs = add As Bs; 12 | notation As - Bs = subtract As Bs; 13 | 14 | let u = 3 - 7 + 2; 15 | 16 | 3 - 5 + 2 - 8 - 7 + u 17 | )) 18 | )) 19 | )) 20 | -------------------------------------------------------------------------------- /testcases/testcases.em: -------------------------------------------------------------------------------- 1 | 計算 2 | add 2 3 3 | 5 4 | 5 | 全体が関数 6 | (add 2 3) 7 | 5 8 | 9 | 冗長な関数 10 | add (2) (3) 11 | 5 12 | 13 | 冗長すぎ 14 | add ((2)) (((3))) 15 | 5 16 | 17 | 全体が冗長すぎ 18 | ((((add 2 3)))) 19 | 5 20 | 21 | 冗長な関数 + 全体が関数 22 | (add (2) (3)) 23 | 5 24 | 25 | 即時関数 26 | (|x| add x 2) 3 27 | 5 28 | 29 | 即時関数 + 全体関数 30 | ((|x| add x 2) 3) 31 | 5 32 | 33 | 引数に冗長な関数 34 | (|x| add (x) 2) 3 35 | 5 36 | 37 | 引数に冗長すぎな関数 38 | (|x| add ((x)) 2) 3 39 | 5 40 | 41 | 関数のボディが冗長な関数 42 | (|x| (add x 2)) 3 43 | 5 44 | 45 | 関数のボディが冗長 + 全体関数 46 | ((|x| (add x 2)) 3) 47 | 5 48 | 49 | 全部冗長 50 | (((|x| ((add ((x)) (2)))) ((3)))) 51 | 5 52 | 53 | 複数値関数 54 | (|x y| add x y) 2 3 55 | 5 56 | 57 | 全体 + 複数 58 | ((|x y| add x y) 2 3) 59 | 5 60 | 61 | 多重関数 62 | (|x1 y1 z1 w1| add w1 ((|x2 y2 z2| add z2 ((|x3 y3| add x3 y3) x2 y2)) x1 y1 z1)) 10 30 24 1 63 | 65 64 | 65 | シャドウ 66 | (|x y z w| add w ((|x y z| add z ((|x y| add x y) x y)) x y z)) 10 30 24 1 67 | 65 68 | 69 | 引数に関数評価が必要 70 | (|x y| (|u| add u 3) x) ((|a| 1) 3) 5 71 | 4 72 | 73 | 引数と名前の衝突 74 | (|x y| add x y) ((|x| negate x) 3) ((|x| x) 5) 75 | 2 76 | 77 | 引数関数の複数回適用 78 | (|subtract| subtract (subtract 2 7) 8) (|a b| add a (negate b)) 79 | -13 80 | 81 | 空引数 82 | (|f| f 1 2) ((|x _ y| add x y) 3) 83 | 5 84 | -------------------------------------------------------------------------------- /utest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | TIMEFMT='%J %U user %S system %P cpu %*E total'$'\n'\ 4 | 'avg shared (code): %X KB'$'\n'\ 5 | 'avg unshared (data/stack): %D KB'$'\n'\ 6 | 'total (sum): %K KB'$'\n'\ 7 | 'max memory: %M MB'$'\n'\ 8 | 'page faults from disk: %F'$'\n'\ 9 | 'other page faults: %R' 10 | 11 | TESTCASES='testcases/testcases.em' 12 | TESTCASES_DIRECTORY='testcases' 13 | 14 | line_count=`cat $TESTCASES | wc -l` 15 | 16 | if [ "$1" = "v" ] ; then 17 | echo "wwwwwww TESTING wwwwwwww" 18 | fi 19 | 20 | # one liner 21 | 22 | for i in $(seq 0 `expr $line_count / 4`) 23 | do 24 | lineI1=`expr $i \* 4 + 1` 25 | lineI2=`expr $i \* 4 + 2` 26 | lineI3=`expr $i \* 4 + 3` 27 | lineI4=`expr $i \* 4 + 4` 28 | 29 | title=`sed -n ${lineI1}p $TESTCASES` 30 | code=`sed -n ${lineI2}p $TESTCASES` 31 | ans=`sed -n ${lineI3}p $TESTCASES` 32 | blank=`sed -n ${lineI4}p $TESTCASES` 33 | 34 | if [ "$1" = "v" ] ; then 35 | echo $title 36 | echo $code 37 | else 38 | echo "Testing $code --- " 39 | fi 40 | 41 | res=`./emelio "$code"` 42 | if [ "$res" = "$ans" ] ; then 43 | echo -e "\e[1;32mPassed.\e[0m" 44 | 45 | if [ "$1" = "v" ] ; then 46 | time ./emelio "$code" 47 | echo "" 48 | fi 49 | else 50 | echo -e "\e[1;31mError!\e[0m " 51 | echo "Expected '$ans', but '$res'."; 52 | echo $title 53 | fi 54 | done 55 | 56 | # file 57 | 58 | for file in $TESTCASES_DIRECTORY/* 59 | do 60 | if [ `basename $file` = "testcases.em" ] ; then 61 | continue 62 | fi 63 | 64 | title=`sed -n 1p ${file}` 65 | ans=`sed -n 2p ${file}` 66 | code=`sed -n '3,$p' ${file}` 67 | 68 | 69 | if [ "$1" = "v" ] ; then 70 | echo "$title ************************************************************" 71 | echo "$code" 72 | echo "********************************************************************" 73 | else 74 | echo $title 75 | fi 76 | 77 | res=`./emelio a a a <<< $code` 78 | if [ "$res" = "$ans" ] ; then 79 | echo -e "\e[1;32mPassed.\e[0m" 80 | 81 | if [ "$1" = "v" ] ; then 82 | time ./emelio a a <<< $code 83 | echo "" 84 | fi 85 | else 86 | echo -e "\e[1;31mError!\e[0m " 87 | echo "Expected '$ans', but '$res'."; 88 | echo $title 89 | echo $code 90 | fi 91 | 92 | done 93 | 94 | -------------------------------------------------------------------------------- /util.cpp: -------------------------------------------------------------------------------- 1 | /* ======================================================================== 2 | $File: util.cpp $ 3 | $Date: Aug 08 2019 $ 4 | $Revision: $ 5 | $Creator: Creative GP $ 6 | $Notice: (C) Copyright 2019 by Creative GP. All Rights Reserved. $ 7 | ======================================================================== */ 8 | /* 9 | util.hで定義されている、標準ライブラリデータ構造に対するユーティリィー関数をここに書いていく 10 | */ 11 | 12 | #include "util.h" 13 | #include 14 | 15 | 16 | // bool is_fusable(const shared_ptr &c) { 17 | // return c->args.size() == 0; 18 | // } 19 | 20 | //Code::~Code() { if (l) delete l; } 21 | 22 | void ASSERT(bool glass, std::string msg) { 23 | if (!glass) { 24 | cout << "Error: " + msg << endl; 25 | assert(glass); 26 | } 27 | } 28 | 29 | std::string join(const std::vector& v, const char* delim) { 30 | std::string s; 31 | if (!v.empty()) { 32 | s += v[0]; 33 | for (decltype(v.size()) i = 1, c = v.size(); i < c; ++i) { 34 | if (delim) s += delim; 35 | s += v[i]; 36 | } 37 | } 38 | return s; 39 | } 40 | 41 | 42 | bool is_number(const std::string& s) 43 | { 44 | int a; 45 | try { 46 | int a = stoi(s); 47 | } catch (invalid_argument& e) { 48 | return false; 49 | } 50 | return true; 51 | } 52 | 53 | bool is_string_literal(const std::string& s) { 54 | return s.front() == '"' && s.back() == '"'; 55 | } 56 | 57 | bool is_literal(const std::string& s) { 58 | return is_number(s) || is_string_literal(s); 59 | } 60 | 61 | bool is_builtin(const std::string& s) { 62 | return s == "add" || s == "negate" || s == "concat"; 63 | } 64 | 65 | 66 | vector split(const string &s, char delim) { 67 | vector elems; 68 | string item; 69 | for (char ch: s) { 70 | if (ch == delim) { 71 | if (!item.empty()) 72 | elems.push_back(item); 73 | item.clear(); 74 | } 75 | else { 76 | item += ch; 77 | } 78 | } 79 | if (!item.empty()) 80 | elems.push_back(item); 81 | return elems; 82 | } 83 | 84 | template 85 | std::basic_string operator * 86 | (const std::basic_string s, size_t n) 87 | { 88 | std::basic_string tmp = s; 89 | for (size_t i = 0; i < n; ++i) 90 | { 91 | tmp += s; 92 | } 93 | return tmp; 94 | } 95 | 96 | template 97 | std::basic_string operator * 98 | (size_t n, const std::basic_string& s) 99 | { 100 | return s * n; 101 | } 102 | 103 | 104 | std::string random_string( size_t length ) 105 | { 106 | auto randchar = []() -> char 107 | { 108 | const char charset[] = 109 | "0123456789" 110 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 111 | "abcdefghijklmnopqrstuvwxyz"; 112 | const size_t max_index = (sizeof(charset) - 1); 113 | return charset[ rand() % max_index ]; 114 | }; 115 | std::string str(length,0); 116 | std::generate_n( str.begin(), length, randchar ); 117 | return str; 118 | } 119 | 120 | std::string random_sane_string( size_t length ) 121 | { 122 | auto randchar = []() -> char 123 | { 124 | const char charset[] = 125 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 126 | "abcdefghijklmnopqrstuvwxyz"; 127 | const size_t max_index = (sizeof(charset) - 1); 128 | return charset[ rand() % max_index ]; 129 | }; 130 | std::string str(length,0); 131 | std::generate_n( str.begin(), length, randchar ); 132 | return str; 133 | } 134 | 135 | std::string random_saneupper_string( size_t length ) 136 | { 137 | auto randchar = []() -> char 138 | { 139 | const char charset[] = 140 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 141 | const size_t max_index = (sizeof(charset) - 1); 142 | return charset[ rand() % max_index ]; 143 | }; 144 | std::string str(length,0); 145 | std::generate_n( str.begin(), length, randchar ); 146 | return str; 147 | } 148 | 149 | char asciitolower(char in) { 150 | if (in <= 'Z' && in >= 'A') 151 | return in - ('Z' - 'z'); 152 | return in; 153 | } 154 | 155 | std::string tolower(std::string data) { 156 | std::string res = data; 157 | std::transform(res.begin(), res.end(), res.begin(), asciitolower); 158 | return res; 159 | } 160 | 161 | 162 | bool is_all_upper(string &s) { 163 | return accumulate(s.begin(), s.end(), true, [](bool acc, char i) { 164 | return acc && isupper(i); 165 | }); 166 | } 167 | 168 | int maxzero(int n) { 169 | return std::max(0, n); 170 | } 171 | 172 | template 173 | std::ostream& operator<<(std::ostream& stream, const std::map& m) { 174 | stream << "{"; 175 | for (const auto &[k, v]: m) { 176 | stream << k << " => " << v << ", "; 177 | } 178 | stream << "}"; 179 | return stream; 180 | } 181 | -------------------------------------------------------------------------------- /util.h: -------------------------------------------------------------------------------- 1 | #if !defined(UTIL_H) 2 | /* ======================================================================== 3 | $File: util.h $ 4 | $Date: Aug 08 2019 $ 5 | $Revision: $ 6 | $Creator: Creative GP $ 7 | $Notice: (C) Copyright 2019 by Creative GP. All Rights Reserved. $ 8 | ======================================================================== */ 9 | 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | using namespace std; 23 | 24 | void ASSERT(bool glass, std::string msg); 25 | 26 | vector split(const string &s, char delim); 27 | std::string join(const std::vector& v, const char* delim = 0); 28 | 29 | template 30 | std::basic_string operator * 31 | (const std::basic_string s, size_t n); 32 | 33 | template 34 | std::basic_string operator * 35 | (size_t n, const std::basic_string& s); 36 | 37 | 38 | template 39 | std::ostream& operator<<(std::ostream& stream, const std::map& m); 40 | 41 | bool is_number(const std::string& s); 42 | bool is_string_literal(const std::string& s); 43 | bool is_literal(const std::string& s); 44 | bool is_builtin(const std::string& s); 45 | char asciitolower(char in); 46 | std::string tolower(std::string); 47 | 48 | std::string random_string( size_t length ); 49 | std::string random_sane_string( size_t length ); 50 | std::string random_saneupper_string( size_t length ); 51 | 52 | bool is_all_upper(string &s); 53 | 54 | int maxzero(int n); 55 | 56 | #define UTIL_H 57 | #endif 58 | --------------------------------------------------------------------------------