├── Makefile ├── README.md ├── bc2bef.cc ├── beflisp.bef ├── beflisp2d.bef ├── befunge.cc ├── eval.l ├── evalify.rb ├── fizzbuzz.l ├── fizzbuzz.l2d ├── libef.h ├── lisp.c ├── lisp2d.c ├── lisp_common.c ├── purelisp.rb ├── sort.l ├── test.l ├── test.rb ├── test ├── cmp_eq.bef ├── cmp_eq.c ├── cmp_eq_1.in ├── cmp_eq_2.in ├── cmp_eq_3.in ├── cmp_ge.bef ├── cmp_ge.c ├── cmp_ge_1.in ├── cmp_ge_2.in ├── cmp_ge_3.in ├── cmp_gt.bef ├── cmp_gt.c ├── cmp_gt_1.in ├── cmp_gt_2.in ├── cmp_gt_3.in ├── cmp_le.bef ├── cmp_le.c ├── cmp_le_1.in ├── cmp_le_2.in ├── cmp_le_3.in ├── cmp_lt.bef ├── cmp_lt.c ├── cmp_lt_1.in ├── cmp_lt_2.in ├── cmp_lt_3.in ├── cmp_ne.bef ├── cmp_ne.c ├── cmp_ne_1.in ├── cmp_ne_2.in ├── cmp_ne_3.in ├── fizzbuzz.bef ├── fizzbuzz.c ├── func.bef ├── func.c ├── func.in ├── global.bef ├── global.c ├── hello.c ├── loop.bef ├── loop.c ├── loop.in ├── malloc.bef ├── malloc.c ├── nullptr.bef ├── nullptr.c ├── print_int.bef ├── print_int.c ├── puts.bef ├── puts.c ├── struct.bef ├── struct.c ├── struct.in ├── swapcase.bef ├── swapcase.c ├── swapcase_1.in ├── swapcase_2.in ├── swapcase_3.in ├── swapcase_4.in ├── swapcase_5.in ├── swapcase_6.in ├── switch_op.bef ├── switch_op.c └── switch_op.in └── test_bef.rb /Makefile: -------------------------------------------------------------------------------- 1 | CXX:=g++ 2 | CXXFLAGS:=-g -std=gnu++11 -Wall -W -Werror 3 | 4 | CFLAGS:=-I. -fno-builtin -m32 5 | CFLAGS+=-Wall -W -Werror -Wno-unused-function 6 | CLANGFLAGS:=$(CFLAGS) -Wno-incompatible-library-redeclaration 7 | TESTS:=cmp_lt cmp_le cmp_gt cmp_ge cmp_eq cmp_ne swapcase loop func print_int fizzbuzz malloc struct nullptr switch_op global puts 8 | 9 | OPT:=1 10 | 11 | ifeq ($(OPT), 0) 12 | else 13 | CFLAGS+=-O 14 | #TESTS+=hello 15 | endif 16 | 17 | TBINS:=$(TESTS:%=test/%) lisp lisp2d 18 | TOBJS:=$(TBINS:=.o) 19 | TASMS:=$(TBINS:=.s) 20 | TBEFS:=$(TBINS:=.bef) 21 | 22 | ALL=bc2bef befunge $(TOBJS) $(TASMS) $(TBEFS) $(TBINS) 23 | 24 | all: $(ALL) 25 | 26 | bc2bef.o: bc2bef.cc 27 | g++ -c $(CXXFLAGS) $< -o $@ 28 | 29 | bc2bef: bc2bef.o 30 | g++ $(CXXFLAGS) $< -L/usr/lib/llvm-3.6/lib -lLLVM-3.6 -o $@ 31 | 32 | befunge: befunge.cc 33 | g++ $(CXXFLAGS) $< -o $@ 34 | 35 | $(TASMS): %.s: %.c Makefile libef.h 36 | clang -S $(CLANGFLAGS) -emit-llvm $< -o $@ 37 | 38 | $(TOBJS): %.o: %.c Makefile libef.h 39 | clang -c $(CLANGFLAGS) -emit-llvm $< -o $@ 40 | 41 | $(TBINS): %: %.c Makefile libef.h 42 | gcc -g -MD $(CFLAGS) $< -o $@ 43 | 44 | $(TBEFS): %.bef: %.o bc2bef Makefile 45 | ./bc2bef -g $< > $@ 2> err || (cat err; rm $@; exit 1) 46 | 47 | test: all 48 | ./test_bef.rb $(TESTS) 49 | 50 | clean: 51 | rm -f $(ALL) err *.d 52 | 53 | -include *.d 54 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | BefLisp 2 | ======= 3 | 4 | Lisp implementation in Befunge 5 | 6 | [beflisp.bef](https://github.com/shinh/beflisp/blob/master/beflisp.bef) 7 | is a Lisp interpreter in Befunge. This Befunge code is generated 8 | from 9 | [lisp.c](https://github.com/shinh/beflisp/blob/master/lisp.c) 10 | with clang and 11 | [bc2bef.cc](https://github.com/shinh/beflisp/blob/master/bc2bef.cc), 12 | which is a translator 13 | from LLVM bit code to Befunge. 14 | 15 | [beflisp2d.bef](https://github.com/shinh/beflisp/blob/master/beflisp2d.bef) 16 | is a joke extension of Lisp. You can use 2D S expression. See 17 | [fizzbuzz.l2d](https://github.com/shinh/beflisp/blob/master/fizzbuzz.l2d) 18 | for an example of 2D Lisp code. 19 | 20 | 21 | How to Use 22 | ---------- 23 | 24 | $ make befunge 25 | $ ./befunge beflisp.bef # '>' won't be shown. 26 | > (car (quote (a b c))) 27 | a 28 | > (cdr (quote (a b c))) 29 | (b c) 30 | > (cons 1 (cons 2 (cons 3 ()))) 31 | (1 2 3) 32 | > (defun fact (n) (if (eq n 0) 1 (* n (fact (- n 1))))) 33 | (lambda (n) (if (eq n 0) 1 (* n (fact (- n 1))))) 34 | > (fact 10) 35 | 3628800 36 | > (defun fib (n) (if (eq n 1) 1 (if (eq n 0) 1 (+ (fib (- n 1)) (fib (- n 2)))))) 37 | (lambda (n) (if (eq n 1) 1 (if (eq n 0) 1 (+ (fib (- n 1)) (fib (- n 2)))))) 38 | > (fib 8) # slow! 39 | 34 40 | > (defun gen (n) ((lambda (x y) y) (define G n) (lambda (m) (define G (+ G m))))) 41 | (lambda (n) ((lambda (x y) y) (define G n) (lambda (m) (define G (+ G m))))) 42 | > (define x (gen 100)) 43 | (lambda (m) (define G (+ G m))) 44 | > (x 10) 45 | 110 46 | > (x 90) 47 | 200 48 | > (x 300) 49 | 500 50 | 51 | To run 2D Lisp, use beflisp2d.bef: 52 | 53 | $ ./befunge beflisp2d.bef < fizzbuzz.l2d 54 | 55 | 56 | Builtin Functions 57 | ----------------- 58 | 59 | - car 60 | - cdr 61 | - cons 62 | - eq 63 | - atom 64 | - +, -, *, /, mod 65 | - neg? 66 | - print 67 | 68 | 69 | Special Forms 70 | ------------- 71 | 72 | - quote 73 | - if 74 | - lambda 75 | - defun 76 | - define 77 | 78 | 79 | More Complicated Examples 80 | ------------------------- 81 | 82 | You can test a few more examples. 83 | 84 | FizzBuzz: 85 | 86 | $ cat fizzbuzz.l | ./befunge beflisp.bef 87 | (lambda (n) (if (eq n 101) nil (if (print (if (eq (mod n 15) 0) FizzBuzz (if (eq (mod n 5) 0) Buzz (if (eq (mod n 3) 0) Fizz n)))) (fizzbuzz (+ n 1)) nil))) 88 | 1 89 | 2 90 | Fizz 91 | ... 92 | 98 93 | Fizz 94 | Buzz 95 | nil 96 | 97 | Sort (this is slow!): 98 | 99 | $ cat sort.l /dev/stdin | ./befunge beflisp.bef 100 | ... 101 | (1 2 3 4 5 6 7) 102 | > (sort (quote (4 2))) 103 | (2 4) 104 | > (sort (quote (4 2 99 12 -4 -7))) 105 | (-7 -4 2 4 12 99) 106 | 107 | Though this Lisp implementation does not support eval function, we can 108 | implement eval on top of this interpreter - eval.l is the 109 | implementation: 110 | 111 | $ cat eval.l /dev/stdin | ./befunge beflisp.bef 112 | ... 113 | (eval (quote (+ 4 38))) 114 | 42 115 | (eval (quote (defun fact (n) (if (eq n 0) 1 (* n (fact (- n 1))))))) 116 | (fact (lambda (n) (if (eq n 0) 1 (* n (fact (- n 1)))))) 117 | (eval (quote (fact 4))) ; Takes 1 minute. 118 | 24 119 | 120 | This essentially means we have a Lisp interpreter in Lisp. evalify.rb 121 | is a helper script to convert a normal Lisp program into the Lisp in 122 | Lisp. You can run the FizzBuzz program like: 123 | 124 | $ ./evalify.rb fizzbuzz.l | ./befunge beflisp.bef 125 | ... 126 | 1 127 | 2 128 | Fizz 129 | 130 | This takes very long time. For me, it took 20 minutes. 131 | 132 | Though beflisp.bef does not support defmacro, eval.l also defines 133 | defmacro: 134 | 135 | $ ./evalify.rb | ./befunge beflisp.bef 136 | (defmacro let (l e) (cons (cons lambda (cons (cons (car l) nil) (cons e nil))) (cons (car (cdr l)) nil))) 137 | (let (x 42) (+ x 7)) ; Hit ^d after this. Takes 1 mins. 138 | ... 139 | 49 140 | $ ./evalify.rb | ./befunge beflisp.bef 141 | (defun list0 (a) (cons a nil)) 142 | (defun cadr (a) (car (cdr a))) 143 | (defmacro cond (l) (if l (cons if (cons (car (car l)) (cons (cadr (car l)) (cons (cons (quote cond) (list0 (cdr l))))))) nil)) 144 | (defun fb (n) (cond (((eq (mod n 5) 0) "Buzz") ((eq (mod n 3) 0) "Fizz") (t n)))) 145 | (fb 18) ; Hit ^d after this. Takes 2 minutes 146 | ... 147 | "Fizz" 148 | 149 | You can apply ./evalify.rb multiple times. However, beflisp seems to 150 | be too slow to run the generated program. lisp.c, which is an equivalent 151 | implementation of beflisp, can run it: 152 | 153 | $ make lisp 154 | $ ./evalify.rb fizzbuzz.l | ./evalify.rb | ./lisp 155 | ... 156 | 1 157 | 2 158 | Fizz 159 | 4 160 | Buzz 161 | Fizz 162 | 7 163 | 8 164 | 165 | test.l is the test program I was using during the development. test.rb 166 | runs it with beflisp.bef and purelisp.rb and compare their 167 | results. You can run the test with evalify.rb by passing -e: 168 | 169 | $ ./test.rb -e purelisp.rb beflisp.bef 170 | 171 | 172 | The LLVM to Befunge compiler 173 | ---------------------------- 174 | 175 | beflisp.bef is generated from lisp.c. Specifically, clang compiles 176 | lisp.c into LLVM bitcode, and bc2bef.cc translates the bitcode into a 177 | Befunge program. 178 | 179 | bc2bef.cc cannot translate arbitrary LLVM bitcode. Especially, it does 180 | not support non 32bit types at all. Notice lisp.c has no variables 181 | which have char. Even strings are represented by int. The test 182 | directory contains a bunch of C source files which bc2bef.cc can 183 | handle. 184 | 185 | There are a few builtin functions: putchar, getchar, calloc, free, 186 | puts, and exit. For now, free does nothing so all allocated memory 187 | leaks. puts is a very special function. Even though bc2bef.cc does not 188 | support character types, you can pass a constant string literal to 189 | puts. 190 | 191 | If you want to see generated code, you can build everything by: 192 | 193 | $ make test 194 | 195 | Note you need clang and LLVM installed. My LLVM version is 3.3. 196 | 197 | Makefile would show how to use bc2bef. 198 | 199 | 200 | Limitations 201 | ----------- 202 | 203 | There should be a lot of limitations. beflisp behaves very strangely 204 | when you pass a broken Lisp code. 205 | 206 | beflisp.bef only uses Befunge-93 operations, but cannot run with 207 | Befunge-93's small address space. 208 | 209 | It seems all test code works with 210 | [cfunge](http://sourceforge.net/projects/cfunge/) 211 | but the Lisp interpreter can only handle specific programs. Not sure 212 | why. 213 | 214 | $ echo '(if 1 9 7)' | cfunge beflisp.bef 215 | 9 # works 216 | $ echo '(+ 9 7)' | cfunge beflisp.bef 217 | # hangs 218 | -------------------------------------------------------------------------------- /bc2bef.cc: -------------------------------------------------------------------------------- 1 | #define __STDC_CONSTANT_MACROS 2 | #define __STDC_LIMIT_MACROS 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | using namespace llvm; 32 | using namespace std; 33 | 34 | static const int kLocalPos = 9 * 9 * 9 * 9 * 8; 35 | static const int kStackPos = 9 * 9 * 9 * 9 * 8; 36 | static const int kGlobalPos = 9 * 9 * 9 * 9 * 9 * 6; 37 | static const int kHeapPos = 9 * 9 * 9 * 9 * 9 * 8; 38 | 39 | bool is_debug; 40 | 41 | int getConstInt(const Value* v) { 42 | auto cv = dynamic_cast(v); 43 | assert(cv); 44 | return cv->getLimitedValue(); 45 | } 46 | 47 | int getSizeOfType(const Type* t) { 48 | if (t->isPointerTy()) 49 | return 1; 50 | if (t->isIntegerTy()) { 51 | assert(t->getPrimitiveSizeInBits() > 0); 52 | assert(t->getPrimitiveSizeInBits() <= 32); 53 | return 1; 54 | } 55 | if (t->isArrayTy()) { 56 | auto at = static_cast(t); 57 | return (at->getNumElements() * getSizeOfType(at->getElementType())); 58 | } 59 | if (t->isStructTy()) { 60 | auto st = static_cast(t); 61 | int s = 0; 62 | for (size_t i = 0; i < st->getNumElements(); i++) { 63 | s += getSizeOfType(st->getElementType(i)); 64 | } 65 | return s; 66 | } 67 | t->dump(); 68 | assert(false); 69 | } 70 | 71 | class B2B { 72 | enum MemType { 73 | LOCAL, 74 | MEM, 75 | PHI, 76 | }; 77 | 78 | public: 79 | explicit B2B(Module* module) : module_(module) { 80 | } 81 | 82 | void filterInstructions() { 83 | for (Function& func : module_->getFunctionList()) { 84 | for (BasicBlock& block : func.getBasicBlockList()) { 85 | vector removes; 86 | for (Instruction& inst : block.getInstList()) { 87 | switch (inst.getOpcode()) { 88 | case Instruction::Call: { 89 | const Function* func = 90 | static_cast(inst).getCalledFunction(); 91 | assert(func); 92 | if (func->getName() != "llvm.lifetime.start" && 93 | func->getName() != "llvm.lifetime.end") { 94 | break; 95 | } 96 | } // fall through 97 | #if 0 98 | case Instruction::BitCast: 99 | case Instruction::SExt: 100 | #endif 101 | removes.push_back(&inst); 102 | } 103 | } 104 | 105 | for (Instruction* inst : removes) { 106 | inst->dump(); 107 | inst->removeFromParent(); 108 | } 109 | } 110 | } 111 | } 112 | 113 | void run() { 114 | filterInstructions(); 115 | int entry_point = assignIds(); 116 | emitSetup(entry_point); 117 | translate(); 118 | } 119 | 120 | const string& code() const { return code_; } 121 | const vector& befunge() const { return bef_; } 122 | 123 | private: 124 | int assignIds() { 125 | int block_id = 0; 126 | int entry_point = -1; 127 | for (const Function& func : module_->getFunctionList()) { 128 | if (func.isDeclaration()) 129 | continue; 130 | 131 | func_map_[&func] = block_id; 132 | 133 | if (func.getName() == "main") 134 | entry_point = block_id; 135 | 136 | for (const BasicBlock& block : func.getBasicBlockList()) { 137 | block_map_.insert(make_pair(&block, block_id)); 138 | for (const Instruction& inst : block.getInstList()) { 139 | block_map_.insert(make_pair(&inst, block_id)); 140 | 141 | if (inst.getOpcode() == Instruction::Call) { 142 | const Function* func = 143 | static_cast(inst).getCalledFunction(); 144 | assert(func); 145 | if (func->getName() != "putchar" && 146 | func->getName() != "getchar" && 147 | func->getName() != "calloc" && 148 | func->getName() != "free" && 149 | func->getName() != "puts" && 150 | func->getName() != "exit") { 151 | assert(inst.getNextNode()); 152 | block_id++; 153 | } 154 | } 155 | } 156 | block_id++; 157 | } 158 | } 159 | 160 | map ref_map; 161 | for (const Function& func : module_->getFunctionList()) { 162 | if (func.isDeclaration()) 163 | continue; 164 | 165 | int id = 0; 166 | for (const BasicBlock& block : func.getBasicBlockList()) { 167 | for (const Instruction& inst : block.getInstList()) { 168 | for (size_t i = 0; i < inst.getNumOperands(); i++) { 169 | auto* o = dynamic_cast(inst.getOperand(i)); 170 | if (!o) 171 | continue; 172 | int rel = 1; 173 | if (block_map_[&inst] != block_map_[o]) 174 | rel = 3; 175 | else if (o->getNextNode() != &inst) 176 | rel = 2; 177 | else 178 | rel = 1; 179 | o->dump(); 180 | ref_map[o] = max(ref_map[o], rel); 181 | } 182 | } 183 | } 184 | 185 | local_size_map_[&func] = id; 186 | } 187 | 188 | for (const Function& func : module_->getFunctionList()) { 189 | if (func.isDeclaration()) 190 | continue; 191 | 192 | int id = 0; 193 | for (const Argument& arg : func.getArgumentList()) { 194 | id_map_.insert(make_pair(&arg, id)); 195 | id++; 196 | } 197 | 198 | for (const BasicBlock& block : func.getBasicBlockList()) { 199 | int reg_id = -3; 200 | for (const Instruction& inst : block.getInstList()) { 201 | int rel = ref_map[&inst]; 202 | /* 203 | if (rel == 0) { 204 | id_map_.insert(make_pair(&inst, -1)); 205 | } else if (rel == 1) { 206 | id_map_.insert(make_pair(&inst, -2)); 207 | } else 208 | */ 209 | if (rel != 3) { 210 | id_map_.insert(make_pair(&inst, reg_id)); 211 | reg_id--; 212 | } else { 213 | id_map_.insert(make_pair(&inst, id)); 214 | id++; 215 | } 216 | } 217 | } 218 | 219 | local_size_map_[&func] = id; 220 | } 221 | return entry_point; 222 | } 223 | 224 | void translate() { 225 | const string indent(20, ' '); 226 | for (const Function& func : module_->getFunctionList()) { 227 | if (func.isDeclaration()) 228 | continue; 229 | 230 | stack_size_ = 0; 231 | 232 | char buf[999]; 233 | sprintf(buf, "*** %s *** %d", func.getName().data(), func_map_[&func]); 234 | bef_.push_back(indent + buf); 235 | 236 | for (const Argument& arg : func.getArgumentList()) 237 | set(LOCAL, id_map_[&arg]); 238 | 239 | const Instruction* last_inst = NULL; 240 | for (const BasicBlock& block : func.getBasicBlockList()) { 241 | if (is_debug) { 242 | sprintf(buf, "block %d", block_map_[&block]); 243 | bef_.push_back(indent + buf); 244 | for (const Instruction& inst : block.getInstList()) { 245 | ostringstream oss; 246 | raw_os_ostream ros(oss); 247 | inst.print(ros); 248 | bef_.push_back(indent + oss.str().substr(0, oss.str().find('\n'))); 249 | } 250 | } 251 | 252 | for (const Instruction& inst : block.getInstList()) { 253 | fprintf(stderr, "%u %s %d\n", 254 | inst.getOpcode(), inst.getOpcodeName(), inst.hasMetadata()); 255 | last_inst = &inst; 256 | handleInstrcution(inst); 257 | if (inst.getOpcode() != Instruction::Br && 258 | inst.getOpcode() != Instruction::Switch && 259 | inst.getOpcode() != Instruction::Store && 260 | inst.getOpcode() != Instruction::Ret) { 261 | set(LOCAL, getInstId(inst)); 262 | } 263 | code_ += ' '; 264 | } 265 | 266 | assert(last_inst); 267 | emitBlock(*last_inst); 268 | } 269 | } 270 | } 271 | 272 | int getInstId(const Value& inst) { 273 | auto found = id_map_.find(&inst); 274 | assert(found != id_map_.end()); 275 | return found->second; 276 | } 277 | 278 | void emitSetup(int entry_point) { 279 | genInt(kStackPos); 280 | setStackPointer(); 281 | genInt(kHeapPos); 282 | setHeapPointer(); 283 | genInt(kLocalPos); 284 | setLocalPointer(); 285 | genInt(entry_point); 286 | 287 | setupGlobalVars(); 288 | 289 | emitCode(0, false); 290 | code_.clear(); 291 | 292 | emitChar(6, bef_.size() - 1, '<'); 293 | emitChar(0, bef_.size() - 1, 'v'); 294 | } 295 | 296 | void setupGlobalVars() { 297 | int global_id = kGlobalPos; 298 | for (const GlobalVariable& gv : module_->getGlobalList()) { 299 | if (gv.getInitializer()->getAggregateElement(0U)) { 300 | // TODO: check if this is a const char? 301 | continue; 302 | } 303 | 304 | if (!dynamic_cast(gv.getInitializer())) { 305 | int v = getConstInt(gv.getInitializer()); 306 | if (v) { 307 | genInt(v); 308 | genInt(global_id); 309 | make2D(MEM); 310 | code_ += 'p'; 311 | } 312 | } 313 | 314 | global_map_.insert(make_pair(&gv, global_id)); 315 | global_id += getSizeOfType(gv.getType()); 316 | } 317 | } 318 | 319 | void emitBlock(const Value& block) { 320 | int block_id = block_map_.at(&block); 321 | bef_.push_back(">:#v_ >$"); 322 | bef_.push_back("v-1<> 1+^"); 323 | bef_.push_back("v ^_^#:<"); 324 | 325 | genInt(block_id); 326 | code_ += "-:0`!"; 327 | int y = bef_.size() - 3; 328 | emitCode(y, true); 329 | } 330 | 331 | void emitCode(int oy, bool is_block) { 332 | int x = 10; 333 | int y = oy; 334 | int dx = 1; 335 | for (char c : code_) { 336 | if (c == 'S' || c == 'G') { 337 | static const int kMargin = 19; 338 | if (x > 78 - kMargin && dx == 1) { 339 | emitChar(x, y, 'v'); 340 | emitChar(x, y + 1, '<'); 341 | y++; 342 | x--; 343 | dx = -dx; 344 | } 345 | if (x < 10 + kMargin && dx == -1) { 346 | emitChar(x, y, 'v'); 347 | emitChar(x, y + 1, '>'); 348 | y++; 349 | x++; 350 | dx = -dx; 351 | } 352 | 353 | string code; 354 | if (c == 'S') { 355 | if (dx > 0) { 356 | code = "> #0 #\\_$"; 357 | } else { 358 | code = "'); 382 | y++; 383 | x++; 384 | dx = -dx; 385 | } 386 | 387 | emitChar(x, y, c); 388 | x += dx; 389 | } 390 | 391 | if (is_block) { 392 | if (x > 75) { 393 | if (dx > 0) { 394 | emitChar(x, y, 'v'); 395 | emitChar(x, y + 1, '<'); 396 | y++; 397 | } 398 | x = 75; 399 | } 400 | emitChar(x, y, 'v'); 401 | y = max(y + 1, oy + 2); 402 | emitChar(x, y, '_'); 403 | emitChar(x + 1, y, '1'); 404 | emitChar(x + 2, y, '-'); 405 | 406 | if (oy + 3 != (int)bef_.size()) { 407 | emitChar(0, bef_.size() - 1, 'v'); 408 | emitChar(9, bef_.size() - 1, '^'); 409 | } 410 | } else { 411 | if (dx > 0) { 412 | emitChar(x, y, 'v'); 413 | emitChar(x, y + 1, '<'); 414 | y++; 415 | x--; 416 | dx = -dx; 417 | } 418 | } 419 | 420 | code_.clear(); 421 | } 422 | 423 | void emitChar(int x, int y, char c) { 424 | bef_.resize(max(bef_.size(), y + 1)); 425 | bef_[y].resize(max(bef_[y].size(), x + 1), ' '); 426 | bef_[y][x] = c; 427 | } 428 | 429 | void handleInstrcution(const Instruction& inst) { 430 | switch (inst.getOpcode()) { 431 | case Instruction::Call: 432 | handleCall(static_cast(inst)); 433 | break; 434 | 435 | case Instruction::Add: 436 | case Instruction::Sub: 437 | case Instruction::Mul: 438 | case Instruction::SDiv: 439 | case Instruction::SRem: 440 | case Instruction::And: 441 | case Instruction::Or: 442 | case Instruction::Xor: 443 | handleArith(inst); 444 | break; 445 | 446 | case Instruction::BitCast: 447 | case Instruction::PtrToInt: 448 | case Instruction::SExt: 449 | case Instruction::ZExt: 450 | getLocal(inst.getOperand(0)); 451 | break; 452 | 453 | case Instruction::GetElementPtr: 454 | handleGetElementPtr(static_cast(inst)); 455 | break; 456 | 457 | case Instruction::ICmp: 458 | handleCmp(static_cast(inst)); 459 | break; 460 | 461 | case Instruction::Br: 462 | handleBr(inst); 463 | break; 464 | 465 | case Instruction::Switch: 466 | handleSwitch(static_cast(inst)); 467 | break; 468 | 469 | case Instruction::Select: 470 | getLocal(inst.getOperand(2)); 471 | getLocal(inst.getOperand(1)); 472 | getLocal(inst.getOperand(0)); 473 | code_ += 'S'; 474 | break; 475 | 476 | case Instruction::PHI: 477 | get(PHI, getInstId(inst)); 478 | break; 479 | 480 | case Instruction::Ret: 481 | handleRet(inst); 482 | break; 483 | 484 | case Instruction::Alloca: 485 | handleAlloca(static_cast(inst)); 486 | break; 487 | 488 | case Instruction::Load: 489 | getLocal(inst.getOperand(0)); 490 | make2D(MEM); 491 | code_ += 'g'; 492 | break; 493 | 494 | case Instruction::Store: 495 | getLocal(inst.getOperand(0)); 496 | //code_ += ":."; 497 | getLocal(inst.getOperand(1)); 498 | //code_ += ":."; 499 | make2D(MEM); 500 | code_ += 'p'; 501 | break; 502 | 503 | default: 504 | fprintf(stderr, "Unknown op: %s\n", inst.getOpcodeName()); 505 | assert(false); 506 | } 507 | } 508 | 509 | void handleArith(const Instruction& inst) { 510 | getLocal(inst.getOperand(0)); 511 | getLocal(inst.getOperand(1)); 512 | switch (inst.getOpcode()) { 513 | case Instruction::Xor: 514 | assert(inst.getType()->getPrimitiveSizeInBits() == 1); 515 | case Instruction::Or: 516 | case Instruction::Add: 517 | code_ += '+'; break; 518 | case Instruction::Sub: 519 | code_ += '-'; break; 520 | case Instruction::And: 521 | assert(inst.getType()->getPrimitiveSizeInBits() == 1); 522 | case Instruction::Mul: 523 | code_ += '*'; break; 524 | case Instruction::SDiv: 525 | code_ += '/'; break; 526 | case Instruction::SRem: 527 | code_ += '%'; break; 528 | default: 529 | assert(false); 530 | } 531 | 532 | if (inst.getOpcode() == Instruction::Xor) { 533 | code_ += "2%"; 534 | } 535 | } 536 | 537 | void handleRet(const Instruction& inst) { 538 | if (stack_size_) { 539 | getStackPointer(); 540 | genInt(stack_size_); 541 | code_ += '-'; 542 | setStackPointer(); 543 | } 544 | 545 | auto func = dynamic_cast(inst.getParent()->getParent()); 546 | assert(func); 547 | if (func->getName() == "main") { 548 | code_ += '@'; 549 | } else { 550 | // TODO: handle SP 551 | assert(inst.getNumOperands() < 2); 552 | if (inst.getNumOperands()) { 553 | getLocal(inst.getOperand(0)); 554 | code_ += '\\'; 555 | } else { 556 | code_ += "0\\"; 557 | } 558 | } 559 | } 560 | 561 | void handleCall(const CallInst& ci) { 562 | const Function* func = ci.getCalledFunction(); 563 | assert(func); 564 | 565 | fprintf(stderr, "func: %s\n", func->getName().data()); 566 | if (func->getName() == "putchar") { 567 | assert(ci.getNumArgOperands() == 1); 568 | getLocal(ci.getArgOperand(0)); 569 | code_ += ",0"; 570 | } else if (func->getName() == "getchar") { 571 | assert(ci.getNumArgOperands() == 0); 572 | code_ += "G"; 573 | } else if (func->getName() == "calloc") { 574 | assert(ci.getNumArgOperands() == 2); 575 | assert(getConstInt(ci.getArgOperand(1)) == 4); 576 | getHeapPointer(); 577 | code_ += ':'; 578 | getLocal(ci.getArgOperand(0)); 579 | code_ += "+"; 580 | setHeapPointer(); 581 | } else if (func->getName() == "free") { 582 | code_ += "0"; 583 | } else if (func->getName() == "puts") { 584 | assert(ci.getNumArgOperands() == 1); 585 | ci.getArgOperand(0)->dump(); 586 | auto ce = dynamic_cast(ci.getArgOperand(0)); 587 | assert(ce); 588 | auto ge = dynamic_cast(ce->getAsInstruction()); 589 | assert(ge); 590 | auto gv = dynamic_cast(ge->getOperand(0)); 591 | assert(gv); 592 | for (size_t i = 0; gv->getInitializer()->getAggregateElement(i); i++) { 593 | int v = getConstInt(gv->getInitializer()->getAggregateElement(i)); 594 | if (!v) 595 | break; 596 | genInt(v); 597 | code_ += ','; 598 | } 599 | code_ += "52*,0"; 600 | } else if (func->getName() == "exit") { 601 | code_ += "@"; 602 | } else { 603 | auto found = block_map_.find(&ci); 604 | assert(found != block_map_.end()); 605 | int ret = found->second + 1; 606 | genInt(ret); 607 | for (int i = ci.getNumArgOperands() - 1; i >= 0; i--) 608 | getLocal(ci.getArgOperand(i)); 609 | 610 | const auto& blocks = func->getBasicBlockList(); 611 | assert(!blocks.empty()); 612 | prepareBranch(NULL, &*blocks.begin()); 613 | 614 | modifyLocalPointer(ci, '+'); 615 | emitBlock(ci); 616 | modifyLocalPointer(ci, '-'); 617 | } 618 | } 619 | 620 | void modifyLocalPointer(const CallInst& ci, char op) { 621 | getLocalPointer(); 622 | auto func = dynamic_cast(ci.getParent()->getParent()); 623 | assert(func); 624 | genInt(local_size_map_[func]); 625 | code_ += op; 626 | setLocalPointer(); 627 | } 628 | 629 | void prepareBranch(const Instruction* src, const BasicBlock* block) { 630 | for (const Instruction& inst : block->getInstList()) { 631 | if (inst.getOpcode() != Instruction::PHI) 632 | break; 633 | 634 | auto& phi = static_cast(inst); 635 | assert(src); 636 | const BasicBlock* src_block = src->getParent(); 637 | 638 | bool handled = false; 639 | for (size_t i = 0; i < phi.getNumIncomingValues(); i++) { 640 | if (src_block != phi.getIncomingBlock(i)) 641 | continue; 642 | if (dynamic_cast(phi.getIncomingValue(i))) 643 | genInt(0); 644 | else 645 | getLocal(phi.getIncomingValue(i)); 646 | #if 0 647 | genInt(getInstId(phi)); 648 | code_ += " .:. "; 649 | #endif 650 | set(PHI, getInstId(phi)); 651 | handled = true; 652 | break; 653 | } 654 | assert(handled); 655 | } 656 | 657 | auto found = block_map_.find(block); 658 | assert(found != block_map_.end()); 659 | genInt(found->second); 660 | } 661 | 662 | void handleBr(const Instruction& inst) { 663 | if (inst.getNumOperands() == 3) { 664 | prepareBranch(&inst, static_cast(inst.getOperand(1))); 665 | prepareBranch(&inst, static_cast(inst.getOperand(2))); 666 | getLocal(inst.getOperand(0)); 667 | 668 | code_ += 'S'; 669 | } else if (inst.getNumOperands() == 1) { 670 | prepareBranch(&inst, static_cast(inst.getOperand(0))); 671 | } 672 | } 673 | 674 | void handleSwitch(const SwitchInst& si) { 675 | assert(si.getNumOperands() > 2); 676 | prepareBranch(&si, static_cast(si.getOperand(1))); 677 | 678 | for (SwitchInst::ConstCaseIt it = si.case_begin(); 679 | it != si.case_end(); 680 | ++it) { 681 | prepareBranch(&si, it.getCaseSuccessor()); 682 | genInt(getConstInt(it.getCaseValue())); 683 | getLocal(si.getOperand(0)); 684 | code_ += "-!S"; 685 | } 686 | } 687 | 688 | void handleCmp(const ICmpInst& cmp) { 689 | switch (cmp.getPredicate()) { 690 | case CmpInst::ICMP_EQ: 691 | getLocal(cmp.getOperand(0)); 692 | //code_ += "88*,:."; 693 | getLocal(cmp.getOperand(1)); 694 | code_ += "-!"; 695 | //code_ += "88*,:."; 696 | break; 697 | 698 | case CmpInst::ICMP_NE: 699 | getLocal(cmp.getOperand(0)); 700 | getLocal(cmp.getOperand(1)); 701 | code_ += "-!!"; 702 | break; 703 | 704 | case CmpInst::ICMP_UGT: 705 | case CmpInst::ICMP_SGT: 706 | getLocal(cmp.getOperand(0)); 707 | if (cmp.getPredicate() == CmpInst::ICMP_UGT) 708 | convertUnsigned(); 709 | getLocal(cmp.getOperand(1)); 710 | if (cmp.getPredicate() == CmpInst::ICMP_UGT) 711 | convertUnsigned(); 712 | code_ += "`"; 713 | break; 714 | 715 | case CmpInst::ICMP_ULT: 716 | case CmpInst::ICMP_SLT: 717 | getLocal(cmp.getOperand(1)); 718 | if (cmp.getPredicate() == CmpInst::ICMP_ULT) 719 | convertUnsigned(); 720 | getLocal(cmp.getOperand(0)); 721 | if (cmp.getPredicate() == CmpInst::ICMP_ULT) 722 | convertUnsigned(); 723 | code_ += "`"; 724 | break; 725 | 726 | case CmpInst::ICMP_UGE: 727 | case CmpInst::ICMP_SGE: 728 | getLocal(cmp.getOperand(1)); 729 | if (cmp.getPredicate() == CmpInst::ICMP_UGE) 730 | convertUnsigned(); 731 | getLocal(cmp.getOperand(0)); 732 | if (cmp.getPredicate() == CmpInst::ICMP_UGE) 733 | convertUnsigned(); 734 | code_ += "`!"; 735 | break; 736 | 737 | case CmpInst::ICMP_ULE: 738 | case CmpInst::ICMP_SLE: 739 | getLocal(cmp.getOperand(0)); 740 | if (cmp.getPredicate() == CmpInst::ICMP_ULE) 741 | convertUnsigned(); 742 | getLocal(cmp.getOperand(1)); 743 | if (cmp.getPredicate() == CmpInst::ICMP_ULE) 744 | convertUnsigned(); 745 | code_ += "`!"; 746 | break; 747 | 748 | default: 749 | assert(false); 750 | } 751 | } 752 | 753 | void handleAlloca(const AllocaInst& alloca) { 754 | getStackPointer(); 755 | alloca.getAllocatedType()->dump(); 756 | code_ += ':'; 757 | int size = getSizeOfType(alloca.getAllocatedType()); 758 | stack_size_ += size; 759 | genInt(size); 760 | code_ += '+'; 761 | setStackPointer(); 762 | } 763 | 764 | void handleGetElementPtr(const GetElementPtrInst& gep) { 765 | assert(gep.isInBounds()); 766 | assert(gep.getNumOperands() > 0); 767 | getLocal(gep.getOperand(0)); 768 | //gep.getOperand(0)->dump(); 769 | for (size_t i = 1; i < gep.getNumOperands(); i++) { 770 | getLocal(gep.getOperand(i)); 771 | code_ += '+'; 772 | } 773 | // TODO: check type 774 | } 775 | 776 | void genInt(int v) { 777 | if (v > 9 && v < 82) { 778 | for (int i = 2; i < 10; i++) { 779 | for (int j = i; j < 10; j++) { 780 | if (i * j == v) { 781 | code_ += '0' + i; 782 | code_ += '0' + j; 783 | code_ += '*'; 784 | return; 785 | } 786 | } 787 | } 788 | } 789 | 790 | char op = '+'; 791 | if (v < 0) { 792 | v = -v; 793 | op = '-'; 794 | } 795 | vector c; 796 | do { 797 | c.push_back(v % 9); 798 | v /= 9; 799 | } while (v); 800 | 801 | if (op == '-') 802 | code_ += '0'; 803 | for (size_t i = 0; i < c.size(); i++) { 804 | if (i != 0) 805 | code_ += "9*"; 806 | char v = c[c.size() - i - 1]; 807 | if (v || c.size() == 1) { 808 | code_ += (v + '0'); 809 | if (i != 0 || op == '-') 810 | code_ += op; 811 | } 812 | } 813 | } 814 | 815 | void getLocal(const Value* v) { 816 | auto found = global_map_.find(v); 817 | if (found != global_map_.end()) { 818 | genInt(found->second); 819 | } else if (auto cv = dynamic_cast(v)) { 820 | int c = cv->getLimitedValue(); 821 | genInt(c); 822 | } else if (dynamic_cast(v)) { 823 | genInt(0); 824 | } else { 825 | int id = getInstId(*v); 826 | get(LOCAL, id); 827 | } 828 | } 829 | 830 | void make2D(MemType mt) { 831 | code_ += ":9%"; 832 | if (mt == MEM) 833 | code_ += "9+"; 834 | else if (mt == PHI) 835 | code_ += "9+9+"; 836 | else 837 | assert(mt == LOCAL); 838 | code_ += "\\9/"; 839 | } 840 | 841 | void getStackPointer() { 842 | code_ += "00g"; 843 | } 844 | 845 | void setStackPointer() { 846 | code_ += "00p"; 847 | } 848 | 849 | void getHeapPointer() { 850 | code_ += "10g"; 851 | } 852 | 853 | void setHeapPointer() { 854 | code_ += "10p"; 855 | } 856 | 857 | void getLocalPointer() { 858 | code_ += "20g"; 859 | } 860 | 861 | void setLocalPointer() { 862 | code_ += "20p"; 863 | } 864 | 865 | void addr(MemType mt, int id) { 866 | if (mt == LOCAL) { 867 | if (id < 0) { 868 | int reg = 2 - id; 869 | int y = reg % 2; 870 | int x = reg / 2 + 3; 871 | assert(x < 80); 872 | genInt(x); 873 | genInt(y); 874 | } else { 875 | getLocalPointer(); 876 | genInt(id); 877 | code_ += '+'; 878 | make2D(mt); 879 | } 880 | } else { 881 | int addr = kLocalPos + id; 882 | genInt(addr); 883 | make2D(mt); 884 | } 885 | } 886 | 887 | void get(MemType mt, int id) { 888 | addr(mt, id); 889 | code_ += 'g'; 890 | } 891 | 892 | void set(MemType mt, int id) { 893 | addr(mt, id); 894 | code_ += 'p'; 895 | } 896 | 897 | void convertUnsigned() { 898 | code_ += "::88*::*:**+\\01-`!S"; 899 | } 900 | 901 | Module* module_; 902 | string code_; 903 | map block_map_; 904 | map id_map_; 905 | map global_map_; 906 | map func_map_; 907 | map local_size_map_; 908 | vector bef_; 909 | int stack_size_; 910 | }; 911 | 912 | int main(int argc, char* argv[]) { 913 | const char* arg0 = argv[0]; 914 | 915 | if (!strcmp(argv[1], "-g")) { 916 | is_debug = true; 917 | argc--; 918 | argv++; 919 | } 920 | 921 | if (argc < 1) { 922 | fprintf(stderr, "Usage: %s bitcode\n", arg0); 923 | return 1; 924 | } 925 | 926 | LLVMContext context; 927 | auto buf = MemoryBuffer::getFile(argv[1]); 928 | if (error_code ec = buf.getError()) { 929 | fprintf(stderr, "Failed to read %s: %s\n", argv[1], ec.message().c_str()); 930 | } 931 | 932 | auto module = parseBitcodeFile(buf.get()->getMemBufferRef(), context); 933 | fprintf(stderr, "%p\n", module.get()); 934 | 935 | B2B b2b(module.get()); 936 | b2b.run(); 937 | for (size_t i = 0; i < b2b.befunge().size(); i++) { 938 | printf("%s\n", b2b.befunge()[i].c_str()); 939 | } 940 | } 941 | -------------------------------------------------------------------------------- /befunge.cc: -------------------------------------------------------------------------------- 1 | // A Funge-98 interpretter only with Befunge-93 operations. 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace std; 15 | 16 | vector > code; 17 | int ix, iy; 18 | int vx, vy; 19 | vector st; 20 | volatile bool signaled; 21 | 22 | bool debug = false; 23 | bool verbose = false; 24 | bool bounce_on_fail_input = false; 25 | 26 | inline void step() { 27 | if (vx) { 28 | ix += vx; 29 | if (ix < 0) 30 | ix = (int)code[iy].size() - 1; 31 | else if (ix >= (int)code[iy].size()) 32 | ix = 0; 33 | return; 34 | } 35 | 36 | restep: 37 | iy += vy; 38 | if (iy < 0) { 39 | iy = (int)code.size() - 1; 40 | } 41 | else if (iy >= (int)code.size()) { 42 | iy = 0; 43 | } else if (ix >= (int)code[iy].size()) { 44 | goto restep; 45 | } 46 | } 47 | 48 | inline int get() { 49 | assert(iy < (int)code.size()); 50 | if (ix < (int)code[iy].size()) 51 | return code[iy][ix]; 52 | else 53 | return 0; 54 | } 55 | 56 | inline void push(int v) { 57 | st.push_back(v); 58 | } 59 | 60 | inline int pop() { 61 | if (st.empty()) 62 | return 0; 63 | else { 64 | int r = st.back(); 65 | st.pop_back(); 66 | return r; 67 | } 68 | } 69 | 70 | void handleSignal(int) { 71 | signaled = true; 72 | } 73 | 74 | static void dump() { 75 | //fprintf(stderr, "%sc", "\x1b"); 76 | fprintf(stderr, "=== MEMORY ===\n"); 77 | for (int y = 0; y < (int)code.size(); y++) { 78 | for (int x = 0; x < (int)code[y].size(); x++) { 79 | char c = code[y][x]; 80 | bool color = true; 81 | if (x == ix && y == iy) { 82 | fprintf(stderr, "\x1b[41m"); 83 | } else if (c < 32) { 84 | fprintf(stderr, "\x1b[30m\x1b[47m"); 85 | c = c < 10 ? '0' + c : 'A' + c - 10; 86 | } else { 87 | color = false; 88 | } 89 | fputc(c, stderr); 90 | if (color) { 91 | fprintf(stderr, "\x1b[39m"); 92 | fprintf(stderr, "\x1b[49m"); 93 | } 94 | } 95 | fputc('\n', stderr); 96 | } 97 | 98 | fprintf(stderr, "=== STACK ===\n"); 99 | for (int v : st) { 100 | fprintf(stderr, "%d ", v); 101 | } 102 | fprintf(stderr, "\n"); 103 | 104 | fprintf(stderr, "\n"); 105 | } 106 | 107 | void handleUnsupportedOp(char op) { 108 | dump(); 109 | fprintf(stderr, 110 | "this implementation doesn't support '%c' (%d) @%d,%d\n", 111 | op, op, ix, iy); 112 | exit(1); 113 | } 114 | 115 | int main(int argc, char* argv[]) { 116 | srand(time(NULL)); 117 | 118 | const char* prog = argv[0]; 119 | 120 | while (argc >= 2 && argv[1][0] == '-') { 121 | if (!strcmp(argv[1], "-g")) { 122 | debug = true; 123 | } else if (!strcmp(argv[1], "-v")) { 124 | verbose = true; 125 | } else { 126 | fprintf(stderr, "unknown switch %s\n", argv[1]); 127 | return 1; 128 | } 129 | argc--; 130 | argv++; 131 | } 132 | 133 | if (argc < 2) { 134 | fprintf(stderr, "%s \n", prog); 135 | exit(1); 136 | } 137 | 138 | FILE* fp = fopen(argv[1], "rb"); 139 | if (!fp) { 140 | fprintf(stderr, "failed to open: %s\n", argv[1]); 141 | exit(1); 142 | } 143 | char* buf = NULL; 144 | size_t buf_len; 145 | ssize_t len; 146 | while ((len = getline(&buf, &buf_len, fp)) >= 0) { 147 | if (buf[len-1] == '\n') { 148 | buf[len-1] = '\0'; 149 | } 150 | code.push_back(vector()); 151 | for (char* p = buf; *p; p++) { 152 | code.back().push_back(*p); 153 | } 154 | } 155 | fclose(fp); 156 | 157 | #if 0 158 | signal(SIGINT, &handleSignal); 159 | signal(SIGSEGV, &handleSignal); 160 | #endif 161 | 162 | ix = iy = 0; 163 | vx = 1; 164 | vy = 0; 165 | for (;;) { 166 | int op = code[iy][ix]; 167 | //fprintf(stderr, "op=%c\n", op); 168 | switch (op) { 169 | case '<': 170 | vx = -1; 171 | vy = 0; 172 | break; 173 | case '>': 174 | vx = 1; 175 | vy = 0; 176 | break; 177 | case '^': 178 | vx = 0; 179 | vy = -1; 180 | break; 181 | case 'v': 182 | vx = 0; 183 | vy = 1; 184 | break; 185 | 186 | case '_': 187 | vy = 0; 188 | if (pop()) { 189 | vx = -1; 190 | } else { 191 | vx = 1; 192 | } 193 | break; 194 | case '|': 195 | vx = 0; 196 | if (pop()) { 197 | vy = -1; 198 | } else { 199 | vy = 1; 200 | } 201 | break; 202 | 203 | case '?': 204 | switch (rand() / (RAND_MAX / 4)) { 205 | case 0: 206 | vx = 1; 207 | vy = 0; 208 | break; 209 | case 1: 210 | vx = -1; 211 | vy = 0; 212 | break; 213 | case 2: 214 | vx = 0; 215 | vy = 1; 216 | break; 217 | case 3: 218 | vx = 0; 219 | vy = -1; 220 | break; 221 | } 222 | break; 223 | 224 | case ' ': 225 | break; 226 | 227 | case '#': 228 | step(); 229 | if (debug && code[iy][ix] == 'S') { 230 | dump(); 231 | } else if (verbose && code[iy][ix] == 'V') { 232 | dump(); 233 | } 234 | break; 235 | 236 | case '@': { 237 | if (debug) { 238 | fprintf(stderr, "program finished\n"); 239 | dump(); 240 | } 241 | exit(0); 242 | } 243 | 244 | case '0': case '1': case '2': case '3': case '4': 245 | case '5': case '6': case '7': case '8': case '9': 246 | push(op - '0'); 247 | break; 248 | 249 | case '"': 250 | step(); 251 | for (;;) { 252 | int c = get(); 253 | if (c == '"') 254 | break; 255 | push(c); 256 | step(); 257 | } 258 | break; 259 | 260 | case '&': { 261 | int v; 262 | if (scanf("%d", &v) == 1) { 263 | push(v); 264 | } else { 265 | if (bounce_on_fail_input) { 266 | vx = -vx; 267 | vy = -vy; 268 | } else { 269 | push(-1); 270 | } 271 | } 272 | break; 273 | } 274 | case '~': { 275 | int v = getchar(); 276 | if (v != EOF || !bounce_on_fail_input) { 277 | push(v); 278 | } else { 279 | vx = -vx; 280 | vy = -vy; 281 | } 282 | break; 283 | } 284 | 285 | case ',': 286 | putchar(pop()); 287 | break; 288 | case '.': 289 | printf("*%d*\n", pop()); 290 | break; 291 | 292 | case '+': { 293 | int y = pop(); 294 | push(pop() + y); 295 | break; 296 | } 297 | case '-': { 298 | int y = pop(); 299 | push(pop() - y); 300 | break; 301 | } 302 | case '*': { 303 | int y = pop(); 304 | push(pop() * y); 305 | break; 306 | } 307 | case '/': { 308 | int y = pop(); 309 | push(pop() / y); 310 | break; 311 | } 312 | case '%': { 313 | int y = pop(); 314 | push(pop() % y); 315 | break; 316 | } 317 | case '`': { 318 | int y = pop(); 319 | push(pop() > y); 320 | break; 321 | } 322 | case '!': 323 | push(!pop()); 324 | break; 325 | 326 | case ':': { 327 | int v = pop(); 328 | push(v); 329 | push(v); 330 | break; 331 | } 332 | case '\\': { 333 | int y = pop(); 334 | int x = pop(); 335 | push(y); 336 | push(x); 337 | break; 338 | } 339 | case '$': 340 | pop(); 341 | break; 342 | 343 | case 'g': { 344 | int y = pop(); 345 | int x = pop(); 346 | int v = 0; 347 | if (y >= 0 && x >= 0 && y < (int)code.size() && x < (int)code[y].size()) 348 | v = code[y][x]; 349 | //fprintf(stderr, "g x=%d y=%d v=%d\n", x, y, v); 350 | push(v); 351 | break; 352 | } 353 | case 'p': { 354 | //dump(); 355 | int y = pop(); 356 | int x = pop(); 357 | int v = pop(); 358 | //fprintf(stderr, "p x=%d y=%d v=%d\n", x, y, v); 359 | if (y < 0 || x < 0) { 360 | dump(); 361 | fprintf(stderr, "negative 'p' isn't supported x=%d y=%d\n", x, y); 362 | exit(1); 363 | } 364 | if (y >= (int)code.size()) { 365 | code.resize(y + 1); 366 | } 367 | if (x >= (int)code[y].size()) { 368 | code[y].resize(x + 1); 369 | } 370 | code[y][x] = v; 371 | break; 372 | } 373 | 374 | #if 0 375 | case 'S': 376 | if (!debug) 377 | goto unsupported; 378 | dump(); 379 | break; 380 | #endif 381 | 382 | default: 383 | // We are very strict for unsupported operations. 384 | handleUnsupportedOp(op); 385 | 386 | } 387 | step(); 388 | 389 | if (signaled) { 390 | if (debug) { 391 | dump(); 392 | } 393 | exit(1); 394 | } 395 | } 396 | } 397 | -------------------------------------------------------------------------------- /eval.l: -------------------------------------------------------------------------------- 1 | (defun cadr (s) (car (cdr s))) 2 | (defun cddr (s) (cdr (cdr s))) 3 | 4 | ;(defun table-add (m k v) (if m (if (eq (car m) k) (cons k (cons v (cddr m))) (cons (car m) (cons (cadr m) (table-add (cddr m) k v)))) (cons k (cons v nil)))) 5 | (defun table-add (m k v) (cons k (cons v m))) 6 | 7 | (define gval-table ()) 8 | (defun gval-table-add (k v) (define gval-table (table-add gval-table k v))) 9 | 10 | (define val-table ()) 11 | 12 | (defun eval (s) (if (atom s) (eval-val s) (eval-if (car s) (cdr s)))) 13 | 14 | (defun eval-gval-1 (v s) (if v (if (eq (car v) s) (cadr v) (eval-gval-1 (cddr v) s)) s)) 15 | (defun eval-gval (s) (eval-gval-1 gval-table s)) 16 | 17 | (defun eval-val-1 (v s) (if v (if (eq (car v) s) (cadr v) (eval-val-1 (cddr v) s)) (eval-gval s))) 18 | (defun eval-val (s) (eval-val-1 val-table s)) 19 | 20 | (defun eval-if (o s) (if (eq o if) (run-if s) (eval-defmacro o s))) 21 | (defun eval-defmacro (o s) (if (eq o defmacro) (run-defmacro s) (eval-defun o s))) 22 | (defun eval-defun (o s) (if (eq o defun) (run-defun s) (eval-lambda o s))) 23 | (defun eval-lambda (o s) (if (eq o lambda) (run-lambda s) (eval-quote o s))) 24 | (defun eval-quote (o s) (if (eq o quote) (run-quote s) (eval-define o s))) 25 | (defun eval-define (o s) (if (eq o define) (run-define s) (eval-macro (eval o) s))) 26 | (defun is-macro (o) (if (atom o) nil (eq (car o) macro))) 27 | (defun eval-macro (o s) (if (is-macro o) (run-macro (cdr o) s) (eval-func o s))) 28 | (defun is-func (o) (if (atom o) nil (eq (car o) lambda))) 29 | (defun eval-func (o s) (if (is-func o) (run-func (cdr o) s) (eval-add o s))) 30 | (defun eval-add (o s) (if (eq o +) (run-add s) (eval-sub o s))) 31 | (defun eval-sub (o s) (if (eq o -) (run-sub s) (eval-mul o s))) 32 | (defun eval-mul (o s) (if (eq o *) (run-mul s) (eval-div o s))) 33 | (defun eval-div (o s) (if (eq o /) (run-div s) (eval-mod o s))) 34 | (defun eval-mod (o s) (if (eq o mod) (run-mod s) (eval-eq o s))) 35 | (defun eval-eq (o s) (if (eq o eq) (run-eq s) (eval-car o s))) 36 | (defun eval-car (o s) (if (eq o car) (run-car s) (eval-cdr o s))) 37 | (defun eval-cdr (o s) (if (eq o cdr) (run-cdr s) (eval-cons o s))) 38 | (defun eval-cons (o s) (if (eq o cons) (run-cons s) (eval-atom o s))) 39 | (defun eval-atom (o s) (if (eq o atom) (run-atom s) (eval-neg o s))) 40 | (defun eval-neg (o s) (if (eq o neg?) (run-neg s) (eval-print o s))) 41 | (defun eval-print (o s) (if (eq o print) (run-print s) (undefined-func o))) 42 | (defun undefined-func (o) (print (cons o (quote (undefined func))))) 43 | 44 | (defun run-if (s) (if (eval (car s)) (eval (cadr s)) (eval (car (cddr s))))) 45 | (defun run-defmacro (s) (gval-table-add (car s) (cons macro (cdr s)))) 46 | (defun run-defun (s) (gval-table-add (car s) (run-lambda (cdr s)))) 47 | (defun run-lambda (s) (cons lambda s)) 48 | (defun run-quote (s) (car s)) 49 | (defun run-define (s) (gval-table-add (car s) (eval (cadr s)))) 50 | 51 | (defun create-val-table (a p) (if a (cons (car a) (cons (eval (car p)) (create-val-table (cdr a) (cdr p)))) ())) 52 | (defun set-vals (a p) (define val-table (create-val-table a p))) 53 | 54 | (defun run-func-2 (a b c) b) 55 | (defun run-func-1 (v l s) (run-func-2 (set-vals (car l) s) (eval (cadr l)) (define val-table v))) 56 | (defun run-func (l s) (run-func-1 val-table l s)) 57 | 58 | (defun create-val-table-m (a p) (if a (cons (car a) (cons (car p) (create-val-table-m (cdr a) (cdr p)))) ())) 59 | (defun set-vals-m (a p) (define val-table (create-val-table-m a p))) 60 | 61 | (defun run-macro-2 (a b c) b) 62 | (defun run-macro-1 (v l s) (run-macro-2 (set-vals-m (car l) s) (eval (cadr l)) (define val-table v))) 63 | 64 | (defun run-macro (l s) (eval (run-macro-1 val-table l s))) 65 | 66 | (defun run-add (s) (+ (eval (car s)) (eval (cadr s)))) 67 | (defun run-sub (s) (- (eval (car s)) (eval (cadr s)))) 68 | (defun run-mul (s) (* (eval (car s)) (eval (cadr s)))) 69 | (defun run-div (s) (/ (eval (car s)) (eval (cadr s)))) 70 | (defun run-mod (s) (mod (eval (car s)) (eval (cadr s)))) 71 | (defun run-eq (s) (eq (eval (car s)) (eval (cadr s)))) 72 | (defun run-car (s) (car (eval (car s)))) 73 | (defun run-cdr (s) (cdr (eval (car s)))) 74 | (defun run-cons (s) (cons (eval (car s)) (eval (cadr s)))) 75 | (defun run-atom (s) (atom (eval (car s)))) 76 | (defun run-neg (s) (neg? (eval (car s)))) 77 | (defun run-print (s) (print (eval (car s)))) 78 | 79 | ; TEST 80 | 81 | ;(eval (quote (cons (quote (1 2)) (quote (3 ((5 6)) 4))))) 82 | ;(eval (quote (- 3 (+ 3 (if (eq 4 2) (+ 2 (+ 3 2)) (- (+ 4 1) (+ 3 9))))))) 83 | 84 | ;(define gval-table (table-add gval-table foo hoge)) 85 | ;(define gval-table (table-add gval-table bar fuga)) 86 | ;(define gval-table (table-add gval-table foo hige)) 87 | ;(table-get gval-table foo) 88 | 89 | ;(eval (quote (defun fizzbuzz (n) (if (eq n 101) nil (if (print (if (eq (mod n 15) 0) FizzBuzz (if (eq (mod n 5) 0) Buzz (if (eq (mod n 3) 0) Fizz n)))) (fizzbuzz (+ n 1)) nil))))) 90 | ;(eval (quote (fizzbuzz 1))) 91 | 92 | 93 | 94 | ;(eval (quote (* 2 3))) 95 | 96 | ;(eval (quote (defun f (n) n))) 97 | ;(eval (quote (f 42))) 98 | 99 | ;(eval (quote ((lambda (n) (+ n 4)) 42))) 100 | ;(eval (quote (lambda (n) (+ n 4)))) 101 | 102 | ;(eval (quote (define func (lambda (n) (+ n n))))) 103 | ;(eval (quote (func 42))) 104 | 105 | ;(eval (quote (define func (lambda () (print FOO))))) 106 | ;(eval (quote (func))) 107 | 108 | ;(print START) 109 | ;(eval (quote (defun mul (n m) (if (eq n 0) 0 (+ m (mul (- n 1) m)))))) 110 | ;(print DEFINED) 111 | ;(eval (quote (print (mul 2 3)))) 112 | 113 | ;(print (run-func-1 1 2 3)) 114 | 115 | ;(eval (quote (print (mul 2 3)))) 116 | 117 | ;(eval (quote (defun mul (n m) (if (eq n 0) 0 (+ m (mul (- n 1) m)))))) 118 | ;(print START) 119 | ;(eval (quote (* 2 3))) 120 | 121 | 122 | ;(define val-table (table-add nil foo hoge)) 123 | ;(push-vals) 124 | ;(print val-stack) 125 | ;(pop-vals) 126 | ;(print val-stack) 127 | 128 | ;(eval (quote (define foo 42))) 129 | ;(eval (quote foo)) 130 | 131 | ;(eval (quote (defun func (c) 3))) 132 | ;(eval (quote (defun func2 (b) (+ (func) b)))) 133 | ;(eval (quote (defun func2 (b) (+ b (func 99))))) 134 | ;(eval (quote (func2 42))) 135 | 136 | ;(eval (quote (defmacro let (l e) (cons (cons lambda (cons (cons (car l) nil) (cons e nil))) (cons (car (cdr l)) nil))))) 137 | ;(eval (quote (let (x 42) x))) 138 | -------------------------------------------------------------------------------- /evalify.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | def evalify(c) 4 | o = File.read('eval.l').sub(/; TEST.*/ms, '') 5 | o.sub!(/;.*/, '') 6 | c.lines.each do |line| 7 | line.sub!(/;.*/, '') 8 | next if line =~ /^$/ 9 | o += "(eval (quote #{line.chomp}))\n" 10 | end 11 | o 12 | end 13 | 14 | if $0 == __FILE__ 15 | puts evalify($<.read) 16 | end 17 | -------------------------------------------------------------------------------- /fizzbuzz.l: -------------------------------------------------------------------------------- 1 | (defun fizzbuzz (n) (if (eq n 101) nil (if (print (if (eq (mod n 15) 0) FizzBuzz (if (eq (mod n 5) 0) Buzz (if (eq (mod n 3) 0) Fizz n)))) (fizzbuzz (+ n 1)) nil))) 2 | (fizzbuzz 1) 3 | -------------------------------------------------------------------------------- /fizzbuzz.l2d: -------------------------------------------------------------------------------- 1 | (defun fizzbuzz ^ (fizzbuzz 1) @ 2 | ^ zzuB ( 0 (5 n dom) 3 | i ^ 4 | f v ^ q 5 | ( eq ^ 6 | ^ fi) ^ v m 7 | e o 8 | q l f d 9 | i i 10 | n (mod n 15) 0) Fizzbuzz v n 11 | 12 | 1 q 3 13 | 0 e v 14 | 1 (if v 15 | v 0 16 | t v 17 | n n 18 | i i F 19 | l r i 20 | p ^ z 21 | (if v ^ z 22 | 1 23 | n 24 | 25 | v 26 | n v 27 | v 28 | + v 29 | v zzubzzif ) 30 | -------------------------------------------------------------------------------- /libef.h: -------------------------------------------------------------------------------- 1 | int getchar(void); 2 | int putchar(int c); 3 | int puts(const char* p); 4 | // We need to declare malloc as int* to reduce bitcasts */ 5 | int* calloc(int n, int s); 6 | void free(void* p); 7 | void exit(int s); 8 | 9 | __attribute__((noinline)) static void print_int(int v) { 10 | if (v < 0) { 11 | putchar('-'); 12 | v = -v; 13 | } 14 | int buf[16]; 15 | int n = 0; 16 | do { 17 | buf[n] = v % 10; 18 | v /= 10; 19 | n++; 20 | } while (v); 21 | 22 | while (n--) { 23 | putchar(buf[n] + '0'); 24 | } 25 | } 26 | 27 | static void print_str(int* p) { 28 | while (*p) { 29 | putchar(*p); 30 | p++; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lisp.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "libef.h" 4 | 5 | int g_buf = -1; 6 | 7 | int getChar(void) { 8 | int r; 9 | if (g_buf >= 0) { 10 | r = g_buf; 11 | g_buf = -1; 12 | } else { 13 | r = getchar(); 14 | if (r == -1) 15 | exit(0); 16 | } 17 | return r; 18 | } 19 | 20 | int peekChar(void) { 21 | if (g_buf >= 0) 22 | return g_buf; 23 | int c = getchar(); 24 | g_buf = c; 25 | return c; 26 | } 27 | 28 | void ungetChar(int c) { 29 | g_buf = c; 30 | } 31 | 32 | const int g_close_char = ')'; 33 | 34 | #include "lisp_common.c" 35 | 36 | Atom* parse(void) { 37 | skipWS(); 38 | int c = getChar(); 39 | if (c == '(') { 40 | return parseList(); 41 | } else if (c == '-' || (c >= '0' && c <= '9')) { 42 | return parseInt(c); 43 | } else if (c == ';') { 44 | while (c != '\n') { 45 | c = getChar(); 46 | } 47 | return parse(); 48 | } else { 49 | return parseStr(c); 50 | } 51 | } 52 | 53 | int main() { 54 | int buf[2]; 55 | buf[0] = 't'; 56 | buf[1] = '\0'; 57 | g_t = createStr(buf); 58 | 59 | while (1) { 60 | Atom* expr = parse(); 61 | Atom* result = eval(expr, NULL); 62 | printExpr(result); 63 | putchar('\n'); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /lisp2d.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "libef.h" 4 | 5 | int g_prog_height; 6 | int* g_line_len; 7 | int** g_prog; 8 | 9 | void readProg() { 10 | g_line_len = calloc(10000, 4); 11 | g_prog = (int**)calloc(10000, 4); 12 | int y = 0; 13 | int x = 0; 14 | for (;;) { 15 | int c = getchar(); 16 | if (c == -1) 17 | break; 18 | if (c == '\n') { 19 | x = 0; 20 | y++; 21 | continue; 22 | } 23 | 24 | if (!g_prog[y]) 25 | g_prog[y] = calloc(1000, 4); 26 | 27 | g_prog[y][x] = c; 28 | g_line_len[y] = ++x; 29 | } 30 | g_prog_height = y; 31 | } 32 | 33 | int g_x; 34 | int g_y; 35 | int g_dx; 36 | int g_dy; 37 | int g_px; 38 | int g_py; 39 | 40 | int peekChar(void) { 41 | if (g_x < g_line_len[g_y]) 42 | return g_prog[g_y][g_x]; 43 | else 44 | return ' '; 45 | } 46 | 47 | int getChar(void) { 48 | int r = peekChar(); 49 | g_px = g_x; 50 | g_py = g_y; 51 | g_x += g_dx; 52 | g_y += g_dy; 53 | if (g_y < 0) 54 | g_y = g_prog_height - 1; 55 | else if (g_y >= g_prog_height) 56 | g_y = 0; 57 | if (g_dx) { 58 | if (g_x < 0) 59 | g_x = g_line_len[g_y] - 1; 60 | else if (g_x >= g_line_len[g_y]) 61 | g_x = 0; 62 | } 63 | return r; 64 | } 65 | 66 | void ungetChar(int c) { 67 | g_x = g_px; 68 | g_y = g_py; 69 | if (peekChar() != c) { 70 | puts("weird ungetChar"); 71 | exit(1); 72 | } 73 | } 74 | 75 | int g_close_char; 76 | 77 | #include "lisp_common.c" 78 | 79 | Atom* parse(void) { 80 | skipWS(); 81 | int c = peekChar(); 82 | if (c == '(' && g_dx != -1) { 83 | g_dx = 1; 84 | g_dy = 0; 85 | getChar(); 86 | g_close_char = ')'; 87 | return parseList(); 88 | } else if (c == ')' && g_dx != 1) { 89 | g_dx = -1; 90 | g_dy = 0; 91 | getChar(); 92 | g_close_char = '('; 93 | return parseList(); 94 | } else if (c == '^' && g_dy != -1) { 95 | g_dx = 0; 96 | g_dy = 1; 97 | getChar(); 98 | g_close_char = 'v'; 99 | return parseList(); 100 | } else if (c == 'v' && g_dy != 1) { 101 | g_dx = 0; 102 | g_dy = -1; 103 | getChar(); 104 | g_close_char = '^'; 105 | return parseList(); 106 | } else if (c == '@') { 107 | exit(0); 108 | } else if (c == '-' || (c >= '0' && c <= '9')) { 109 | getChar(); 110 | return parseInt(c); 111 | } else if (c == ';') { 112 | while (c != '\n') { 113 | c = getChar(); 114 | } 115 | return parse(); 116 | } else { 117 | getChar(); 118 | return parseStr(c); 119 | } 120 | return NULL; 121 | } 122 | 123 | int main() { 124 | readProg(); 125 | g_dx = 1; 126 | 127 | int buf[2]; 128 | buf[0] = 't'; 129 | buf[1] = '\0'; 130 | g_t = createStr(buf); 131 | 132 | while (1) { 133 | Atom* expr = parse(); 134 | //printExpr(expr); 135 | Atom* result = eval(expr, NULL); 136 | printExpr(result); 137 | putchar('\n'); 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /lisp_common.c: -------------------------------------------------------------------------------- 1 | #define ALLOC(s) calloc(s / 4, 4) 2 | 3 | #define ERROR(s) (puts(s), printExpr(a), putchar('\n'), exit(1)) 4 | 5 | typedef enum { 6 | NUM, 7 | STR, 8 | LIST, 9 | LAMBDA 10 | } Type; 11 | 12 | typedef struct List { 13 | struct Atom* head; 14 | struct List* tail; 15 | } List; 16 | 17 | typedef struct Atom { 18 | Type type; 19 | union { 20 | int num; 21 | int* str; 22 | List* list; 23 | }; 24 | } Atom; 25 | 26 | typedef struct Table { 27 | int* key; 28 | Atom* value; 29 | struct Table* next; 30 | } Table; 31 | 32 | void printExpr(Atom* expr) { 33 | if (!expr) { 34 | putchar('n'); 35 | putchar('i'); 36 | putchar('l'); 37 | return; 38 | } 39 | 40 | if (expr->type == NUM) { 41 | print_int(expr->num); 42 | return; 43 | } 44 | 45 | if (expr->type == STR) { 46 | print_str(expr->str); 47 | return; 48 | } 49 | 50 | putchar('('); 51 | if (expr->type == LAMBDA) { 52 | putchar('l'); 53 | putchar('a'); 54 | putchar('m'); 55 | putchar('b'); 56 | putchar('d'); 57 | putchar('a'); 58 | putchar(' '); 59 | } 60 | 61 | List* l = expr->list; 62 | while (l) { 63 | printExpr(l->head); 64 | l = l->tail; 65 | if (l) 66 | putchar(' '); 67 | } 68 | putchar(')'); 69 | } 70 | 71 | List* cons(Atom* h, List* t) { 72 | List* s = (List*)ALLOC(sizeof(List)); 73 | s->head = h; 74 | s->tail = t; 75 | return s; 76 | } 77 | 78 | Atom* createAtom(Type type) { 79 | Atom* a = (Atom*)ALLOC(sizeof(Atom)); 80 | a->type = type; 81 | return a; 82 | } 83 | 84 | Atom* createInt(int n) { 85 | Atom* a = createAtom(NUM); 86 | a->num = n; 87 | return a; 88 | } 89 | 90 | Atom* createStr(int* s) { 91 | Atom* a = createAtom(STR); 92 | a->str = s; 93 | return a; 94 | } 95 | 96 | Atom* createList(List* l) { 97 | if (l == NULL) 98 | return NULL; 99 | Atom* a = createAtom(LIST); 100 | a->list = l; 101 | return a; 102 | } 103 | 104 | Atom* createLambda(List* l) { 105 | Atom* a = createAtom(LAMBDA); 106 | a->list = l; 107 | return a; 108 | } 109 | 110 | int atom(Atom* a) { 111 | return a == NULL || a->type != LIST || a->list == NULL; 112 | } 113 | 114 | int isList(Atom* a) { 115 | return a == NULL || a->type == LIST; 116 | } 117 | 118 | Atom* g_t; 119 | 120 | Table* g_val; 121 | 122 | Atom* parse(void); 123 | 124 | void skipWS(void) { 125 | int c = getChar(); 126 | while (c == ' ' || c == '\n') 127 | c = getChar(); 128 | ungetChar(c); 129 | } 130 | 131 | Atom* parseList(void) { 132 | List* l = NULL; 133 | List* n = NULL; 134 | while (1) { 135 | skipWS(); 136 | if (peekChar() == g_close_char) { 137 | getChar(); 138 | break; 139 | } 140 | Atom* a = parse(); 141 | List* t = cons(a, NULL); 142 | if (n) { 143 | n->tail = t; 144 | } else { 145 | l = n = t; 146 | } 147 | n = t; 148 | } 149 | return createList(l); 150 | } 151 | 152 | Atom* parseStr(int c) { 153 | int buf[99]; 154 | int n = 0; 155 | while (c != ' ' && c != '\n' && c != '(' && c != ')') { 156 | buf[n] = c; 157 | c = getChar(); 158 | n++; 159 | } 160 | ungetChar(c); 161 | 162 | if (n == 3 && buf[0] == 'n' && buf[1] == 'i' && buf[2] == 'l') 163 | return NULL; 164 | 165 | int* str = calloc(n + 1, 4); 166 | int i; 167 | for (i = 0; i < n; i++) { 168 | str[i] = buf[i]; 169 | } 170 | str[i] = '\0'; 171 | return createStr(str); 172 | } 173 | 174 | Atom* parseInt(int c) { 175 | int n = 0; 176 | int m = 0; 177 | if (c == '-') { 178 | m = 1; 179 | } else { 180 | n += c - '0'; 181 | } 182 | 183 | while (1) { 184 | c = getChar(); 185 | if (c >= '0' && c <= '9') { 186 | n *= 10; 187 | n += c - '0'; 188 | } else { 189 | ungetChar(c); 190 | break; 191 | } 192 | } 193 | 194 | if (m) { 195 | if (n == 0) 196 | return parseStr('-'); 197 | n = -n; 198 | } 199 | return createInt(n); 200 | } 201 | 202 | int eqStr(int* l, int* r) { 203 | int i; 204 | for (i = 0; l[i] || r[i]; i++) { 205 | if (l[i] != r[i]) 206 | return 0; 207 | } 208 | return 1; 209 | } 210 | 211 | Table* lookupTable(Table* t, int* k) { 212 | while (t) { 213 | if (eqStr(t->key, k)) 214 | return t; 215 | t = t->next; 216 | } 217 | return NULL; 218 | } 219 | 220 | void addTable(Table** t, int* k, Atom* v) { 221 | Table* nt = lookupTable(*t, k); 222 | if (!nt) { 223 | nt = (Table*)ALLOC(sizeof(Table)); 224 | nt->next = *t; 225 | *t = nt; 226 | } 227 | nt->key = k; 228 | nt->value = v; 229 | } 230 | 231 | int eq(Atom* l, Atom* r); 232 | 233 | int eqList(List* l, List* r) { 234 | while (l && r) { 235 | if (!eq(l->head, r->head)) 236 | return 0; 237 | 238 | l = l->tail; 239 | r = r->tail; 240 | } 241 | 242 | return l == NULL && r == NULL; 243 | } 244 | 245 | int eq(Atom* l, Atom* r) { 246 | if (l == r) 247 | return 1; 248 | 249 | if (l == NULL || r == NULL) 250 | return 0; 251 | 252 | if (l->type != r->type) 253 | return 0; 254 | 255 | if (l->type == NUM) 256 | return l->num == r->num; 257 | 258 | if (l->type == STR) 259 | return eqStr(l->str, r->str); 260 | 261 | return eqList(l->list, r->list); 262 | } 263 | 264 | int getListSize(List* l) { 265 | int n = 0; 266 | while (l) { 267 | l = l->tail; 268 | n++; 269 | } 270 | return n; 271 | } 272 | 273 | Atom* eval(Atom* a, Table* val) { 274 | if (atom(a)) { 275 | if (a && a->type == STR) { 276 | Table* t = lookupTable(val, a->str); 277 | if (t) 278 | return t->value; 279 | t = lookupTable(g_val, a->str); 280 | if (t) 281 | return t->value; 282 | } 283 | return a; 284 | } 285 | 286 | List* s = a->list; 287 | 288 | if (s->head->type == STR) { 289 | int* fn = s->head->str; 290 | if (fn[0] == 'i' && fn[1] == 'f' && fn[2] == '\0') { 291 | if (getListSize(s) != 4) 292 | ERROR("invalid if"); 293 | 294 | Atom* c = eval(s->tail->head, val); 295 | if (c) { 296 | return eval(s->tail->tail->head, val); 297 | } else { 298 | return eval(s->tail->tail->tail->head, val); 299 | } 300 | } else if (fn[0] == 'q' && fn[1] == 'u' && fn[2] == 'o' && 301 | fn[3] == 't' && fn[4] == 'e' && fn[5] == '\0') { 302 | if (getListSize(s) != 2) 303 | ERROR("invalid quote"); 304 | 305 | return s->tail->head; 306 | } else if (fn[0] == 'd' && fn[1] == 'e' && fn[2] == 'f' && 307 | fn[3] == 'i' && fn[4] == 'n' && fn[5] == 'e' && 308 | fn[6] == '\0') { 309 | if (getListSize(s) != 3 || s->tail->head->type != STR) 310 | ERROR("invalid define"); 311 | 312 | Atom* e = eval(s->tail->tail->head, val); 313 | addTable(&g_val, s->tail->head->str, e); 314 | return e; 315 | } else if (fn[0] == 'l' && fn[1] == 'a' && fn[2] == 'm' && 316 | fn[3] == 'b' && fn[4] == 'd' && fn[5] == 'a' && 317 | fn[6] == '\0') { 318 | if (getListSize(s) != 3 || !isList(s->tail->head)) 319 | ERROR("invalid lambda"); 320 | 321 | return createLambda(s->tail); 322 | } else if (fn[0] == 'd' && fn[1] == 'e' && fn[2] == 'f' && 323 | fn[3] == 'u' && fn[4] == 'n' && fn[5] == '\0') { 324 | if (getListSize(s) != 4 || 325 | s->tail->head->type != STR || !isList(s->tail->tail->head)) 326 | ERROR("invalid defun"); 327 | 328 | Atom* e = createLambda(s->tail->tail); 329 | addTable(&g_val, s->tail->head->str, e); 330 | return e; 331 | } 332 | } 333 | 334 | Atom* hd = eval(s->head, val); 335 | 336 | if (hd->type == LAMBDA) { 337 | List* args = hd->list->head ? hd->list->head->list : NULL; 338 | 339 | if (getListSize(s) - 1 != getListSize(args)) 340 | ERROR("invalid lambda application"); 341 | 342 | Table* nval = NULL; 343 | List* params = s->tail; 344 | while (args) { 345 | addTable(&nval, args->head->str, eval(params->head, val)); 346 | args = args->tail; 347 | params = params->tail; 348 | } 349 | 350 | Atom* expr = hd->list->tail->head; 351 | return eval(expr, nval); 352 | } 353 | 354 | if (hd->type == STR) { 355 | int* fn = hd->str; 356 | int op = fn[0]; 357 | if (((op == '+' || op == '-' || op == '*' || op == '/') && 358 | fn[1] == '\0') || 359 | (op == 'm' && fn[1] == 'o' && fn[2] == 'd' && fn[3] == '\0')) { 360 | if (getListSize(s) != 3) 361 | ERROR("invalid arith"); 362 | Atom* l = eval(s->tail->head, val); 363 | Atom* r = eval(s->tail->tail->head, val); 364 | if (l->type != NUM || r->type != NUM) 365 | ERROR("invalid arith"); 366 | int result = 0; 367 | if (op == '+') result = l->num + r->num; 368 | else if (op == '-') result = l->num - r->num; 369 | else if (op == '*') result = l->num * r->num; 370 | else if (op == '/') result = l->num / r->num; 371 | else result = l->num % r->num; 372 | return createInt(result); 373 | } else if (op == 'e' && fn[1] == 'q' && fn[2] == '\0') { 374 | if (getListSize(s) != 3) 375 | ERROR("invalid eq"); 376 | 377 | Atom* l = eval(s->tail->head, val); 378 | Atom* r = eval(s->tail->tail->head, val); 379 | if (eq(l, r)) 380 | return g_t; 381 | else 382 | return NULL; 383 | } else if (op == 'c' && (fn[1] == 'a' || fn[1] == 'd') && 384 | fn[2] == 'r' && fn[3] == '\0') { 385 | Atom* e = eval(s->tail->head, val); 386 | 387 | if (e == NULL) 388 | return NULL; 389 | 390 | if (e->type != LIST || getListSize(s) != 2) 391 | ERROR("invalid car/cdr"); 392 | 393 | if (fn[1] == 'a') 394 | return e->list->head; 395 | else 396 | return createList(e->list->tail); 397 | } else if (op == 'c' && fn[1] == 'o' && fn[2] == 'n' && 398 | fn[3] == 's' && fn[4] == '\0') { 399 | if (getListSize(s) != 3) 400 | ERROR("invalid cons"); 401 | 402 | Atom* l = eval(s->tail->head, val); 403 | Atom* r = eval(s->tail->tail->head, val); 404 | 405 | if (r && r->type != LIST) 406 | ERROR("invalid cons"); 407 | 408 | return createList(cons(l, r ? r->list : NULL)); 409 | } else if (op == 'a' && fn[1] == 't' && fn[2] == 'o' && 410 | fn[3] == 'm' && fn[4] == '\0') { 411 | if (getListSize(s) != 2) 412 | ERROR("invalid atom"); 413 | 414 | Atom* e = eval(s->tail->head, val); 415 | 416 | if (atom(e)) 417 | return g_t; 418 | else 419 | return NULL; 420 | } else if (op == 'n' && fn[1] == 'e' && fn[2] == 'g' && 421 | fn[3] == '?' && fn[4] == '\0') { 422 | if (getListSize(s) != 2) 423 | ERROR("invalid neg?"); 424 | 425 | Atom* e = eval(s->tail->head, val); 426 | 427 | if (e->type == NUM && e->num < 0) 428 | return g_t; 429 | else 430 | return NULL; 431 | } else if (fn[0] == 'p' && fn[1] == 'r' && fn[2] == 'i' && 432 | fn[3] == 'n' && fn[4] == 't' && fn[5] == '\0') { 433 | if (getListSize(s) != 2) 434 | ERROR("invalid print"); 435 | 436 | Atom* e = eval(s->tail->head, val); 437 | printExpr(e); 438 | putchar('\n'); 439 | return e; 440 | } 441 | 442 | print_str(fn); 443 | putchar(':'); 444 | putchar(' '); 445 | ERROR("undefined function"); 446 | } 447 | 448 | ERROR("invalid function application"); 449 | return NULL; 450 | } 451 | -------------------------------------------------------------------------------- /purelisp.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | $vals = {} 4 | 5 | def parse_sexpr(s, orig) 6 | case s.strip 7 | when /^\(/ 8 | s = $' 9 | r = [] 10 | while s !~ /^\)/ 11 | raise "invalid sexpr: #{orig}" if s.empty? 12 | x, s = parse_sexpr(s, orig) 13 | r << x 14 | s.lstrip! 15 | end 16 | [r, $'] 17 | when /^-?\d+/ 18 | [$&.to_i, $'] 19 | when /^t\b/ 20 | [:t, $'] 21 | when /^nil\b/ 22 | [[], $'] 23 | when /^([^() ]+)/ 24 | [$1, $'] 25 | end 26 | end 27 | 28 | def atom?(sexpr) 29 | !sexpr.is_a?(Array) || sexpr == [] 30 | end 31 | 32 | def eval_sexpr(sexpr, vals) 33 | if atom?(sexpr) 34 | return vals[sexpr] || $vals[sexpr] || sexpr 35 | end 36 | 37 | op, *args = sexpr 38 | case op 39 | when 'if' 40 | raise "invalid if: #{stringify_sexpr(sexpr)}" if args.size != 3 41 | cond = eval_sexpr(args[0], vals) 42 | result = cond != [] ? eval_sexpr(args[1], vals) : eval_sexpr(args[2], vals) 43 | return result 44 | when 'defun' 45 | if (args.size != 3 || !args[0].is_a?(String) || !args[1].is_a?(Array) || 46 | !args[1].all?{|a|a.is_a?(String)}) 47 | raise "invalid defun: #{stringify_sexpr(sexpr)}" 48 | end 49 | $vals[args[0]] = {:args => args[1], :expr => args[2]} 50 | return args[0] 51 | when 'lambda' 52 | if (args.size != 2 || 53 | !args[0].is_a?(Array) || !args[0].all?{|a|a.is_a?(String)}) 54 | raise "invalid lambda: #{stringify_sexpr(sexpr)}" 55 | end 56 | return {:args => args[0], :expr => args[1]} 57 | when 'define' 58 | if args.size != 2 || !args[0].is_a?(String) 59 | raise "invalid define: #{stringify_sexpr(sexpr)}" 60 | end 61 | $vals[args[0]] = eval_sexpr(args[1], vals) 62 | return [] 63 | when 'quote' 64 | raise "invalid quote: #{stringify_sexpr(sexpr)}" if args.size != 1 65 | return args[0] 66 | end 67 | 68 | op = eval_sexpr(op, vals) 69 | args = args.map{|a|eval_sexpr(a, vals)} 70 | 71 | case op 72 | when Hash 73 | if op[:args].size != args.size 74 | raise "invalid number of args: #{stringify_sexpr(sexpr)}" 75 | end 76 | vals = {} 77 | op[:args].zip(args){|k, v|vals[k] = v} 78 | eval_sexpr(op[:expr], vals) 79 | when '+' 80 | raise "invalid add: #{stringify_sexpr(sexpr)}" if args.size != 2 81 | args[0] + args[1] 82 | when '-' 83 | raise "invalid sub: #{stringify_sexpr(sexpr)}" if args.size != 2 84 | args[0] - args[1] 85 | when '*' 86 | raise "invalid mul: #{stringify_sexpr(sexpr)}" if args.size != 2 87 | args[0] * args[1] 88 | when '/' 89 | raise "invalid div: #{stringify_sexpr(sexpr)}" if args.size != 2 90 | args[0] / args[1] 91 | when 'mod' 92 | raise "invalid mod: #{stringify_sexpr(sexpr)}" if args.size != 2 93 | args[0] % args[1] 94 | when 'eq' 95 | raise "invalid eq: #{stringify_sexpr(sexpr)}" if args.size != 2 96 | args[0] == args[1] ? :t : [] 97 | when 'car' 98 | if args.size != 1 || !args[0].is_a?(Array) 99 | raise "invalid car: #{stringify_sexpr(sexpr)}" 100 | end 101 | args[0][0] || [] 102 | when 'cdr' 103 | if args.size != 1 || !args[0].is_a?(Array) 104 | raise "invalid cdr: #{stringify_sexpr(sexpr)}" 105 | end 106 | args[0][1..-1] || [] 107 | when 'cons' 108 | if args.size != 2 || !args[1].is_a?(Array) 109 | raise "invalid cons: #{stringify_sexpr(sexpr)}" 110 | end 111 | [args[0]] + args[1] 112 | when 'atom' 113 | raise "invalid atom: #{stringify_sexpr(sexpr)}" if args.size != 1 114 | atom?(args[0]) ? :t : [] 115 | when 'neg?' 116 | raise "invalid neg?: #{stringify_sexpr(sexpr)}" if args.size != 1 117 | args[0] < 0 ? :t : [] 118 | when 'print' 119 | raise "invalid print: #{stringify_sexpr(sexpr)}" if args.size != 1 120 | puts "PRINT: #{stringify_sexpr(args[0])}" 121 | args[0] 122 | else 123 | raise "undefined function: #{op}" 124 | end 125 | end 126 | 127 | def stringify_sexpr(sexpr) 128 | if sexpr == [] 129 | 'nil' 130 | elsif sexpr == :t 131 | 't' 132 | elsif sexpr.is_a?(Array) 133 | '(' + sexpr.map{|s|stringify_sexpr(s)} * ' ' + ')' 134 | else 135 | sexpr.to_s 136 | end 137 | end 138 | 139 | $<.each do |line| 140 | line.sub!(/;.*/, '') 141 | next if line =~ /^$/ 142 | line.gsub!(/\s+/, ' ') 143 | sexpr, rest = parse_sexpr(line, line) 144 | raise "invalid sexpr: #{line}" if !rest.empty? 145 | puts stringify_sexpr(eval_sexpr(sexpr, {})) 146 | end 147 | -------------------------------------------------------------------------------- /sort.l: -------------------------------------------------------------------------------- 1 | (defun concat (a b) (if a (cons (car a) (concat (cdr a) b)) b)) 2 | (defun < (a b) (neg? (- a b))) 3 | (defun >= (a b) (if (< a b) nil t)) 4 | (defun filter-less1 (p h l) (if (< h p) (cons h l) l)) 5 | (defun filter-less (p l) (if l (filter-less1 p (car l) (filter-less p (cdr l))) nil)) 6 | (defun filter-more1 (p h l) (if (>= h p) (cons h l) l)) 7 | (defun filter-more (p l) (if l (filter-more1 p (car l) (filter-more p (cdr l))) nil)) 8 | (defun sort-1 (p l) (concat (sort (filter-less p l)) (cons p (sort (filter-more p l))))) 9 | (defun sort (l) (if l (sort-1 (car l) (cdr l)) nil)) 10 | 11 | (sort (quote (6 4 3 5 1 2 7))) 12 | -------------------------------------------------------------------------------- /test.l: -------------------------------------------------------------------------------- 1 | (+ 19 99) 2 | (+ 2 98) 3 | (+ 98 2 ) 4 | (+ 38 2 ) 5 | (+ -19 -99) 6 | 7 | (- 3 -17) 8 | (- -3 29) 9 | 10 | (- 10 10) 11 | (- -999 -999) 12 | 13 | (- 3 2) 14 | 15 | (- 1 3) 16 | 17 | (- 111 3) 18 | 19 | (- 100 3) 20 | 21 | (- 3 994) 22 | 23 | (+ 2 -3) 24 | 25 | (+ -2 3) 26 | (+ -9 2) 27 | (+ -2 9) 28 | 29 | 30 | (- -1 -3) 31 | (- -5 -3) 32 | 33 | (- 0 0) 34 | (- 0 0) 35 | 36 | (- 11 2) 37 | 38 | (- 8 9) 39 | 40 | ;(- 9 9) 41 | ;(- 9 0) 42 | ;(- 34 1) 43 | 44 | ;(- 34 7) 45 | 46 | ;(if 1 2 3) 47 | 1 48 | (+ 1(+ 1 1)) 49 | 50 | (+(- 9 2) 1) 51 | 52 | (- (- 9 2) (- 3 6)) 53 | 54 | (+ (+ (+ 1 2) 3) 4) 55 | (+ 1 (+ 2 (+ 3 4))) 56 | 57 | (eq 3 4) 58 | (eq 12 12) 59 | 60 | (if (eq 2 (+ 1 1)) (+ 3 4) (+ 4 2)) 61 | 62 | (if (eq 2 (+ 3 1)) (+ 3 4) (+ 2 4)) 63 | 64 | (if t 2 3) 65 | (if nil 2 3) 66 | 67 | (if (eq 4 2) 2 (+ (+ 4 1) 3)) 68 | 69 | (+ (if (eq 2 (+ 3 1)) (+ 3 4) (+ 2 4)) 4) 70 | (+ 4 (if (eq 2 (+ 3 1)) (+ 3 4) (+ 2 4))) 71 | 72 | (+ 3 (if (eq 4 4) (+ 2 (+ 3 2)) (+ 4 3))) 73 | (+ 3 (if (eq 4 2) (+ 2 (+ 3 2)) (+ (+ 4 1) 3))) 74 | 75 | (+ 3 (if t 2 3)) 76 | (+ 3 (if nil 2 3)) 77 | 78 | (- 3 (+ 3 (if (eq 4 2) (+ 2 (+ 3 2)) (- (+ 4 1) (+ 3 9))))) 79 | (if (eq (+ 1 2) (- 3 1)) (- (+ 2 3) (+ 3 9)) (+ (+ 2 3) (+ 3 9))) 80 | (if (eq (+ 1 2) (- 4 1)) (- (+ 2 3) (+ 3 9)) (+ (+ 2 3) (+ 3 9))) 81 | 82 | (defun f () 42) ;cont 83 | (f) 84 | (defun f () (+ 4 8)) ;cont 85 | (f) 86 | (defun f (n) (+ n n)) ;cont 87 | (f 42) 88 | 89 | (* 23 33) 90 | 91 | (/ 45 7) 92 | (mod 45 7) 93 | 94 | (quote ((1 2) (3 4))) 95 | (quote (())) 96 | 97 | () 98 | (car ()) 99 | (car nil) 100 | (car (quote ())) 101 | (car (quote (3))) 102 | (car (quote (42 99))) 103 | (car (quote ((42 99) (3 7)))) 104 | (car (quote ((42 (11 22) 99) (3 7)))) 105 | 106 | (cdr ()) 107 | (cdr nil) 108 | (cdr (quote ())) 109 | (cdr (quote (3))) 110 | (cdr (quote (42 99))) 111 | (cdr (quote ((42 99) (3 7)))) 112 | (cdr (quote ((42 (11 22) 99) (3 7)))) 113 | 114 | (cons 42 nil) 115 | (cons 42 ()) 116 | (cons nil nil) 117 | (cons 42 (quote ())) 118 | (cons 1 (quote (2))) 119 | (cons (quote (1 2)) (quote (3 ((5 6)) 4))) 120 | (cons 2 (cons 3 ())) 121 | 122 | (atom ()) 123 | (atom nil) 124 | (atom t) 125 | (atom 42) 126 | (atom (quote ())) 127 | (atom (quote (3))) 128 | (atom (quote (42 99))) 129 | (atom (quote ((42 99) (3 7)))) 130 | (atom (quote ((42 (11 22) 99) (3 7)))) 131 | 132 | ; TEST LAMBDA 133 | 134 | ((lambda (n) (+ 4 n)) 42) 135 | ((lambda (n m) (- m n)) 42 99) 136 | ((lambda (x) x) 42) 137 | 138 | (define foo 42) ;cont 139 | foo 140 | 141 | (define func (lambda (x y z) y)) ;cont 142 | (func 1 2 3) 143 | 144 | ((lambda (f) (f)) (lambda () 42)) 145 | 146 | (defun func (a b) b) ;cont 147 | (defun func2 (a b) (+ (func 2 3) b)) ;cont 148 | (func2 99 42) 149 | 150 | ; TEST EVAL 151 | 152 | (defmacro let (l e) (cons (cons lambda (cons (cons (car l) nil) (cons e nil))) (cons (car (cdr l)) nil))) ;cont 153 | (let (x 42) (+ x 7)) 154 | 155 | (defun list0 (a) (cons a nil)) ;cont 156 | (defun cadr (a) (car (cdr a))) ;cont 157 | (defmacro cond (l) (if l (cons if (cons (car (car l)) (cons (cadr (car l)) (cons (cons (quote cond) (list0 (cdr l))))))) nil)) ;cont 158 | (defun fb (n) (cond (((eq (mod n 5) 0) Buzz) ((eq (mod n 3) 0) Fizz) (t n)))) ;cont 159 | (fb 18) 160 | -------------------------------------------------------------------------------- /test.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require './evalify' 4 | 5 | $evalify = false 6 | if ARGV[0] == '-e' 7 | $evalify = true 8 | ARGV.shift 9 | elsif ARGV[0] == '-E' 10 | $evalify = true 11 | $eval_test_only = true 12 | ARGV.shift 13 | end 14 | 15 | ref_lisp = ARGV[0] || 'purelisp.rb' 16 | test_lisp = ARGV[1] 17 | test_lisp ||= File.exist?('sedlisp.sed') ? 'sedlisp.sed' : 'beflisp.bef' 18 | 19 | COMMANDS = { 20 | 'purelisp.rb' => ['ruby', 'purelisp.rb'], 21 | 'rblisp.rb' => ['ruby', 'rblisp.rb'], 22 | 'sedlisp.sed' => ['sed', '-f', 'sedlisp.sed'], 23 | 'lisp.bef' => ['./befunge', 'lisp.bef'], 24 | 'beflisp.bef' => ['./befunge', 'beflisp.bef'], 25 | 'lisp' => ['./lisp'], 26 | 'makelisp.mk' => ['make', '-f', 'makelisp.mk'], 27 | 'makelisp2.mk' => ['make', '-f', 'makelisp2.mk'], 28 | } 29 | 30 | def getResult(cmd, line) 31 | pipe = IO.popen(cmd, 'r+') 32 | pipe.puts(line) 33 | pipe.close_write 34 | o = pipe.read 35 | if cmd[-1] == 'rblisp.rb' 36 | o.gsub!(/^> /, '') 37 | end 38 | o 39 | end 40 | 41 | num_tests = 0 42 | fails = [] 43 | 44 | lines = File.readlines('test.l') 45 | lineno = -1 46 | while line = lines[lineno += 1] 47 | if line.sub(/;.*/, '') =~ /^ *$/ 48 | if (/TEST LAMBDA/ =~ line && 49 | (ref_lisp == 'rblisp.rb' || test_lisp == 'rblisp.rb')) 50 | break 51 | elsif /TEST EVAL/ =~ line 52 | $eval_test = true 53 | if !$evalify 54 | break 55 | end 56 | end 57 | next 58 | end 59 | 60 | next if !$eval_test && $eval_test_only 61 | 62 | while line =~ /;cont/ 63 | line.sub!(/;cont/, '') 64 | line += lines[lineno += 1] 65 | end 66 | line.chomp! 67 | orig = line 68 | if $evalify 69 | line = evalify(line) 70 | end 71 | 72 | expected = getResult(COMMANDS[ref_lisp], $eval_test ? line : orig) 73 | expected = expected.lines.to_a[-1].to_s.chomp 74 | output = getResult(COMMANDS[test_lisp], line) 75 | actual = output.lines.to_a[-1].to_s.chomp 76 | 77 | if expected == actual 78 | puts "#{orig}: OK (#{expected})" 79 | else 80 | puts "#{orig}: FAIL expected=#{expected} actual=#{actual}" 81 | puts output 82 | fails << orig 83 | end 84 | num_tests += 1 85 | end 86 | 87 | if fails.empty? 88 | puts 'PASS' 89 | else 90 | puts "Failed tests:" 91 | puts fails.map{|f|f.inspect} 92 | puts "#{fails.size} / #{num_tests} FAIL" 93 | end 94 | -------------------------------------------------------------------------------- /test/cmp_eq.bef: -------------------------------------------------------------------------------- 1 | 89*9*9*9*00p89*9*9*9*9*10p89*9*9*9*20p0v 2 | v < < 3 | *** main *** 0 4 | block 0 5 | %1 = alloca i32, align 4 6 | %c = alloca i32, align 4 7 | store i32 0, i32* %1 8 | %2 = call i32 @getchar() #2 9 | store i32 %2, i32* %c, align 4 10 | %3 = load i32* %c, align 4 11 | %4 = icmp eq i32 %3, 65 12 | br i1 %4, label %5, label %7 13 | >:#v_ >$ 00g:1+00p51p 00g:1+00p60p 051g:9%9+\9/p #@~70p 70g60g:9%9+\9/p 60g:9v 14 | v-1<> 1+^ v!`0:-0 $_\# 0#!:#v_ >$ 19*9*7+,051p 3 1-:0`!v 20 | v-1<> 1+^ 21 | v ^_^#:< _1- 22 | block 2 23 | %8 = call i32 @putchar(i32 89) #2 24 | br label %9 25 | >:#v_ >$ 19*9*8+,051p 3 2-:0`!v 26 | v-1<> 1+^ 27 | v ^_^#:< _1- 28 | block 3 29 | ret i32 0 30 | >:#v_ >$ 00g2-00p@ 3-:0`!v 31 | v-1<> 1+^ 32 | v ^_^#:< _1- 33 | -------------------------------------------------------------------------------- /test/cmp_eq.c: -------------------------------------------------------------------------------- 1 | int getchar(void); 2 | int putchar(int c); 3 | 4 | int main() { 5 | int c = getchar(); 6 | if (c == 'A') 7 | putchar('X'); 8 | else 9 | putchar('Y'); 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /test/cmp_eq_1.in: -------------------------------------------------------------------------------- 1 | 0 -------------------------------------------------------------------------------- /test/cmp_eq_2.in: -------------------------------------------------------------------------------- 1 | X -------------------------------------------------------------------------------- /test/cmp_eq_3.in: -------------------------------------------------------------------------------- 1 | A -------------------------------------------------------------------------------- /test/cmp_ge.bef: -------------------------------------------------------------------------------- 1 | 89*9*9*9*00p89*9*9*9*9*10p89*9*9*9*20p0v 2 | v < < 3 | *** main *** 0 4 | block 0 5 | %1 = alloca i32, align 4 6 | %c = alloca i32, align 4 7 | store i32 0, i32* %1 8 | %2 = call i32 @getchar() #2 9 | store i32 %2, i32* %c, align 4 10 | %3 = load i32* %c, align 4 11 | %4 = icmp sge i32 %3, 65 12 | br i1 %4, label %5, label %7 13 | >:#v_ >$ 00g:1+00p51p 00g:1+00p60p 051g:9%9+\9/p #@~70p 70g60g:9%9+\9/p 60g:9v 14 | v-1<> 1+^ v!`0:-0 $_\# 0#!:#v_ >$ 19*9*7+,051p 3 1-:0`!v 20 | v-1<> 1+^ 21 | v ^_^#:< _1- 22 | block 2 23 | %8 = call i32 @putchar(i32 89) #2 24 | br label %9 25 | >:#v_ >$ 19*9*8+,051p 3 2-:0`!v 26 | v-1<> 1+^ 27 | v ^_^#:< _1- 28 | block 3 29 | ret i32 0 30 | >:#v_ >$ 00g2-00p@ 3-:0`!v 31 | v-1<> 1+^ 32 | v ^_^#:< _1- 33 | -------------------------------------------------------------------------------- /test/cmp_ge.c: -------------------------------------------------------------------------------- 1 | int getchar(void); 2 | int putchar(int c); 3 | 4 | int main() { 5 | int c = getchar(); 6 | if (c >= 'A') 7 | putchar('X'); 8 | else 9 | putchar('Y'); 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /test/cmp_ge_1.in: -------------------------------------------------------------------------------- 1 | 0 -------------------------------------------------------------------------------- /test/cmp_ge_2.in: -------------------------------------------------------------------------------- 1 | X -------------------------------------------------------------------------------- /test/cmp_ge_3.in: -------------------------------------------------------------------------------- 1 | A -------------------------------------------------------------------------------- /test/cmp_gt.bef: -------------------------------------------------------------------------------- 1 | 89*9*9*9*00p89*9*9*9*9*10p89*9*9*9*20p0v 2 | v < < 3 | *** main *** 0 4 | block 0 5 | %1 = alloca i32, align 4 6 | %c = alloca i32, align 4 7 | store i32 0, i32* %1 8 | %2 = call i32 @getchar() #2 9 | store i32 %2, i32* %c, align 4 10 | %3 = load i32* %c, align 4 11 | %4 = icmp sgt i32 %3, 65 12 | br i1 %4, label %5, label %7 13 | >:#v_ >$ 00g:1+00p51p 00g:1+00p60p 051g:9%9+\9/p #@~70p 70g60g:9%9+\9/p 60g:9v 14 | v-1<> 1+^ v!`0:-0 $_\# 0#!:#v_ >$ 19*9*7+,051p 3 1-:0`!v 20 | v-1<> 1+^ 21 | v ^_^#:< _1- 22 | block 2 23 | %8 = call i32 @putchar(i32 89) #2 24 | br label %9 25 | >:#v_ >$ 19*9*8+,051p 3 2-:0`!v 26 | v-1<> 1+^ 27 | v ^_^#:< _1- 28 | block 3 29 | ret i32 0 30 | >:#v_ >$ 00g2-00p@ 3-:0`!v 31 | v-1<> 1+^ 32 | v ^_^#:< _1- 33 | -------------------------------------------------------------------------------- /test/cmp_gt.c: -------------------------------------------------------------------------------- 1 | int getchar(void); 2 | int putchar(int c); 3 | 4 | int main() { 5 | int c = getchar(); 6 | if (c > 'A') 7 | putchar('X'); 8 | else 9 | putchar('Y'); 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /test/cmp_gt_1.in: -------------------------------------------------------------------------------- 1 | 0 -------------------------------------------------------------------------------- /test/cmp_gt_2.in: -------------------------------------------------------------------------------- 1 | X -------------------------------------------------------------------------------- /test/cmp_gt_3.in: -------------------------------------------------------------------------------- 1 | A -------------------------------------------------------------------------------- /test/cmp_le.bef: -------------------------------------------------------------------------------- 1 | 89*9*9*9*00p89*9*9*9*9*10p89*9*9*9*20p0v 2 | v < < 3 | *** main *** 0 4 | block 0 5 | %1 = alloca i32, align 4 6 | %c = alloca i32, align 4 7 | store i32 0, i32* %1 8 | %2 = call i32 @getchar() #2 9 | store i32 %2, i32* %c, align 4 10 | %3 = load i32* %c, align 4 11 | %4 = icmp sle i32 %3, 65 12 | br i1 %4, label %5, label %7 13 | >:#v_ >$ 00g:1+00p51p 00g:1+00p60p 051g:9%9+\9/p #@~70p 70g60g:9%9+\9/p 60g:9v 14 | v-1<> 1+^ v!`0:-0 $_\# 0#!:#v_ >$ 19*9*7+,051p 3 1-:0`!v 20 | v-1<> 1+^ 21 | v ^_^#:< _1- 22 | block 2 23 | %8 = call i32 @putchar(i32 89) #2 24 | br label %9 25 | >:#v_ >$ 19*9*8+,051p 3 2-:0`!v 26 | v-1<> 1+^ 27 | v ^_^#:< _1- 28 | block 3 29 | ret i32 0 30 | >:#v_ >$ 00g2-00p@ 3-:0`!v 31 | v-1<> 1+^ 32 | v ^_^#:< _1- 33 | -------------------------------------------------------------------------------- /test/cmp_le.c: -------------------------------------------------------------------------------- 1 | int getchar(void); 2 | int putchar(int c); 3 | 4 | int main() { 5 | int c = getchar(); 6 | if (c <= 'A') 7 | putchar('X'); 8 | else 9 | putchar('Y'); 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /test/cmp_le_1.in: -------------------------------------------------------------------------------- 1 | 0 -------------------------------------------------------------------------------- /test/cmp_le_2.in: -------------------------------------------------------------------------------- 1 | X -------------------------------------------------------------------------------- /test/cmp_le_3.in: -------------------------------------------------------------------------------- 1 | A -------------------------------------------------------------------------------- /test/cmp_lt.bef: -------------------------------------------------------------------------------- 1 | 89*9*9*9*00p89*9*9*9*9*10p89*9*9*9*20p0v 2 | v < < 3 | *** main *** 0 4 | block 0 5 | %1 = alloca i32, align 4 6 | %c = alloca i32, align 4 7 | store i32 0, i32* %1 8 | %2 = call i32 @getchar() #2 9 | store i32 %2, i32* %c, align 4 10 | %3 = load i32* %c, align 4 11 | %4 = icmp slt i32 %3, 65 12 | br i1 %4, label %5, label %7 13 | >:#v_ >$ 00g:1+00p51p 00g:1+00p60p 051g:9%9+\9/p #@~70p 70g60g:9%9+\9/p 60g:9v 14 | v-1<> 1+^ v!`0:-0 $_\# 0#!:#v_ >$ 19*9*7+,051p 3 1-:0`!v 20 | v-1<> 1+^ 21 | v ^_^#:< _1- 22 | block 2 23 | %8 = call i32 @putchar(i32 89) #2 24 | br label %9 25 | >:#v_ >$ 19*9*8+,051p 3 2-:0`!v 26 | v-1<> 1+^ 27 | v ^_^#:< _1- 28 | block 3 29 | ret i32 0 30 | >:#v_ >$ 00g2-00p@ 3-:0`!v 31 | v-1<> 1+^ 32 | v ^_^#:< _1- 33 | -------------------------------------------------------------------------------- /test/cmp_lt.c: -------------------------------------------------------------------------------- 1 | int getchar(void); 2 | int putchar(int c); 3 | 4 | int main() { 5 | int c = getchar(); 6 | if (c < 'A') 7 | putchar('X'); 8 | else 9 | putchar('Y'); 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /test/cmp_lt_1.in: -------------------------------------------------------------------------------- 1 | 0 -------------------------------------------------------------------------------- /test/cmp_lt_2.in: -------------------------------------------------------------------------------- 1 | X -------------------------------------------------------------------------------- /test/cmp_lt_3.in: -------------------------------------------------------------------------------- 1 | A -------------------------------------------------------------------------------- /test/cmp_ne.bef: -------------------------------------------------------------------------------- 1 | 89*9*9*9*00p89*9*9*9*9*10p89*9*9*9*20p0v 2 | v < < 3 | *** main *** 0 4 | block 0 5 | %1 = alloca i32, align 4 6 | %c = alloca i32, align 4 7 | store i32 0, i32* %1 8 | %2 = call i32 @getchar() #2 9 | store i32 %2, i32* %c, align 4 10 | %3 = load i32* %c, align 4 11 | %4 = icmp ne i32 %3, 65 12 | br i1 %4, label %5, label %7 13 | >:#v_ >$ 00g:1+00p51p 00g:1+00p60p 051g:9%9+\9/p #@~70p 70g60g:9%9+\9/p 60g:9v 14 | v-1<> 1+^ v!`0:-0 $_\# 0#!:#v_ >$ 19*9*7+,051p 3 1-:0`!v 20 | v-1<> 1+^ 21 | v ^_^#:< _1- 22 | block 2 23 | %8 = call i32 @putchar(i32 89) #2 24 | br label %9 25 | >:#v_ >$ 19*9*8+,051p 3 2-:0`!v 26 | v-1<> 1+^ 27 | v ^_^#:< _1- 28 | block 3 29 | ret i32 0 30 | >:#v_ >$ 00g2-00p@ 3-:0`!v 31 | v-1<> 1+^ 32 | v ^_^#:< _1- 33 | -------------------------------------------------------------------------------- /test/cmp_ne.c: -------------------------------------------------------------------------------- 1 | int getchar(void); 2 | int putchar(int c); 3 | 4 | int main() { 5 | int c = getchar(); 6 | if (c != 'A') 7 | putchar('X'); 8 | else 9 | putchar('Y'); 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /test/cmp_ne_1.in: -------------------------------------------------------------------------------- 1 | 0 -------------------------------------------------------------------------------- /test/cmp_ne_2.in: -------------------------------------------------------------------------------- 1 | X -------------------------------------------------------------------------------- /test/cmp_ne_3.in: -------------------------------------------------------------------------------- 1 | A -------------------------------------------------------------------------------- /test/fizzbuzz.bef: -------------------------------------------------------------------------------- 1 | 89*9*9*9*00p89*9*9*9*9*10p89*9*9*9*20p0v 2 | v < < 3 | *** main *** 0 4 | block 0 5 | %1 = alloca i32, align 4 6 | %i = alloca i32, align 4 7 | %done = alloca i32, align 4 8 | store i32 0, i32* %1 9 | store i32 1, i32* %i, align 4 10 | br label %2 11 | >:#v_ >$ 00g:1+00p51p 00g:1+00p20g0+:9%\9/p 00g:1+00p20g1+:9%\9/p 051g:9%9+\9v 12 | v-1<> 1+^ v!`0:-0 1 p/9\+9%9:g/9\%9:+0g021 p/< 13 | v ^_^#:< _1- 14 | block 1 15 | %3 = load i32* %i, align 4 16 | %4 = icmp sle i32 %3, 100 17 | br i1 %4, label %5, label %33 18 | >:#v_ >$ 20g0+:9%\9/g:9%9+\9/g51p 51g19*2+9*1+`!60p 19*2+260gv 19 | v-1<> 1+^ v!`0:-1 $_\# 0#!<< 20 | v ^_^#:< _1- 21 | block 2 22 | store i32 0, i32* %done, align 4 23 | %6 = load i32* %i, align 4 24 | %7 = srem i32 %6, 3 25 | %8 = icmp eq i32 %7, 0 26 | br i1 %8, label %9, label %14 27 | >:#v_ >$ 020g1+:9%\9/g:9%9+\9/p 20g0+:9%\9/g:9%9+\9/g60p 60g3%61p 61g0-!70p 4v 28 | v-1<> 1+^ v!`0:-2 $_\# 0#!:#v_ >$ 79*7+,051p 19*2+9*6+,060p 19*4+9*5+,061p 19*4+9*5+,070p 120g1+:9%\9/v 38 | v-1<> 1+^ v!`0:-3 4 p/9\+9%9:g< 39 | v ^_^#:< _1- 40 | block 4 41 | %15 = load i32* %i, align 4 42 | %16 = srem i32 %15, 5 43 | %17 = icmp eq i32 %16, 0 44 | br i1 %17, label %18, label %23 45 | >:#v_ >$ 20g0+:9%\9/g:9%9+\9/g51p 51g5%60p 60g0-!61p 6561g> #0 #\_$ 4-:0`!v 46 | v-1<> 1+^ 47 | v ^_^#:< _1- 48 | block 5 49 | %19 = call i32 @putchar(i32 66) #3 50 | %20 = call i32 @putchar(i32 117) #3 51 | %21 = call i32 @putchar(i32 122) #3 52 | %22 = call i32 @putchar(i32 122) #3 53 | store i32 1, i32* %done, align 4 54 | br label %23 55 | >:#v_ >$ 79*3+,051p 19*4+9*,060p 19*4+9*5+,061p 19*4+9*5+,070p 120g1+:9%\9/g:v 56 | v-1<> 1+^ v!`0:-5 6 p/9\+9%9< 57 | v ^_^#:< _1- 58 | block 6 59 | %24 = load i32* %done, align 4 60 | %25 = icmp ne i32 %24, 0 61 | br i1 %25, label %28, label %26 62 | >:#v_ >$ 20g1+:9%\9/g:9%9+\9/g51p 51g0-!!60p 719*60g> #0 #\_$ 6-:0`!v 63 | v-1<> 1+^ 64 | v ^_^#:< _1- 65 | block 7 66 | %27 = load i32* %i, align 4 67 | call void @print_int(i32 %27) #3 68 | br label %28 69 | >:#v_ >$ 20g0+:9%\9/g:9%9+\9/g51p 851g26*20g2+20p7-:0`!v 70 | v-1<> 1+^ 71 | v ^_^#:< _1- 72 | >:#v_ >$ 20g2-20p60p 19* 8-:0`!v 73 | v-1<> 1+^ 74 | v ^_^#:< _1- 75 | block 9 76 | %29 = call i32 @putchar(i32 10) #3 77 | br label %30 78 | >:#v_ >$ 25*,051p 25* 19*-:0`!v 79 | v-1<> 1+^ 80 | v ^_^#:< _1- 81 | block 10 82 | %31 = load i32* %i, align 4 83 | %32 = add nsw i32 %31, 1 84 | store i32 %32, i32* %i, align 4 85 | br label %2 86 | >:#v_ >$ 20g0+:9%\9/g:9%9+\9/g51p 51g1+60p 60g20g0+:9%\9/g:9%9+\9/p 1 25*-:0`v 87 | v-1<> 1+^ v !< 88 | v ^_^#:< _1- 89 | block 11 90 | ret i32 0 91 | >:#v_ >$ 00g3-00p@ 19*2+-:0`!v 92 | v-1<> 1+^ 93 | v ^_^#:< _1- 94 | *** print_int *** 12 95 | block 12 96 | %1 = alloca i32, align 4 97 | %buf = alloca [16 x i32], align 4 98 | %n = alloca i32, align 4 99 | store i32 %v, i32* %1, align 4 100 | %2 = load i32* %1, align 4 101 | %3 = icmp slt i32 %2, 0 102 | br i1 %3, label %4, label %8 103 | >:#v_ >$ 20g0+:9%\9/p00g:1+00p20g1+:9%\9/p 00g:28*+00p20g2+:9%\9/p 00g:1+00p2v 104 | v-1<> 1+^vg/9\+9%9:g/9\%9:+1g02 p/9\+9%9:g/9\%9:+1g02g/9\%9:+0g02 p/9\%9:+3g0< 105 | v ^_^#:<>60p 060g`61p 27*19*4+61g> #0 #\_$ 26*-:0`!v 106 | v ^ _1- 107 | block 13 108 | %5 = call i32 @putchar(i32 45) #3 109 | %6 = load i32* %1, align 4 110 | %7 = sub nsw i32 0, %6 111 | store i32 %7, i32* %1, align 4 112 | br label %8 113 | >:#v_ >$ 59*,051p 20g1+:9%\9/g:9%9+\9/g60p 060g-61p 61g20g1+:9%\9/g:9%9+\9/p v 114 | v-1<> 1+^ v!`0:-+4*91 *72< 115 | v ^_^#:< _1- 116 | block 14 117 | store i32 0, i32* %n, align 4 118 | br label %9 119 | >:#v_ >$ 020g3+:9%\9/g:9%9+\9/p 35* 27*-:0`!v 120 | v-1<> 1+^ 121 | v ^_^#:< _1- 122 | block 15 123 | %10 = load i32* %1, align 4 124 | %11 = srem i32 %10, 10 125 | %12 = load i32* %n, align 4 126 | %13 = getelementptr inbounds [16 x i32]* %buf, i32 0, i32 %12 127 | store i32 %11, i32* %13, align 4 128 | %14 = load i32* %1, align 4 129 | %15 = sdiv i32 %14, 10 130 | store i32 %15, i32* %1, align 4 131 | %16 = load i32* %n, align 4 132 | %17 = add nsw i32 %16, 1 133 | store i32 %17, i32* %n, align 4 134 | br label %18 135 | >:#v_ >$ 20g1+:9%\9/g:9%9+\9/g51p 51g25*%60p 20g3+:9%\9/g:9%9+\9/g61p 20g2+:9v 136 | v-1<> 1+^v p18/*52g08 p08g/9\+9%9:g/9\%9:+1g02 p/9\+9%9:g07g06 p07+g16+0g/9\%< 137 | v ^_^#:<>81g20g1+:9%\9/g:9%9+\9/p 20g3+:9%\9/g:9%9+\9/g19*1p 19*1g1+25*0p 25v 138 | v!`0:-*53 *82 p/9\+9%9:g/9\%9:+3g02g0*< 139 | v ^ _1- 140 | block 16 141 | %19 = load i32* %1, align 4 142 | %20 = icmp ne i32 %19, 0 143 | br i1 %20, label %9, label %21 144 | >:#v_ >$ 20g1+:9%\9/g:9%9+\9/g51p 51g0-!!60p 19*8+35*60g> #0 #\_$ 28*-:0`!v 145 | v-1<> 1+^ 146 | v ^_^#:< _1- 147 | block 17 148 | br label %22 149 | >:#v_ >$ 29* 19*8+-:0`!v 150 | v-1<> 1+^ 151 | v ^_^#:< _1- 152 | block 18 153 | %23 = load i32* %n, align 4 154 | %24 = add nsw i32 %23, -1 155 | store i32 %24, i32* %n, align 4 156 | %25 = icmp ne i32 %23, 0 157 | br i1 %25, label %26, label %32 158 | >:#v_ >$ 20g3+:9%\9/g:9%9+\9/g51p 51g01-+60p 60g20g3+:9%\9/g:9%9+\9/p 51g0-!!v 159 | v-1<> 1+^ v!`0:-*92 $_\# 0#!:#v_ >$ 20g3+:9%\9/g:9%9+\9/g51p 20g2+:9%\9/g0+51g+60p 60g:9%9+\9/g61p 61g68v 169 | v-1<> 1+^ v!`0:-+1*92 *92 p170,g07 p07+*< 170 | v ^_^#:< _1- 171 | block 20 172 | ret void 173 | >:#v_ >$ 00g29*-00p0\ 45*-:0`!v 174 | v-1<> 1+^ 175 | v ^_^#:< _1- 176 | -------------------------------------------------------------------------------- /test/fizzbuzz.c: -------------------------------------------------------------------------------- 1 | #include "libef.h" 2 | 3 | int main() { 4 | int i; 5 | for (i = 1; i <= 100; i++) { 6 | int done = 0; 7 | if (i % 3 == 0) { 8 | putchar('F'); 9 | putchar('i'); 10 | putchar('z'); 11 | putchar('z'); 12 | done = 1; 13 | } 14 | if (i % 5 == 0) { 15 | putchar('B'); 16 | putchar('u'); 17 | putchar('z'); 18 | putchar('z'); 19 | done = 1; 20 | } 21 | 22 | if (!done) 23 | print_int(i); 24 | putchar('\n'); 25 | } 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /test/func.bef: -------------------------------------------------------------------------------- 1 | 89*9*9*9*00p89*9*9*9*9*10p89*9*9*9*20p0v 2 | v < < 3 | *** main *** 0 4 | block 0 5 | %1 = alloca i32, align 4 6 | %c = alloca i32, align 4 7 | store i32 0, i32* %1 8 | br label %2 9 | >:#v_ >$ 00g:1+00p51p 00g:1+00p20g0+:9%\9/p 051g:9%9+\9/p 1 0-:0`!v 10 | v-1<> 1+^ 11 | v ^_^#:< _1- 12 | block 1 13 | %3 = call i32 @getchar() #3 14 | store i32 %3, i32* %c, align 4 15 | %4 = load i32* %c, align 4 16 | %5 = icmp eq i32 %4, -1 17 | br i1 %5, label %6, label %7 18 | >:#v_ >$ #@~51p 51g20g0+:9%\9/g:9%9+\9/p 20g0+:9%\9/g:9%9+\9/g61p 61g01--!70pv 19 | v-1<> 1+^ v!`0:-1 $_\# 0#!:#v_ >$ 5 2-:0`!v 24 | v-1<> 1+^ 25 | v ^_^#:< _1- 26 | block 3 27 | %8 = load i32* %c, align 4 28 | %9 = call i32 @swap(i32 %8) #3 29 | %10 = call i32 @putchar(i32 %9) #3 30 | br label %2 31 | >:#v_ >$ 20g0+:9%\9/g:9%9+\9/g51p 451g620g2+20p3-:0`!v 32 | v-1<> 1+^ 33 | v ^_^#:< _1- 34 | >:#v_ >$ 20g2-20p20g1+:9%\9/p 20g1+:9%\9/g,060p 1 4-:0`!v 35 | v-1<> 1+^ 36 | v ^_^#:< _1- 37 | block 5 38 | ret i32 0 39 | >:#v_ >$ 00g2-00p@ 5-:0`!v 40 | v-1<> 1+^ 41 | v ^_^#:< _1- 42 | *** swap *** 6 43 | block 6 44 | %1 = alloca i32, align 4 45 | %2 = alloca i32, align 4 46 | store i32 %c, i32* %2, align 4 47 | %3 = load i32* %2, align 4 48 | %4 = icmp sge i32 %3, 65 49 | br i1 %4, label %5, label %11 50 | >:#v_ >$ 20g0+:9%\9/p00g:1+00p20g1+:9%\9/p 00g:1+00p20g2+:9%\9/p 20g0+:9%\9/gv 51 | v-1<> 1+^v167*91 p16!`g06+2*97 p06g/9\+9%9:g/9\%9:+2g02 p/9\+9%9:g/9\%9:+2g02< 52 | v ^_^#:<>g> #0 #\_$ 6-:0`!v 53 | v ^ _1- 54 | block 7 55 | %6 = load i32* %2, align 4 56 | %7 = icmp sle i32 %6, 90 57 | br i1 %7, label %8, label %11 58 | >:#v_ >$ 20g2+:9%\9/g:9%9+\9/g51p 51g19*1+9*`!60p 19*860g> #0 #\_$ 7-:0`!v 59 | v-1<> 1+^ 60 | v ^_^#:< _1- 61 | block 8 62 | %9 = load i32* %2, align 4 63 | %10 = add nsw i32 %9, 32 64 | store i32 %10, i32* %1 65 | br label %23 66 | >:#v_ >$ 20g2+:9%\9/g:9%9+\9/g51p 51g48*+60p 60g20g1+:9%\9/g:9%9+\9/p 27* 8-:v 67 | v-1<> 1+^ v!`0< 68 | v ^_^#:< _1- 69 | block 9 70 | %12 = load i32* %2, align 4 71 | %13 = icmp sge i32 %12, 97 72 | br i1 %13, label %14, label %20 73 | >:#v_ >$ 20g2+:9%\9/g:9%9+\9/g51p 19*1+9*7+51g`!60p 26*25*60gv 74 | v-1<> 1+^ v!`0:-*91 $_\# 0#!<< 75 | v ^_^#:< _1- 76 | block 10 77 | %15 = load i32* %2, align 4 78 | %16 = icmp sle i32 %15, 122 79 | br i1 %16, label %17, label %20 80 | >:#v_ >$ 20g2+:9%\9/g:9%9+\9/g51p 51g19*4+9*5+`!60p 26*19*2+60gv 81 | v-1<> 1+^ v!`0:-*52 $_\# 0#!<< 82 | v ^_^#:< _1- 83 | block 11 84 | %18 = load i32* %2, align 4 85 | %19 = sub nsw i32 %18, 32 86 | store i32 %19, i32* %1 87 | br label %23 88 | >:#v_ >$ 20g2+:9%\9/g:9%9+\9/g51p 51g48*-60p 60g20g1+:9%\9/g:9%9+\9/p 27* 19*v 89 | v-1<> 1+^ v!`0:-+2< 90 | v ^_^#:< _1- 91 | block 12 92 | br label %21 93 | >:#v_ >$ 19*4+ 26*-:0`!v 94 | v-1<> 1+^ 95 | v ^_^#:< _1- 96 | block 13 97 | %22 = load i32* %2, align 4 98 | store i32 %22, i32* %1 99 | br label %23 100 | >:#v_ >$ 20g2+:9%\9/g:9%9+\9/g51p 51g20g1+:9%\9/g:9%9+\9/p 27* 19*4+-:0`!v 101 | v-1<> 1+^ 102 | v ^_^#:< _1- 103 | block 14 104 | %24 = load i32* %1 105 | ret i32 %24 106 | >:#v_ >$ 20g1+:9%\9/g:9%9+\9/g51p 00g2-00p51g\ 27*-:0`!v 107 | v-1<> 1+^ 108 | v ^_^#:< _1- 109 | -------------------------------------------------------------------------------- /test/func.c: -------------------------------------------------------------------------------- 1 | int getchar(void); 2 | int putchar(int c); 3 | int swap(int c) __attribute__((noinline)); 4 | 5 | int main() { 6 | while (1) { 7 | int c = getchar(); 8 | if (c == -1) 9 | break; 10 | putchar(swap(c)); 11 | } 12 | return 0; 13 | } 14 | 15 | int swap(int c) { 16 | if (c >= 'A' && c <= 'Z') { 17 | return c + 32; 18 | } else if (c >= 'a' && c <= 'z') { 19 | return c - 32; 20 | } 21 | return c; 22 | } 23 | -------------------------------------------------------------------------------- /test/func.in: -------------------------------------------------------------------------------- 1 | 09ANZ_az~ 2 | -------------------------------------------------------------------------------- /test/global.bef: -------------------------------------------------------------------------------- 1 | 89*9*9*9*00p89*9*9*9*9*10p89*9*9*9*20p157*69*9*9*9*9*:9%9+\9/pv 2 | v < < 3 | *** foo *** 0 4 | block 0 5 | %1 = load i32* @global, align 4 6 | %2 = add nsw i32 %1, 34 7 | store i32 %2, i32* @global, align 4 8 | ret void 9 | >:#v_ >$ 69*9*9*9*9*:9%9+\9/g51p 51g39*7++60p 60g69*9*9*9*9*:9%9+\9/p 0\ 0-:0v 10 | v-1<> 1+^ v!`< 11 | v ^_^#:< _1- 12 | *** main *** 1 13 | block 1 14 | %1 = alloca i32, align 4 15 | store i32 0, i32* %1 16 | %2 = load i32* @global, align 4 17 | %3 = call i32 @putchar(i32 %2) #2 18 | call void @foo() #2 19 | %4 = load i32* @global, align 4 20 | %5 = call i32 @putchar(i32 %4) #2 21 | ret i32 0 22 | >:#v_ >$ 00g:1+00p51p 051g:9%9+\9/p 69*9*9*9*9*:9%9+\9/g61p 61g,070p 2020g0+2v 23 | v-1<> 1+^ v!`0:-1p0< 24 | v ^_^#:< _1- 25 | >:#v_ >$ 20g0-20p71p 69*9*9*9*9*:9%9+\9/g80p 80g,081p 00g1-00p@ 2-:0`!v 26 | v-1<> 1+^ 27 | v ^_^#:< _1- 28 | -------------------------------------------------------------------------------- /test/global.c: -------------------------------------------------------------------------------- 1 | #include "libef.h" 2 | 3 | int global = 35; 4 | 5 | void foo() { 6 | global += 34; 7 | } 8 | 9 | int main() { 10 | putchar(global); 11 | foo(); 12 | putchar(global); 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /test/hello.c: -------------------------------------------------------------------------------- 1 | #include "libef.h" 2 | 3 | int main() { 4 | const char* p = "Hello, world!\n"; 5 | for (; *p; p++) 6 | putchar(*p); 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /test/loop.bef: -------------------------------------------------------------------------------- 1 | 89*9*9*9*00p89*9*9*9*9*10p89*9*9*9*20p0v 2 | v < < 3 | *** main *** 0 4 | block 0 5 | %1 = alloca i32, align 4 6 | %c = alloca i32, align 4 7 | store i32 0, i32* %1 8 | br label %2 9 | >:#v_ >$ 00g:1+00p51p 00g:1+00p20g0+:9%\9/p 051g:9%9+\9/p 1 0-:0`!v 10 | v-1<> 1+^ 11 | v ^_^#:< _1- 12 | block 1 13 | %3 = call i32 @getchar() #2 14 | store i32 %3, i32* %c, align 4 15 | %4 = load i32* %c, align 4 16 | %5 = icmp eq i32 %4, -1 17 | br i1 %5, label %6, label %7 18 | >:#v_ >$ #@~51p 51g20g0+:9%\9/g:9%9+\9/p 20g0+:9%\9/g:9%9+\9/g61p 61g01--!70pv 19 | v-1<> 1+^ v!`0:-1 $_\# 0#!:#v_ >$ 19*2+ 2-:0`!v 24 | v-1<> 1+^ 25 | v ^_^#:< _1- 26 | block 3 27 | %8 = load i32* %c, align 4 28 | %9 = icmp sge i32 %8, 65 29 | br i1 %9, label %10, label %16 30 | >:#v_ >$ 20g0+:9%\9/g:9%9+\9/g51p 79*2+51g`!60p 6460g> #0 #\_$ 3-:0`!v 31 | v-1<> 1+^ 32 | v ^_^#:< _1- 33 | block 4 34 | %11 = load i32* %c, align 4 35 | %12 = icmp sle i32 %11, 90 36 | br i1 %12, label %13, label %16 37 | >:#v_ >$ 20g0+:9%\9/g:9%9+\9/g51p 51g19*1+9*`!60p 6560g> #0 #\_$ 4-:0`!v 38 | v-1<> 1+^ 39 | v ^_^#:< _1- 40 | block 5 41 | %14 = load i32* %c, align 4 42 | %15 = add nsw i32 %14, 32 43 | store i32 %15, i32* %c, align 4 44 | br label %26 45 | >:#v_ >$ 20g0+:9%\9/g:9%9+\9/g51p 51g48*+60p 60g20g0+:9%\9/g:9%9+\9/p 25* 5-:v 46 | v-1<> 1+^ v!`0< 47 | v ^_^#:< _1- 48 | block 6 49 | %17 = load i32* %c, align 4 50 | %18 = icmp sge i32 %17, 97 51 | br i1 %18, label %19, label %25 52 | >:#v_ >$ 20g0+:9%\9/g:9%9+\9/g51p 19*1+9*7+51g`!60p 19*760gv 53 | v-1<> 1+^ v!`0:-6 $_\# 0#!<< 54 | v ^_^#:< _1- 55 | block 7 56 | %20 = load i32* %c, align 4 57 | %21 = icmp sle i32 %20, 122 58 | br i1 %21, label %22, label %25 59 | >:#v_ >$ 20g0+:9%\9/g:9%9+\9/g51p 51g19*4+9*5+`!60p 19*860gv 60 | v-1<> 1+^ v!`0:-7 $_\# 0#!<< 61 | v ^_^#:< _1- 62 | block 8 63 | %23 = load i32* %c, align 4 64 | %24 = sub nsw i32 %23, 32 65 | store i32 %24, i32* %c, align 4 66 | br label %25 67 | >:#v_ >$ 20g0+:9%\9/g:9%9+\9/g51p 51g48*-60p 60g20g0+:9%\9/g:9%9+\9/p 19* 8-:v 68 | v-1<> 1+^ v!`0< 69 | v ^_^#:< _1- 70 | block 9 71 | br label %26 72 | >:#v_ >$ 25* 19*-:0`!v 73 | v-1<> 1+^ 74 | v ^_^#:< _1- 75 | block 10 76 | %27 = load i32* %c, align 4 77 | %28 = call i32 @putchar(i32 %27) #2 78 | br label %2 79 | >:#v_ >$ 20g0+:9%\9/g:9%9+\9/g51p 51g,060p 1 25*-:0`!v 80 | v-1<> 1+^ 81 | v ^_^#:< _1- 82 | block 11 83 | ret i32 0 84 | >:#v_ >$ 00g2-00p@ 19*2+-:0`!v 85 | v-1<> 1+^ 86 | v ^_^#:< _1- 87 | -------------------------------------------------------------------------------- /test/loop.c: -------------------------------------------------------------------------------- 1 | int getchar(void); 2 | int putchar(int c); 3 | 4 | int main() { 5 | while (1) { 6 | int c = getchar(); 7 | if (c == -1) 8 | break; 9 | if (c >= 'A' && c <= 'Z') { 10 | c += 32; 11 | } else if (c >= 'a' && c <= 'z') { 12 | c -= 32; 13 | } 14 | putchar(c); 15 | } 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /test/loop.in: -------------------------------------------------------------------------------- 1 | 09ANZ_az~ 2 | -------------------------------------------------------------------------------- /test/malloc.bef: -------------------------------------------------------------------------------- 1 | 89*9*9*9*00p89*9*9*9*9*10p89*9*9*9*20p0v 2 | v < < 3 | *** main *** 0 4 | block 0 5 | %1 = alloca i32, align 4 6 | %buf = alloca i32*, align 4 7 | %buf2 = alloca i32*, align 4 8 | store i32 0, i32* %1 9 | %2 = call i32* @calloc(i32 6, i32 4) #2 10 | store i32* %2, i32** %buf, align 4 11 | %3 = call i32* @calloc(i32 6, i32 4) #2 12 | store i32* %3, i32** %buf2, align 4 13 | %4 = load i32** %buf, align 4 14 | %5 = getelementptr inbounds i32* %4, i32 0 15 | store i32 104, i32* %5, align 4 16 | %6 = load i32** %buf, align 4 17 | %7 = getelementptr inbounds i32* %6, i32 1 18 | store i32 101, i32* %7, align 4 19 | %8 = load i32** %buf, align 4 20 | %9 = getelementptr inbounds i32* %8, i32 2 21 | store i32 108, i32* %9, align 4 22 | %10 = load i32** %buf, align 4 23 | %11 = getelementptr inbounds i32* %10, i32 3 24 | store i32 108, i32* %11, align 4 25 | %12 = load i32** %buf, align 4 26 | %13 = getelementptr inbounds i32* %12, i32 4 27 | store i32 111, i32* %13, align 4 28 | %14 = load i32** %buf, align 4 29 | %15 = getelementptr inbounds i32* %14, i32 5 30 | store i32 0, i32* %15, align 4 31 | %16 = load i32** %buf2, align 4 32 | %17 = getelementptr inbounds i32* %16, i32 0 33 | store i32 119, i32* %17, align 4 34 | %18 = load i32** %buf2, align 4 35 | %19 = getelementptr inbounds i32* %18, i32 1 36 | store i32 111, i32* %19, align 4 37 | %20 = load i32** %buf2, align 4 38 | %21 = getelementptr inbounds i32* %20, i32 2 39 | store i32 114, i32* %21, align 4 40 | %22 = load i32** %buf2, align 4 41 | %23 = getelementptr inbounds i32* %22, i32 3 42 | store i32 108, i32* %23, align 4 43 | %24 = load i32** %buf2, align 4 44 | %25 = getelementptr inbounds i32* %24, i32 4 45 | store i32 100, i32* %25, align 4 46 | %26 = load i32** %buf2, align 4 47 | %27 = getelementptr inbounds i32* %26, i32 5 48 | store i32 0, i32* %27, align 4 49 | %28 = load i32** %buf, align 4 50 | call void @print_str(i32* %28) #2 51 | %29 = load i32** %buf2, align 4 52 | call void @print_str(i32* %29) #2 53 | %30 = load i32** %buf, align 4 54 | %31 = bitcast i32* %30 to i8* 55 | call void @free(i8* %31) #2 56 | %32 = load i32** %buf2, align 4 57 | %33 = bitcast i32* %32 to i8* 58 | call void @free(i8* %33) #2 59 | ret i32 0 60 | >:#v_ >$ 00g:1+00p51p 00g:1+00p20g0+:9%\9/p 00g:1+00p20g1+:9%\9/p 051g:9%9+\9v 61 | v-1<> 1+^v9\%9:+1g02g17 p17p01+6:g01 p/9\+9%9:g/9\%9:+0g02g16 p16p01+6:g01 p/< 62 | v ^_^#:<>/g:9%9+\9/p 20g0+:9%\9/g:9%9+\9/g81p 81g0+19*0p 19*2+9*5+19*0g:9%9+v 63 | v/9\+9%9:g1*52+2*9+2*91 p1*52+1g0*52 p0*52g/9\+9%9:g/9\%9:+0g02 p/9\< 64 | >p 20g0+:9%\9/g:9%9+\9/g19*2+1p 19*2+1g2+26*0p 19*3+9*26*0g:9%9+\9/pv 65 | v\+9%9:g1+4*91*9+3*91 p1+4*91+3g0+4*91 p0+4*91g/9\+9%9:g/9\%9:+0g02 < 66 | >9/p 20g0+:9%\9/g:9%9+\9/g27*1p 27*1g4+35*0p 19*3+9*3+35*0g:9%9+\9/pv 67 | v9\%9:+1g02 p/9\+9%9:g1*820 p1*82+5g0*82 p0*82g/9\+9%9:g/9\%9:+0g02 < 68 | >/g:9%9+\9/g19*8+1p 19*8+1g0+29*0p 19*4+9*2+29*0g:9%9+\9/p 20g1+:9%\v 69 | v1g02 p/9\+9%9:g1+1*92+3*9+3*91 p1+1*92+1g0+1*92 p0+1*92g/9\+9%9:g/9< 70 | >+:9%\9/g:9%9+\9/g45*1p 45*1g2+37*0p 19*3+9*6+37*0g:9%9+\9/p 20g1+:9v 71 | v1g02 p/9\+9%9:g1+4*92*9+3*91 p1+4*92+3g0+4*92 p0+4*92g/9\+9%9:g/9\%< 72 | >+:9%\9/g:9%9+\9/g29*5+1p 29*5+1g4+38*0p 19*2+9*1+38*0g:9%9+\9/p 20gv 73 | v9:g/9\%9:+0g02 p/9\+9%9:g1*550 p1*55+5g0*55 p0*55g/9\+9%9:g/9\%9:+1< 74 | >%9+\9/g29*8+1p 129*8+1g320g2+20p0-:0`!v 75 | v ^ _1- 76 | >:#v_ >$ 20g2-20p39*0p 20g1+:9%\9/g:9%9+\9/g39*1p 239*1g320g2+20p1-:0`!v 77 | v-1<> 1+^ 78 | v ^_^#:< _1- 79 | >:#v_ >$ 20g2-20p47*0p 20g0+:9%\9/g:9%9+\9/g47*1p 47*1g39*2+0p 039*2+1p 20g1+v 80 | v-1<> 1+^ v!`0:-2 @p00-3g00 p0+4*930 p1*65g0*65 p0*65g/9\+9%9:g/9\%9:< 81 | v ^_^#:< _1- 82 | *** print_str *** 3 83 | block 3 84 | %1 = alloca i32*, align 4 85 | store i32* %p, i32** %1, align 4 86 | br label %2 87 | >:#v_ >$ 20g0+:9%\9/p00g:1+00p20g1+:9%\9/p 20g0+:9%\9/g20g1+:9%\9/g:9%9+\9/p v 88 | v-1<> 1+^ v!`0:-3 4< 89 | v ^_^#:< _1- 90 | block 4 91 | %3 = load i32** %1, align 4 92 | %4 = load i32* %3, align 4 93 | %5 = icmp ne i32 %4, 0 94 | br i1 %5, label %6, label %12 95 | >:#v_ >$ 20g1+:9%\9/g:9%9+\9/g51p 51g:9%9+\9/g60p 60g0-!!61p 6561gv 96 | v-1<> 1+^ v!`0:-4 $_\# 0#!<< 97 | v ^_^#:< _1- 98 | block 5 99 | %7 = load i32** %1, align 4 100 | %8 = load i32* %7, align 4 101 | %9 = call i32 @putchar(i32 %8) #2 102 | %10 = load i32** %1, align 4 103 | %11 = getelementptr inbounds i32* %10, i32 1 104 | store i32* %11, i32** %1, align 4 105 | br label %2 106 | >:#v_ >$ 20g1+:9%\9/g:9%9+\9/g51p 51g:9%9+\9/g60p 60g,061p 20g1+:9%\9/g:9%9+\v 107 | v-1<> 1+^ v!`0:-5 4 p/9\+9%9:g/9\%9:+1g02g17 p17+1g07 p07g/9< 108 | v ^_^#:< _1- 109 | block 6 110 | ret void 111 | >:#v_ >$ 00g1-00p0\ 6-:0`!v 112 | v-1<> 1+^ 113 | v ^_^#:< _1- 114 | -------------------------------------------------------------------------------- /test/malloc.c: -------------------------------------------------------------------------------- 1 | #include "libef.h" 2 | 3 | int main() { 4 | int* buf = calloc(6, 4); 5 | int* buf2 = calloc(6, 4); 6 | buf[0] = 'h'; 7 | buf[1] = 'e'; 8 | buf[2] = 'l'; 9 | buf[3] = 'l'; 10 | buf[4] = 'o'; 11 | buf[5] = 0; 12 | buf2[0] = 'w'; 13 | buf2[1] = 'o'; 14 | buf2[2] = 'r'; 15 | buf2[3] = 'l'; 16 | buf2[4] = 'd'; 17 | buf2[5] = 0; 18 | print_str(buf); 19 | print_str(buf2); 20 | free(buf); 21 | free(buf2); 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /test/nullptr.bef: -------------------------------------------------------------------------------- 1 | 89*9*9*9*00p89*9*9*9*9*10p89*9*9*9*20p1v 2 | v < < 3 | *** retNull *** 0 4 | block 0 5 | ret i8* null 6 | >:#v_ >$ 0\ 0-:0`!v 7 | v-1<> 1+^ 8 | v ^_^#:< _1- 9 | *** main *** 1 10 | block 1 11 | %1 = alloca i32, align 4 12 | store i32 0, i32* %1 13 | %2 = call i8* @retNull() #3 14 | %3 = icmp ne i8* %2, null 15 | br i1 %3, label %4, label %9 16 | >:#v_ >$ 00g:1+00p51p 051g:9%9+\9/p 2020g1+20p1-:0`!v 17 | v-1<> 1+^ 18 | v ^_^#:< _1- 19 | >:#v_ >$ 20g1-20p20g0+:9%\9/p 20g0+:9%\9/g0-!!61p 4361g> #0 #\_$ 2-:0`!v 20 | v-1<> 1+^ 21 | v ^_^#:< _1- 22 | block 3 23 | %5 = call i32 @putchar(i32 70) #3 24 | %6 = call i32 @putchar(i32 65) #3 25 | %7 = call i32 @putchar(i32 73) #3 26 | %8 = call i32 @putchar(i32 76) #3 27 | br label %12 28 | >:#v_ >$ 79*7+,051p 79*2+,060p 89*1+,061p 89*4+,070p 5 3-:0`!v 29 | v-1<> 1+^ 30 | v ^_^#:< _1- 31 | block 4 32 | %10 = call i32 @putchar(i32 79) #3 33 | %11 = call i32 @putchar(i32 75) #3 34 | br label %12 35 | >:#v_ >$ 89*7+,051p 89*3+,060p 5 4-:0`!v 36 | v-1<> 1+^ 37 | v ^_^#:< _1- 38 | block 5 39 | ret i32 0 40 | >:#v_ >$ 00g1-00p@ 5-:0`!v 41 | v-1<> 1+^ 42 | v ^_^#:< _1- 43 | -------------------------------------------------------------------------------- /test/nullptr.c: -------------------------------------------------------------------------------- 1 | #include "libef.h" 2 | 3 | __attribute__((noinline)) void* retNull() { 4 | return 0; 5 | } 6 | 7 | int main() { 8 | if (retNull()) { 9 | putchar('F'); 10 | putchar('A'); 11 | putchar('I'); 12 | putchar('L'); 13 | } else { 14 | putchar('O'); 15 | putchar('K'); 16 | } 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /test/print_int.bef: -------------------------------------------------------------------------------- 1 | 89*9*9*9*00p89*9*9*9*9*10p89*9*9*9*20p0v 2 | v < < 3 | *** main *** 0 4 | block 0 5 | %1 = alloca i32, align 4 6 | store i32 0, i32* %1 7 | call void @print_int(i32 7) #3 8 | call void @print_int(i32 42) #3 9 | call void @print_int(i32 123) #3 10 | call void @print_int(i32 0) #3 11 | call void @print_int(i32 -99) #3 12 | ret i32 0 13 | >:#v_ >$ 00g:1+00p51p 051g:9%9+\9/p 17620g0+20p0-:0`!v 14 | v-1<> 1+^ 15 | v ^_^#:< _1- 16 | >:#v_ >$ 20g0-20p61p 267*620g0+20p1-:0`!v 17 | v-1<> 1+^ 18 | v ^_^#:< _1- 19 | >:#v_ >$ 20g0-20p70p 319*4+9*6+620g0+20p2-:0`!v 20 | v-1<> 1+^ 21 | v ^_^#:< _1- 22 | >:#v_ >$ 20g0-20p71p 40620g0+20p3-:0`!v 23 | v-1<> 1+^ 24 | v ^_^#:< _1- 25 | >:#v_ >$ 20g0-20p80p 501-9*2-9*620g0+20p4-:0`!v 26 | v-1<> 1+^ 27 | v ^_^#:< _1- 28 | >:#v_ >$ 20g0-20p81p 00g1-00p@ 5-:0`!v 29 | v-1<> 1+^ 30 | v ^_^#:< _1- 31 | *** print_int *** 6 32 | block 6 33 | %1 = alloca i32, align 4 34 | %buf = alloca [16 x i32], align 4 35 | %n = alloca i32, align 4 36 | store i32 %v, i32* %1, align 4 37 | %2 = load i32* %1, align 4 38 | %3 = icmp slt i32 %2, 0 39 | br i1 %3, label %4, label %8 40 | >:#v_ >$ 20g0+:9%\9/p00g:1+00p20g1+:9%\9/p 00g:28*+00p20g2+:9%\9/p 00g:1+00p2v 41 | v-1<> 1+^vg/9\+9%9:g/9\%9:+1g02 p/9\+9%9:g/9\%9:+1g02g/9\%9:+0g02 p/9\%9:+3g0< 42 | v ^_^#:<>60p 060g`61p 8761g> #0 #\_$ 6-:0`!v 43 | v ^ _1- 44 | block 7 45 | %5 = call i32 @putchar(i32 45) #3 46 | %6 = load i32* %1, align 4 47 | %7 = sub nsw i32 0, %6 48 | store i32 %7, i32* %1, align 4 49 | br label %8 50 | >:#v_ >$ 59*,051p 20g1+:9%\9/g:9%9+\9/g60p 060g-61p 61g20g1+:9%\9/g:9%9+\9/p v 51 | v-1<> 1+^ v!`0:-7 8< 52 | v ^_^#:< _1- 53 | block 8 54 | store i32 0, i32* %n, align 4 55 | br label %9 56 | >:#v_ >$ 020g3+:9%\9/g:9%9+\9/p 19* 8-:0`!v 57 | v-1<> 1+^ 58 | v ^_^#:< _1- 59 | block 9 60 | %10 = load i32* %1, align 4 61 | %11 = srem i32 %10, 10 62 | %12 = load i32* %n, align 4 63 | %13 = getelementptr inbounds [16 x i32]* %buf, i32 0, i32 %12 64 | store i32 %11, i32* %13, align 4 65 | %14 = load i32* %1, align 4 66 | %15 = sdiv i32 %14, 10 67 | store i32 %15, i32* %1, align 4 68 | %16 = load i32* %n, align 4 69 | %17 = add nsw i32 %16, 1 70 | store i32 %17, i32* %n, align 4 71 | br label %18 72 | >:#v_ >$ 20g1+:9%\9/g:9%9+\9/g51p 51g25*%60p 20g3+:9%\9/g:9%9+\9/g61p 20g2+:9v 73 | v-1<> 1+^v p18/*52g08 p08g/9\+9%9:g/9\%9:+1g02 p/9\+9%9:g07g06 p07+g16+0g/9\%< 74 | v ^_^#:<>81g20g1+:9%\9/g:9%9+\9/p 20g3+:9%\9/g:9%9+\9/g19*1p 19*1g1+25*0p 25v 75 | v!`0:-*91 *52 p/9\+9%9:g/9\%9:+3g02g0*< 76 | v ^ _1- 77 | block 10 78 | %19 = load i32* %1, align 4 79 | %20 = icmp ne i32 %19, 0 80 | br i1 %20, label %9, label %21 81 | >:#v_ >$ 20g1+:9%\9/g:9%9+\9/g51p 51g0-!!60p 19*2+19*60g> #0 #\_$ 25*-:0`!v 82 | v-1<> 1+^ 83 | v ^_^#:< _1- 84 | block 11 85 | br label %22 86 | >:#v_ >$ 26* 19*2+-:0`!v 87 | v-1<> 1+^ 88 | v ^_^#:< _1- 89 | block 12 90 | %23 = load i32* %n, align 4 91 | %24 = add nsw i32 %23, -1 92 | store i32 %24, i32* %n, align 4 93 | %25 = icmp ne i32 %23, 0 94 | br i1 %25, label %26, label %32 95 | >:#v_ >$ 20g3+:9%\9/g:9%9+\9/g51p 51g01-+60p 60g20g3+:9%\9/g:9%9+\9/p 51g0-!!v 96 | v-1<> 1+^ v!`0:-*62 $_\# 0#!:#v_ >$ 20g3+:9%\9/g:9%9+\9/g51p 20g2+:9%\9/g0+51g+60p 60g:9%9+\9/g61p 61g68v 106 | v-1<> 1+^ v!`0:-+4*91 *62 p170,g07 p07+*< 107 | v ^_^#:< _1- 108 | block 14 109 | ret void 110 | >:#v_ >$ 00g29*-00p0\ 27*-:0`!v 111 | v-1<> 1+^ 112 | v ^_^#:< _1- 113 | -------------------------------------------------------------------------------- /test/print_int.c: -------------------------------------------------------------------------------- 1 | #include "libef.h" 2 | 3 | int main() { 4 | print_int(7); 5 | print_int(42); 6 | print_int(123); 7 | print_int(0); 8 | print_int(-99); 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /test/puts.bef: -------------------------------------------------------------------------------- 1 | 89*9*9*9*00p89*9*9*9*9*10p89*9*9*9*20p0v 2 | v < < 3 | *** main *** 0 4 | block 0 5 | %1 = alloca i32, align 4 6 | store i32 0, i32* %1 7 | %2 = call i32 @puts(i8* getelementptr inbounds ([14 x i8]* @.str, i32 0, i32 0)) #2 8 | ret i32 0 9 | >:#v_ >$ 00g:1+00p51p 051g:9%9+\9/p 89*,19*2+9*2+,19*3+9*,19*3+9*,19*3+9*3+,4v 10 | v-1<> 1+^v,*25,+6*93,+1*9+2*91,*9+3*91,+6*9+3*91,+3*9+3*91,+2*9+4*91,*84,+8*9< 11 | v ^_^#:<>061p 00g1-00p@ 0-:0`!v 12 | v ^ _1- 13 | -------------------------------------------------------------------------------- /test/puts.c: -------------------------------------------------------------------------------- 1 | #include "libef.h" 2 | 3 | int main() { 4 | puts("Hello, world!"); 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /test/struct.bef: -------------------------------------------------------------------------------- 1 | 89*9*9*9*00p89*9*9*9*9*10p89*9*9*9*20p1v 2 | v < < 3 | *** add *** 0 4 | block 0 5 | %1 = alloca %struct.S*, align 4 6 | store %struct.S* %s, %struct.S** %1, align 4 7 | %2 = load %struct.S** %1, align 4 8 | %3 = getelementptr inbounds %struct.S* %2, i32 0, i32 0 9 | %4 = load i32* %3, align 4 10 | %5 = load %struct.S** %1, align 4 11 | %6 = getelementptr inbounds %struct.S* %5, i32 0, i32 1 12 | %7 = load i32* %6, align 4 13 | %8 = add nsw i32 %4, %7 14 | ret i32 %8 15 | >:#v_ >$ 20g0+:9%\9/p00g:1+00p51p 20g0+:9%\9/g51g:9%9+\9/p 51g:9%9+\9/g61p 61v 16 | v-1<> 1+^v*91g/9\+9%9:g18 p18+1+0g08 p08g/9\+9%9:g15 p17g/9\+9%9:g07 p07+0+0g< 17 | v ^_^#:<>0p 71g19*0g+19*1p 00g1-00p19*1g\ 0-:0`!v 18 | v ^ _1- 19 | *** main *** 1 20 | block 1 21 | %1 = alloca i32, align 4 22 | %s = alloca %struct.S, align 4 23 | store i32 0, i32* %1 24 | %2 = call i32 @getchar() #3 25 | %3 = getelementptr inbounds %struct.S* %s, i32 0, i32 0 26 | store i32 %2, i32* %3, align 4 27 | %4 = call i32 @getchar() #3 28 | %5 = getelementptr inbounds %struct.S* %s, i32 0, i32 1 29 | store i32 %4, i32* %5, align 4 30 | %6 = call i32 @add(%struct.S* %s) #3 31 | %7 = call i32 @putchar(i32 %6) #3 32 | ret i32 0 33 | >:#v_ >$ 00g:1+00p51p 00g:2+00p60p 051g:9%9+\9/p #@~70p 60g0+0+71p 70g71g:9%9v 34 | v-1<> 1+^ v!`0:-1p02+1g020g062 p/9\+9%9:g0*91g18 p0*91+1+0g06 p18~@# p/9\+< 35 | v ^_^#:< _1- 36 | >:#v_ >$ 20g1-20p20g0+:9%\9/p 20g0+:9%\9/g,025*0p 00g3-00p@ 2-:0`!v 37 | v-1<> 1+^ 38 | v ^_^#:< _1- 39 | -------------------------------------------------------------------------------- /test/struct.c: -------------------------------------------------------------------------------- 1 | #include "libef.h" 2 | 3 | typedef struct { 4 | int x; 5 | int y; 6 | } S; 7 | 8 | __attribute__((noinline)) int add(S* s) { 9 | return s->x + s->y; 10 | } 11 | 12 | int main() { 13 | S s; 14 | s.x = getchar(); 15 | s.y = getchar(); 16 | putchar(add(&s)); 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /test/struct.in: -------------------------------------------------------------------------------- 1 | !@ -------------------------------------------------------------------------------- /test/swapcase.bef: -------------------------------------------------------------------------------- 1 | 89*9*9*9*00p89*9*9*9*9*10p89*9*9*9*20p0v 2 | v < < 3 | *** main *** 0 4 | block 0 5 | %1 = alloca i32, align 4 6 | %c = alloca i32, align 4 7 | store i32 0, i32* %1 8 | %2 = call i32 @getchar() #2 9 | store i32 %2, i32* %c, align 4 10 | %3 = load i32* %c, align 4 11 | %4 = icmp sge i32 %3, 65 12 | br i1 %4, label %5, label %11 13 | >:#v_ >$ 00g:1+00p51p 00g:1+00p20g0+:9%\9/p 051g:9%9+\9/p #@~61p 61g20g0+:9%\v 14 | v-1<> 1+^ vg0813 p08!`g17+2*97 p17g/9\+9%9:g/9\%9:+0g02 p/9\+9%9:g/9< 15 | v ^_^#:< >> #0 #\_$ 0-:0`!v 16 | v ^ _1- 17 | block 1 18 | %6 = load i32* %c, align 4 19 | %7 = icmp sle i32 %6, 90 20 | br i1 %7, label %8, label %11 21 | >:#v_ >$ 20g0+:9%\9/g:9%9+\9/g51p 51g19*1+9*`!60p 3260g> #0 #\_$ 1-:0`!v 22 | v-1<> 1+^ 23 | v ^_^#:< _1- 24 | block 2 25 | %9 = load i32* %c, align 4 26 | %10 = add nsw i32 %9, 32 27 | store i32 %10, i32* %c, align 4 28 | br label %21 29 | >:#v_ >$ 20g0+:9%\9/g:9%9+\9/g51p 51g48*+60p 60g20g0+:9%\9/g:9%9+\9/p 7 2-:0`v 30 | v-1<> 1+^ v !< 31 | v ^_^#:< _1- 32 | block 3 33 | %12 = load i32* %c, align 4 34 | %13 = icmp sge i32 %12, 97 35 | br i1 %13, label %14, label %20 36 | >:#v_ >$ 20g0+:9%\9/g:9%9+\9/g51p 19*1+9*7+51g`!60p 6460g> #0 #\_$ 3-:0`!v 37 | v-1<> 1+^ 38 | v ^_^#:< _1- 39 | block 4 40 | %15 = load i32* %c, align 4 41 | %16 = icmp sle i32 %15, 122 42 | br i1 %16, label %17, label %20 43 | >:#v_ >$ 20g0+:9%\9/g:9%9+\9/g51p 51g19*4+9*5+`!60p 6560g> #0 #\_$ 4-:0`!v 44 | v-1<> 1+^ 45 | v ^_^#:< _1- 46 | block 5 47 | %18 = load i32* %c, align 4 48 | %19 = sub nsw i32 %18, 32 49 | store i32 %19, i32* %c, align 4 50 | br label %20 51 | >:#v_ >$ 20g0+:9%\9/g:9%9+\9/g51p 51g48*-60p 60g20g0+:9%\9/g:9%9+\9/p 6 5-:0`v 52 | v-1<> 1+^ v !< 53 | v ^_^#:< _1- 54 | block 6 55 | br label %21 56 | >:#v_ >$ 7 6-:0`!v 57 | v-1<> 1+^ 58 | v ^_^#:< _1- 59 | block 7 60 | %22 = load i32* %c, align 4 61 | %23 = call i32 @putchar(i32 %22) #2 62 | ret i32 0 63 | >:#v_ >$ 20g0+:9%\9/g:9%9+\9/g51p 51g,060p 00g2-00p@ 7-:0`!v 64 | v-1<> 1+^ 65 | v ^_^#:< _1- 66 | -------------------------------------------------------------------------------- /test/swapcase.c: -------------------------------------------------------------------------------- 1 | int getchar(void); 2 | int putchar(int c); 3 | 4 | int main() { 5 | int c = getchar(); 6 | if (c >= 'A' && c <= 'Z') { 7 | c += 32; 8 | } else if (c >= 'a' && c <= 'z') { 9 | c -= 32; 10 | } 11 | putchar(c); 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /test/swapcase_1.in: -------------------------------------------------------------------------------- 1 | 0 2 | -------------------------------------------------------------------------------- /test/swapcase_2.in: -------------------------------------------------------------------------------- 1 | A 2 | -------------------------------------------------------------------------------- /test/swapcase_3.in: -------------------------------------------------------------------------------- 1 | Z 2 | -------------------------------------------------------------------------------- /test/swapcase_4.in: -------------------------------------------------------------------------------- 1 | a 2 | -------------------------------------------------------------------------------- /test/swapcase_5.in: -------------------------------------------------------------------------------- 1 | z 2 | -------------------------------------------------------------------------------- /test/swapcase_6.in: -------------------------------------------------------------------------------- 1 | $ 2 | -------------------------------------------------------------------------------- /test/switch_op.bef: -------------------------------------------------------------------------------- 1 | 89*9*9*9*00p89*9*9*9*9*10p89*9*9*9*20p0v 2 | v < < 3 | *** main *** 0 4 | block 0 5 | %1 = alloca i32, align 4 6 | %c = alloca i32, align 4 7 | store i32 0, i32* %1 8 | br label %2 9 | >:#v_ >$ 00g:1+00p51p 00g:1+00p20g0+:9%\9/p 051g:9%9+\9/p 1 0-:0`!v 10 | v-1<> 1+^ 11 | v ^_^#:< _1- 12 | block 1 13 | %3 = call i32 @getchar() #2 14 | store i32 %3, i32* %c, align 4 15 | %4 = load i32* %c, align 4 16 | %5 = icmp eq i32 %4, -1 17 | br i1 %5, label %6, label %7 18 | >:#v_ >$ #@~51p 51g20g0+:9%\9/g:9%9+\9/p 20g0+:9%\9/g:9%9+\9/g61p 61g01--!70pv 19 | v-1<> 1+^ v!`0:-1 $_\# 0#!:#v_ >$ 00g2-00p@ 2-:0`!v 24 | v-1<> 1+^ 25 | v ^_^#:< _1- 26 | block 3 27 | %8 = load i32* %c, align 4 28 | %9 = icmp eq i32 %8, 40 29 | br i1 %9, label %10, label %12 30 | >:#v_ >$ 20g0+:9%\9/g:9%9+\9/g51p 51g58*-!60p 5460g> #0 #\_$ 3-:0`!v 31 | v-1<> 1+^ 32 | v ^_^#:< _1- 33 | block 4 34 | %11 = call i32 @putchar(i32 112) #2 35 | br label %26 36 | >:#v_ >$ 19*3+9*4+,051p 19*2+ 4-:0`!v 37 | v-1<> 1+^ 38 | v ^_^#:< _1- 39 | block 5 40 | %13 = load i32* %c, align 4 41 | %14 = icmp eq i32 %13, 45 42 | br i1 %14, label %21, label %15 43 | >:#v_ >$ 20g0+:9%\9/g:9%9+\9/g51p 51g59*-!60p 6860g> #0 #\_$ 5-:0`!v 44 | v-1<> 1+^ 45 | v ^_^#:< _1- 46 | block 6 47 | %16 = load i32* %c, align 4 48 | %17 = icmp sge i32 %16, 48 49 | br i1 %17, label %18, label %23 50 | >:#v_ >$ 20g0+:9%\9/g:9%9+\9/g51p 68*51g`!60p 19*760g> #0 #\_$ 6-:0`!v 51 | v-1<> 1+^ 52 | v ^_^#:< _1- 53 | block 7 54 | %19 = load i32* %c, align 4 55 | %20 = icmp sle i32 %19, 57 56 | br i1 %20, label %21, label %23 57 | >:#v_ >$ 20g0+:9%\9/g:9%9+\9/g51p 51g69*3+`!60p 19*860g> #0 #\_$ 7-:0`!v 58 | v-1<> 1+^ 59 | v ^_^#:< _1- 60 | block 8 61 | %22 = call i32 @putchar(i32 110) #2 62 | br label %25 63 | >:#v_ >$ 19*3+9*2+,051p 25* 8-:0`!v 64 | v-1<> 1+^ 65 | v ^_^#:< _1- 66 | block 9 67 | %24 = call i32 @putchar(i32 111) #2 68 | br label %25 69 | >:#v_ >$ 19*3+9*3+,051p 25* 19*-:0`!v 70 | v-1<> 1+^ 71 | v ^_^#:< _1- 72 | block 10 73 | br label %26 74 | >:#v_ >$ 19*2+ 25*-:0`!v 75 | v-1<> 1+^ 76 | v ^_^#:< _1- 77 | block 11 78 | br label %27 79 | >:#v_ >$ 26* 19*2+-:0`!v 80 | v-1<> 1+^ 81 | v ^_^#:< _1- 82 | block 12 83 | br label %2 84 | >:#v_ >$ 1 26*-:0`!v 85 | v-1<> 1+^ 86 | v ^_^#:< _1- 87 | -------------------------------------------------------------------------------- /test/switch_op.c: -------------------------------------------------------------------------------- 1 | #include "libef.h" 2 | 3 | int main() { 4 | while (1) { 5 | int c = getchar(); 6 | if (c == -1) { 7 | return 0; 8 | } else if (c == '(') { 9 | putchar('p'); 10 | } else if (c == '-' || (c >= '0' && c <= '9')) { 11 | putchar('n'); 12 | } else { 13 | putchar('o'); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/switch_op.in: -------------------------------------------------------------------------------- 1 | 09ANZ_az~(){} -------------------------------------------------------------------------------- /test_bef.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | def getResult(cmd, input) 4 | pipe = IO.popen(cmd, 'r+') 5 | pipe.write(input) 6 | pipe.close_write 7 | o = pipe.read 8 | o 9 | end 10 | 11 | num_tests = 0 12 | fails = [] 13 | 14 | ARGV.each do |test| 15 | test_path = "test/#{test}" 16 | tests = Dir.glob("#{test_path}*.in").sort 17 | tests = [test_path] if tests.empty? 18 | tests.each do |test_case| 19 | input = test_case == test_path ? '' : File.read(test_case) 20 | expected = getResult([test_path], input) 21 | actual = getResult(['./befunge', "#{test_path}.bef"], input) 22 | #actual = getResult(['./ccbi', "#{test_path}.bef"], input) 23 | #actual = getResult(['./cfunge', "#{test_path}.bef"], input) 24 | if expected == actual 25 | puts "#{test_case}: OK (#{expected.sub(/\n.*/ms, '...')})" 26 | else 27 | puts "#{test_case}: FAIL expected=#{expected} actual=#{actual}" 28 | fails << test_case 29 | end 30 | num_tests += 1 31 | end 32 | end 33 | 34 | if fails.empty? 35 | puts 'PASS' 36 | else 37 | puts "Failed tests:" 38 | puts fails.map{|f|f.inspect} 39 | puts "#{fails.size} / #{num_tests} FAIL" 40 | end 41 | --------------------------------------------------------------------------------