#include <utility>
- 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;
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<Addr>(s.pop());
+ return dcell;
+ }
+
+ void pushd(State& s, DoubleCell d)
+ {
+ s.push(static_cast<Cell>(d));
+ s.push(static_cast<Cell>(d >> (sizeof(Cell) * 8)));
+ }
+
#ifndef ALEEFORTH_COREWORDS_HPP
#define ALEEFORTH_COREWORDS_HPP
- #include "types.hpp"
+#include "config.hpp"
-#include "state.hpp"
+#include "dictionary.hpp"
+ #include "types.hpp"
-#include <cstring>
+
+ #include <algorithm>
++
++class State;
/**
* To be implemented by the user, this function is called when the `sys` word
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));
}
/**
"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<typename Iter>
+ LIBALEE_SECTION
constexpr static Cell findi(Iter it, std::size_t size)
{
const char *ptr = CoreWords::wordsarr;
#ifndef ALEEFORTH_CTYPE_HPP
#define ALEEFORTH_CTYPE_HPP
- /**
- * We implement our own character comparison functions to keep them lean.
- */
-
#include <cstdint>
++/** 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';
}
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');
}
*/
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.
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<typename Iter1, typename Iter2>
+ 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<uint8_t>(c1)))
c1 |= 32;
{
auto addr = Dictionary::Input;
- const auto len = static_cast<Cell>(std::strlen(str));
+ // Set source and input length
+ const auto len = static_cast<Cell>(strlen(str));
state.dict.write(addr, 0);
state.dict.write(Dictionary::SourceLen, len);
*/
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);
}
*/
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<int>(error));
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);
}
#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: