diff --git a/alee.cpp b/alee.cpp index c8dee45..855afa8 100644 --- a/alee.cpp +++ b/alee.cpp @@ -47,6 +47,10 @@ int main(int argc, char *argv[]) State state (dict, readchar); Parser parser; + dict.write(Dictionary::Base, 10); + dict.write(Dictionary::Compiling, 0); + dict.write(Dictionary::Postpone, 0); + std::vector args (argv + 1, argv + argc); for (const auto& a : args) { std::ifstream file (a); diff --git a/core.fth b/core.fth index 7a6e455..24fa6dc 100644 --- a/core.fth +++ b/core.fth @@ -1,72 +1,79 @@ ( : variable create 0 , ; ) ( : create here const ; ) -: 1+ 1 + ; -: 1- 1 - ; +: 1+ 1 + ; +: 1- 1 - ; -: ! 2 _! ; -: @ 2 _@ ; -: , here ! 2 allot ; -: cell+ 2 + ; -: cells 2 * ; +: ! 2 _! ; +: @ 2 _@ ; +: , here ! 2 allot ; +: cell+ 2 + ; +: cells 2 * ; -: c! 1 _! ; -: c@ 1 _@ ; -: c, here c! 1 allot ; -: char+ 1+ ; -: chars ; +: over 1 pick ; +: -rot rot rot ; +: nip swap drop ; +: tuck swap over ; -: align here 1 & if 1 allot then ; -: aligned dup 1 & if 1+ then ; +: base 0 ; +: state 2 ; +: decimal 1 1+ base ! 1010 base ! ; + +: postpone 1 4 ! ; imm +: ['] ' postpone literal ; imm -( set decimal numbers ) -10 0 ! +: if ['] _jmp0 , here 0 , ; imm +: then here swap ! ; imm +: else ['] _jmp , here 0 , here rot ! ; imm -: . 0 sys ; -: emit 1 sys ; +: c! 1 _! ; +: c@ 1 _@ ; +: c, here c! 1 allot ; +: char+ 1+ ; +: chars ; + +: align here 1 & if 1 allot then ; +: aligned dup 1 & if 1+ then ; -: over 1 pick ; -: -rot rot rot ; -: nip swap drop ; -: tuck swap over ; +: . 0 sys ; +: emit 1 sys ; -: +! swap over @ + swap ! ; +: +! swap over @ + swap ! ; -: and & ; -: or | ; -: xor ^ ; -: lshift << ; -: rshift >> ; -: mod % ; -: 2* 2 * ; -: 2/ 2 / ; +: and & ; +: or | ; +: xor ^ ; +: lshift << ; +: rshift >> ; +: mod % ; +: 2* 2 * ; +: 2/ 2 / ; -: 2drop drop drop ; -: 2dup over over ; -: 2over 3 pick 3 pick ; -: 2swap rot >r rot r> ; +: 2drop drop drop ; +: 2dup over over ; +: 2over 3 pick 3 pick ; +: 2swap rot >r rot r> ; -: r@ r> dup >r ; -: 2! swap over ! cell+ ! ; -: 2@ dup cell+ @ swap @ ; +: r@ r> dup >r ; +: 2! swap over ! cell+ ! ; +: 2@ dup cell+ @ swap @ ; -: 0= 0 = ; -: 0< 0 < ; -: <= 2dup - 1- 0< ; -: > <= 0= ; +: 0= 0 = ; +: 0< 0 < ; +: <= - 1- 0< ; +: > <= 0= ; -: cr 9 emit ; -: bl 32 ; -: space bl emit ; +: cr 9 emit ; +: bl 32 ; +: space bl emit ; -: state 1 ; -: base 0 ; -: decimal 1 2* base ! 1010 base ! ; +: ?dup dup if dup then ; -: ?dup dup if dup then ; +: negate -1 * ; +: abs dup 0< if negate then ; +: min 2dup <= if drop else nip then ; +: max 2dup <= if nip else drop then ; -: negate -1 * ; -: abs dup 0< if negate then ; -: min 2dup <= if drop else nip then ; -: max 2dup <= if nip else drop then ; +: begin here ; imm +: do postpone >r postpone >r here ; imm diff --git a/corewords.cpp b/corewords.cpp index 3312ef1..9b43fcf 100644 --- a/corewords.cpp +++ b/corewords.cpp @@ -20,44 +20,19 @@ Func CoreWords::get(int index) { - switch (index) { - case 0: return op_drop; - case 1: return op_dup; - case 2: return op_swap; - case 3: return op_pick; - case 4: return op_sys; - case 5: return op_add; - case 6: return op_sub; - case 7: return op_mul; - case 8: return op_div; - case 9: return op_mod; - case 10: return op_peek; - case 11: return op_poke; - case 12: return op_rot; - case 13: return op_pushr; - case 14: return op_popr; - case 15: return op_eq; - case 16: return op_lt; - case 17: return op_allot; - case 18: return op_and; - case 19: return op_or; - case 20: return op_xor; - case 21: return op_shl; - case 22: return op_shr; - case 23: return op_comment; - case 24: return op_colon; - case 25: return op_semic; // :267 - case 26: return op_here; - case 27: return op_imm; - case 28: return op_const; - case 29: return op_if; - case 30: return op_then; - case 31: return op_else; - case 32: return op_depth; - case 33: return op_literal; - case 34: return op_jump; - default: return nullptr; - } + static const Func ops[WordCount] = { + op_drop, op_dup, op_swap, op_pick, op_sys, + op_add, op_sub, op_mul, op_div, op_mod, + op_peek, op_poke, op_rot, op_pushr, op_popr, + op_eq, op_lt, op_allot, op_and, op_or, + op_xor, op_shl, op_shr, op_comment, op_colon, + op_semic, op_here, op_imm, op_const, op_depth, + op_key, op_exit, op_tick, op_execute, op_jmp, + op_jmp0, op_lit, op_literal, + op_jump + }; + + return index >= 0 && index < WordCount ? ops[index] : nullptr; } void CoreWords::op_drop(State& state) @@ -197,13 +172,37 @@ void CoreWords::op_colon(State& state) { state.pushr(state.dict.alignhere()); state.dict.addDefinition(word); } +} +void CoreWords::op_tick(State& state) { + Word word = state.dict.input(); + while (word.size() == 0) { + state.input(state); + word = state.dict.input(); + } + + Cell xt = 0; + if (auto i = CoreWords::findi(state, word); i >= 0) { + xt = i & ~CoreWords::Compiletime; + } else if (auto j = state.dict.find(word); j > 0) { + xt = state.dict.getexec(j) - sizeof(Cell); + } + + state.push(xt); +} + +void CoreWords::op_execute(State& state) { + state.execute(state.pop()); +} + +void CoreWords::op_exit(State& state) { + state.ip = state.popr(); } void CoreWords::op_semic(State& state) { - if (!state.compiling()) { - state.ip = state.popr(); - } else { + if (state.compiling()) { + state.dict.add(findi("exit")); + auto begin = state.popr(); state.dict.write(begin, @@ -213,7 +212,6 @@ void CoreWords::op_semic(State& state) { state.dict.latest = begin; state.compiling(false); } - } void CoreWords::op_here(State& state) { @@ -228,71 +226,50 @@ void CoreWords::op_imm(State& state) void CoreWords::op_const(State& state) { - if (state.compiling()) { - Word word = state.dict.input(); - while (word.size() == 0) { - state.input(state); - word = state.dict.input(); - } - - state.pushr(state.dict.alignhere()); - state.dict.addDefinition(word); - state.dict.add(CoreWords::HiddenWordLiteral); - state.dict.add(state.pop()); - state.dict.add(25 | CoreImmediate); - op_semic(state); - state.compiling(false); + Word word = state.dict.input(); + while (word.size() == 0) { + state.input(state); + word = state.dict.input(); } + state.pushr(state.dict.alignhere()); + state.dict.addDefinition(word); + state.dict.add(findi("_lit")); + state.dict.add(state.pop()); + op_semic(state); } -void CoreWords::op_literal(State& state) +void CoreWords::op_lit(State& state) { state.push(state.beyondip()); state.ip += sizeof(Cell); } -void CoreWords::op_jump(State& state) -{ - state.pushr(state.ip + sizeof(Cell)); - state.ip = state.beyondip() - sizeof(Cell); -} - -void CoreWords::op_if(State& state) +void CoreWords::op_literal(State& state) { if (state.compiling()) { - state.push(state.dict.here); - state.dict.add(0); - } else { - if (state.pop()) - state.ip += sizeof(Cell); - else - state.ip = state.beyondip() - sizeof(Cell); + state.dict.add(findi("_lit")); + state.dict.add(state.pop()); } - } -void CoreWords::op_then(State& state) +void CoreWords::op_jump(State& state) { - if (state.compiling()) { - const auto ifaddr = state.pop(); - if (state.dict.read(ifaddr) == 0) - state.dict.write(ifaddr, state.dict.here); - } - + state.pushr(state.ip + sizeof(Cell)); + state.ip = state.beyondip() - sizeof(Cell); } -void CoreWords::op_else(State& state) +void CoreWords::op_jmp(State& state) { - if (state.compiling()) { - const auto ifaddr = state.pop(); - state.push(state.dict.here); - state.dict.add(0); - state.dict.write(ifaddr, state.dict.here); - } else { - state.ip = state.beyondip() - sizeof(Cell); - } + state.ip = state.beyondip() - sizeof(Cell); +} +void CoreWords::op_jmp0(State& state) +{ + if (state.pop()) + state.ip += sizeof(Cell); + else + op_jmp(state); } void CoreWords::op_depth(State& state) @@ -314,6 +291,26 @@ void CoreWords::op_key(State& state) state.push(val); } +int CoreWords::findi(std::string_view word) +{ + std::size_t i; + int wordsi = 0; + + std::string_view words (wordsarr, sizeof(wordsarr)); + + for (i = 0; i < words.size();) { + const auto end = words.find_first_of({"\0\1", 2}, i); + + if (word == words.substr(i, end - i)) + return words[end] == '\0' ? wordsi : (wordsi | Compiletime); + + ++wordsi; + i = end + 1; + } + + return -1; +} + int CoreWords::findi(State& state, Word word) { std::size_t i; @@ -325,7 +322,7 @@ int CoreWords::findi(State& state, Word word) const auto end = words.find_first_of({"\0\1", 2}, i); if (state.dict.equal(word, words.substr(i, end - i))) - return words[end] == '\0' ? wordsi : (wordsi | CoreImmediate); + return words[end] == '\0' ? wordsi : (wordsi | Compiletime); ++wordsi; i = end + 1; @@ -337,12 +334,12 @@ int CoreWords::findi(State& state, Word word) Func CoreWords::find(State& state, Word word) { const auto i = findi(state, word); - return i >= 0 ? get(i & ~CoreWords::CoreImmediate) : nullptr; + return i >= 0 ? get(i & ~Compiletime) : nullptr; } void CoreWords::run(int i, State& state) { - i &= ~CoreWords::CoreImmediate; + i &= ~Compiletime; if (i >= 0 && i < WordCount) get(i)(state); diff --git a/corewords.hpp b/corewords.hpp index babb5aa..76c1353 100644 --- a/corewords.hpp +++ b/corewords.hpp @@ -22,32 +22,37 @@ #include "types.hpp" #include "state.hpp" +#include + void user_sys(State&); class CoreWords { public: - constexpr static std::size_t VisibleWordCount = 33; // size - constexpr static auto HiddenWordLiteral = VisibleWordCount; // index - constexpr static auto HiddenWordJump = VisibleWordCount + 1; // index - constexpr static auto WordCount = HiddenWordJump + 1; // size + constexpr static std::size_t VisibleWordCount = 38; // size + constexpr static auto HiddenWordJump = VisibleWordCount; // index + constexpr static auto WordCount = VisibleWordCount + 1; // size - constexpr static Cell Immediate = (1 << 5); - constexpr static Cell CoreImmediate = (1 << 6); + constexpr static Cell Immediate = (1 << 5); + constexpr static Cell Compiletime = (1 << 6); + static int findi(std::string_view); static int findi(State&, Word); static Func find(State&, Word); static void run(int, State&); private: + // Ends with '\0': regular word + // Ends with '\1': compile-only word constexpr static char wordsarr[] = "drop\0dup\0swap\0pick\0sys\0" "+\0-\0*\0/\0%\0" "_@\0_!\0rot\0>r\0r>\0" "=\0<\0allot\0&\0|\0" "^\0<<\0>>\0(\0:\1" - ";\1here\0imm\0const\0" - "if\1then\1else\1depth\0"; + ";\1here\0imm\0const\0depth\0" + "key\0exit\0'\0execute\0_jmp\0" + "_jmp0\0_lit\0literal\1"; static Func get(int); @@ -63,7 +68,7 @@ private: static void op_mod(State&); static void op_peek(State&); static void op_poke(State&); - static void op_rot(State&); + static void op_rot(State&); // : rot >r swap r> swap ; static void op_pushr(State&); static void op_popr(State&); static void op_eq(State&); @@ -80,14 +85,16 @@ private: static void op_here(State&); static void op_imm(State&); static void op_const(State&); - static void op_literal(State&); + static void op_lit(State&); static void op_jump(State&); - static void op_if(State&); - static void op_then(State&); - static void op_else(State&); static void op_depth(State&); static void op_key(State&); - static void op_word(State&); + static void op_exit(State&); + static void op_tick(State&); + static void op_execute(State&); + static void op_jmp(State&); + static void op_jmp0(State&); + static void op_literal(State&); // : literal ['] _lit , , ; imm }; #endif // ALEEFORTH_COREWORDS_HPP diff --git a/dictionary.hpp b/dictionary.hpp index 90234ba..e30858c 100644 --- a/dictionary.hpp +++ b/dictionary.hpp @@ -29,10 +29,11 @@ class Dictionary { public: constexpr static Addr Base = 0; - constexpr static Addr Compiling = Base + sizeof(Cell); - constexpr static Addr Input = Compiling + sizeof(Cell); // len data... + constexpr static Addr Compiling = sizeof(Cell); + constexpr static Addr Postpone = sizeof(Cell) * 2; + constexpr static Addr Input = sizeof(Cell) * 3; // len data... constexpr static Addr InputCells = 80; // bytes! - constexpr static Addr Begin = Input + sizeof(Cell) + InputCells; + constexpr static Addr Begin = sizeof(Cell) * 4 + InputCells; Addr here = Begin; Addr latest = Begin; diff --git a/parser.cpp b/parser.cpp index b44547f..b78390c 100644 --- a/parser.cpp +++ b/parser.cpp @@ -22,6 +22,8 @@ #include #include +#include + ParseStatus Parser::parse(State& state, std::string_view& str) { auto addr = Dictionary::Input; @@ -50,25 +52,42 @@ ParseStatus Parser::parseSource(State& state) ParseStatus Parser::parseWord(State& state, Word word) { + // TODO unify core-word and defined-word parsing/execution. + if (auto i = CoreWords::findi(state, word); i >= 0) { - if (state.compiling()) - state.dict.add(i & ~CoreWords::CoreImmediate); - else if (state.dict.equal(word, ":")) - state.compiling(true); + auto p = state.dict.read(Dictionary::Postpone); + auto imm = (i & CoreWords::Compiletime); + + if (state.compiling() || p) { + if (p || !imm) { + state.dict.add(i & ~CoreWords::Compiletime); + + if (p) + state.dict.write(Dictionary::Postpone, 0); + } else if (imm) { + CoreWords::run(i & ~CoreWords::Compiletime, state); + } + } else { + if (state.dict.equal(word, ":")) + state.compiling(true); - if (!state.compiling() || (i & CoreWords::CoreImmediate)) - CoreWords::run(i & ~CoreWords::CoreImmediate, state); + CoreWords::run(i & ~CoreWords::Compiletime, state); + } } else if (auto j = state.dict.find(word); j > 0) { auto e = state.dict.getexec(j); + auto p = state.dict.read(Dictionary::Postpone); - if (state.compiling()) { - if (state.dict.read(j) & CoreWords::Immediate) { - state.compiling(false); - state.execute(e); - state.compiling(true); - } else { + if (state.compiling() || p) { + auto imm = state.dict.read(j) & CoreWords::Immediate; + + if (p || !imm) { state.dict.add(CoreWords::HiddenWordJump); state.dict.add(e); + + if (p) + state.dict.write(Dictionary::Postpone, 0); + } else if (imm) { + state.execute(e); } } else { state.execute(e); @@ -85,12 +104,13 @@ ParseStatus Parser::parseWord(State& state, Word word) if (std::distance(buf, p) == word.size()) { if (state.compiling()) { - state.dict.add(CoreWords::HiddenWordLiteral); + state.dict.add(CoreWords::findi("_lit")); state.dict.add(l); } else { state.push(l); } } else { + std::cout << "word not found: " << buf << std::endl; return ParseStatus::NotAWord; } } diff --git a/state.cpp b/state.cpp index 0fe0905..6d056ba 100644 --- a/state.cpp +++ b/state.cpp @@ -40,13 +40,18 @@ void State::compiling(bool yes) void State::execute(Addr addr) { - pushr(0); - ip = addr - sizeof(Cell); - - do { - ip += sizeof(Cell); - CoreWords::run(dict.read(ip), *this); - } while (ip); + if (addr < Dictionary::Begin) { + // Must be a core-word + CoreWords::run(addr, *this); + } else { + pushr(0); + ip = addr - sizeof(Cell); + + do { + ip += sizeof(Cell); + CoreWords::run(dict.read(ip), *this); + } while (ip); + } } Cell State::beyondip() const