From: Clyne Sullivan Date: Tue, 14 Nov 2023 03:04:32 +0000 (-0500) Subject: Merge branch 'documentation' X-Git-Url: https://code.bitgloo.com/?a=commitdiff_plain;h=ebbde43fa98315a57a15650944f80757f9652b9b;p=bitgloo%2Falee-forth.git Merge branch 'documentation' --- ebbde43fa98315a57a15650944f80757f9652b9b diff --cc libalee/corewords.cpp index b768163,661590f..7c79aea --- a/libalee/corewords.cpp +++ b/libalee/corewords.cpp @@@ -20,24 -21,10 +20,11 @@@ #include - LIBALEE_SECTION - void find(State& state, Word word) - { - Cell tok = 0; - Cell imm = 0; - - if (auto j = state.dict.find(word); j > 0) { - tok = state.dict.getexec(j); - imm = (state.dict.read(j) & Dictionary::Immediate) ? 1 : -1; - } else if (tok = CoreWords::findi(state, word); tok >= 0) { - imm = (tok == CoreWords::Semicolon) ? 1 : -1; - } - - state.push(tok); - state.push(imm); - } + static void find(State&, Word); + static DoubleCell popd(State&); + static void pushd(State&, DoubleCell); +LIBALEE_SECTION void CoreWords::run(Cell ins, State& state) { Cell cell; @@@ -259,3 -235,33 +236,34 @@@ Cell CoreWords::findi(State& state, Wor return findi(word.begin(&state.dict), word.size()); } ++LIBALEE_SECTION + void find(State& state, Word word) + { + Cell tok = 0; + Cell imm = 0; + + if (auto j = state.dict.find(word); j > 0) { + tok = state.dict.getexec(j); + imm = (state.dict.read(j) & Dictionary::Immediate) ? 1 : -1; + } else if (tok = CoreWords::findi(state, word); tok >= 0) { + imm = (tok == CoreWords::token(";")) ? 1 : -1; + } + + state.push(tok); + state.push(imm); + } + + DoubleCell popd(State& s) + { + DoubleCell dcell = s.pop(); + dcell <<= sizeof(Cell) * 8; + dcell |= static_cast(s.pop()); + return dcell; + } + + void pushd(State& s, DoubleCell d) + { + s.push(static_cast(d)); + s.push(static_cast(d >> (sizeof(Cell) * 8))); + } + diff --cc libalee/corewords.hpp index f4ab851,630f3cf..30d0a42 --- a/libalee/corewords.hpp +++ b/libalee/corewords.hpp @@@ -19,9 -21,11 +21,13 @@@ #ifndef ALEEFORTH_COREWORDS_HPP #define ALEEFORTH_COREWORDS_HPP +#include "config.hpp" - #include "types.hpp" +#include "dictionary.hpp" + #include "types.hpp" -#include "state.hpp" + + #include -#include ++ ++class State; /** * To be implemented by the user, this function is called when the `sys` word @@@ -32,16 -41,23 +43,23 @@@ void user_sys(State& state) class CoreWords { public: - constexpr static Cell WordCount = 37; - constexpr static Cell Semicolon = 26; + /** + * Searches for the token/index of the given word if it is part of the + * fundamental word-set. + * @param state Current execution state object. + * @param word Word (stored in state's dictionary memory) to look up. + * @return The token/index of the word or -1 if not found. + */ + static Cell findi(State& state, Word word); /** - * Finds execution token that corresponds to the given word. - * Returns -1 if not found. + * Looks up the token/index of the given fundamental word. + * Primarily used for compile-time lookup. + * @param word The word to look up. + * @return The token/index of the word or -1 if not found. */ - static Cell findi(State&, Word); - consteval static Cell findi(const char *word) { + consteval static Cell token(const char *word) { - return findi(word, std::strlen(word)); + return findi(word, strlen(word)); } /** @@@ -59,9 -81,20 +83,21 @@@ "depth\0_rdepth\0_in\0_ev\0find\0" "_uma\0u<\0um/mod\0"; + /** + * Count of total fundamental words. + */ + constexpr static Cell WordCount = [] { + return std::count(wordsarr, wordsarr + sizeof(wordsarr), '\0'); }(); + private: + /** + * Generic implementation of findi(). Private; use public implementations. + * @param it Beginning iterator of the word to search for. + * @param size Size of the searched-for word i.e. end == it + size. + * @return The token/index of the word or -1 if not found. + */ template + LIBALEE_SECTION constexpr static Cell findi(Iter it, std::size_t size) { const char *ptr = CoreWords::wordsarr; diff --cc libalee/ctype.hpp index b0df174,5252eda..f7ce3fb --- a/libalee/ctype.hpp +++ b/libalee/ctype.hpp @@@ -19,18 -21,9 +21,16 @@@ #ifndef ALEEFORTH_CTYPE_HPP #define ALEEFORTH_CTYPE_HPP - /** - * We implement our own character comparison functions to keep them lean. - */ - #include ++/** Determines the length of a null-terminated string. */ +constexpr inline unsigned strlen(const char * const s) { + unsigned i = 0; + while (s[i]) i++; + return i; +} + + /** Tests if given character represents whitespace. */ constexpr inline bool isspace(uint8_t c) { return c == ' ' || c == '\t' || c == '\r' || c == '\n'; } @@@ -43,10 -38,7 +45,12 @@@ constexpr inline bool isupper(uint8_t c return c >= 'A' && c <= 'Z'; } ++/** Tests if given character is a lowercase letter. */ +constexpr inline bool islower(uint8_t c) { + return c >= 'a' && c <= 'z'; +} + + /** Tests if given character is a letter. */ constexpr inline bool isalpha(uint8_t c) { return isupper(c) || (c >= 'a' && c <= 'z'); } diff --cc libalee/dictionary.hpp index 27edf68,f6f6bbe..ad1ee02 --- a/libalee/dictionary.hpp +++ b/libalee/dictionary.hpp @@@ -73,30 -96,59 +97,63 @@@ public */ void initialize(); + /** + * Gets the address stored in `here`. + */ + LIBALEE_SECTION Addr here() const noexcept { return read(Here); } + + /** + * Sets the address stored in `here`. + */ + LIBALEE_SECTION void here(Addr l) noexcept { write(Here, l); } + /** + * Gets the value of `latest`. + */ + LIBALEE_SECTION Addr latest() const noexcept { return read(Latest); } + + /** + * Sets the value of `latest`. + */ + LIBALEE_SECTION void latest(Addr l) noexcept { write(Latest, l); } - // Aligns the given address. - static Addr aligned(Addr); - // Aligns `here`. + /** + * Aligns the given address to the next Cell boundary if necessary. + * @param addr The address to align. + * @return The resulting aligned address. + */ + static Addr aligned(Addr addr); + + /** + * Aligns `here` to the next Cell boundary if necessary. + * @return The new aligned address stored in `here`. + */ Addr alignhere() noexcept; - // Advances `here` by the given number of bytes. - Addr allot(Cell) noexcept; - // Stores value to `here`, then adds sizeof(Cell) to `here`. - void add(Cell) noexcept; /** - * Uses add() to store a new definition entry starting at `here`. - * The entry does not become active until a semicolon is executed. + * Allocates memory by returning and then increasing the current `here`. + * @param count The number of bytes to increase `here` by. + * @return The address stored in `here` before the increase. */ - void addDefinition(Word) noexcept; + Addr allot(Cell count) noexcept; + + /** + * Stores the given value to `here` then calls allot to "save" that cell. + * @param value The value to store. + * @see allot(Cell) + */ + void add(Cell value) noexcept; + + /** + * Stores the beginning of a new word definition in the dictionary. + * The word must eventually have its definition concluded via semicolon. + * @param word The dictionary-stored name of the new word. + */ + void addDefinition(Word word) noexcept; /** * Searches the dictionary for an entry for the given word. @@@ -118,27 -178,38 +183,40 @@@ bool hasInput() const noexcept; /** - * Checks if this dictionary's word is equivalent to the given string/size. + * Checks if the dictionary-stored word is equivalent to the given string. + * @param word Dictionary-stored word to compare against. + * @param str String to compare to. + * @param size Size of the string to compare to. + * @return True if the two words are equivalent. */ - bool equal(Word, const char *, unsigned) const noexcept; + bool equal(Word word, const char *str, unsigned size) const noexcept; /** - * Checks if two words in this dictionary's word are equivalent. + * Checks if two words stored in this dictionary are equivalent. + * @param word1 First word to compare + * @param word2 Second word to compare + * @return True if the words are equivalent. */ - bool equal(Word, Word) const noexcept; + bool equal(Word word1, Word word2) const noexcept; - // Used for case-insensitive comparison between two iterators. + /** + * Generic equality comparison using our own case-insensitive comparator. + * Arguments and return value identical to std::equal. + */ template + LIBALEE_SECTION constexpr static bool equal(Iter1 b1, Iter1 e1, Iter2 b2) { return std::equal(b1, e1, b2, eqchars); } - virtual ~Dictionary() = default; + virtual ~Dictionary() {}; private: - // Case-insensitive comparison. + /** + * Case-insensitive character comparison used for dictionary lookup. + * @return True if the characters are equivalent. + */ + LIBALEE_SECTION constexpr static bool eqchars(char c1, char c2) { if (isalpha(static_cast(c1))) c1 |= 32; diff --cc libalee/parser.cpp index b3e8211,3699d5f..11aba38 --- a/libalee/parser.cpp +++ b/libalee/parser.cpp @@@ -25,7 -29,8 +25,8 @@@ Error Parser::parse(State& state, cons { auto addr = Dictionary::Input; + // Set source and input length - const auto len = static_cast(std::strlen(str)); + const auto len = static_cast(strlen(str)); state.dict.write(addr, 0); state.dict.write(Dictionary::SourceLen, len); diff --cc libalee/state.hpp index 0ac9a7c,60ff95f..a5e49b5 --- a/libalee/state.hpp +++ b/libalee/state.hpp @@@ -58,12 -81,12 +82,14 @@@ public */ void reset(); + /** Returns a reference to the instruction pointer. */ + LIBALEE_SECTION Addr& ip() noexcept { return context.ip; } + /** Calls the user input function with this state as the argument. */ + LIBALEE_SECTION void input() noexcept { inputfunc(*this); } @@@ -85,50 -111,70 +114,78 @@@ */ void load(const Context&); + /** + * Pushes the given value to the data stack. + */ + LIBALEE_SECTION inline void push(Cell value) { verify(dsp < dstack + DataStackSize, Error::push); *dsp++ = value; } + /** + * Pops a value from the data stack and returns that value. + */ + LIBALEE_SECTION inline Cell pop() { verify(dsp > dstack, Error::pop); return *--dsp; } + /** + * Pushes the given value to the return stack. + */ + LIBALEE_SECTION inline void pushr(Cell value) { verify(rsp < rstack + ReturnStackSize, Error::pushr); *rsp++ = value; } + /** + * Pops a value from the return stack and returns that value. + */ + LIBALEE_SECTION inline Cell popr() { verify(rsp > rstack, Error::popr); return *--rsp; } + /** + * Returns the value stored at the current data stack position. + */ + LIBALEE_SECTION inline Cell& top() { verify(dsp > dstack, Error::top); return *(dsp - 1); } + /** + * Picks a value currently stored on the data stack. + * @param i Index from current position to fetch from + * @return The value stored at the given index + */ + LIBALEE_SECTION inline Cell& pick(std::size_t i) { verify(dsp - i > dstack, Error::pick); return *(dsp - i - 1); } - // Advances the instruction pointer and returns that cell's contents. + /** + * Advances the instruction pointer and returns that cell's contents. + */ + LIBALEE_SECTION inline Cell beyondip() { context.ip += sizeof(Cell); return dict.read(context.ip); } + /** + * Asserts the given condition is true, longjmp-ing if false. + * Used as an exception handler and the method of exiting execution. + * @param condition Condition to be tested + * @param error Error code to report via longjmp() on false condition + */ + LIBALEE_SECTION inline void verify(bool condition, Error error) { if (!condition) std::longjmp(context.jmpbuf, static_cast(error)); diff --cc libalee/types.hpp index 028c490,a122c84..7b5bb62 --- a/libalee/types.hpp +++ b/libalee/types.hpp @@@ -61,7 -73,12 +73,13 @@@ public constexpr explicit Word(Addr s = 0, Addr e = 0): start(s), wend(e) {} + /** + * Constructs a word using beginning index and length. + * @param s Beginning/start index of word + * @param l Count of bytes until end of word + * @return Resulting Word object + */ + LIBALEE_SECTION static constexpr Word fromLength(Addr s, Addr l) { return Word(s, s + l); } diff --cc memdict.hpp index 003b3a7,b1dbe55..9861921 --- a/memdict.hpp +++ b/memdict.hpp @@@ -19,15 -21,23 +21,23 @@@ #ifndef ALEEFORTH_MEMDICT_HPP #define ALEEFORTH_MEMDICT_HPP -#include "alee.hpp" +#include "libalee/alee.hpp" #ifndef MEMDICTSIZE + /** Default dictionary size in bytes. */ #define MEMDICTSIZE (65536) #endif + + /** Size in bytes of a MemDict. */ constexpr unsigned long int MemDictSize = MEMDICTSIZE; + /** + * @class MemDict + * Dictionary implementation that uses a large block of memory. + */ class MemDict : public Dictionary { + /** Block of memory to contain dictionary's contents. */ uint8_t dict[MemDictSize] = {0}; public: