Index: forth/Forth.cpp |
diff --git a/forth/Forth.cpp b/forth/Forth.cpp |
deleted file mode 100644 |
index 1dd4c73e4a9ee1753c30211015e356c88c1df6a0..0000000000000000000000000000000000000000 |
--- a/forth/Forth.cpp |
+++ /dev/null |
@@ -1,501 +0,0 @@ |
- |
-/* |
- * Copyright 2011 Google Inc. |
- * |
- * Use of this source code is governed by a BSD-style license that can be |
- * found in the LICENSE file. |
- */ |
-#include "Forth.h" |
-#include "ForthParser.h" |
-#include "SkTDArray.h" |
-#include "SkString.h" |
-#include "SkTDStack.h" |
- |
-ForthEngine::ForthEngine(ForthOutput* output) : fOutput(output) { |
- size_t size = 32 * sizeof(intptr_t); |
- fStackBase = reinterpret_cast<intptr_t*>(sk_malloc_throw(size)); |
- fStackStop = fStackBase + size/sizeof(intptr_t); |
- fStackCurr = fStackStop; |
-} |
- |
-ForthEngine::~ForthEngine() { |
- sk_free(fStackBase); |
-} |
- |
-void ForthEngine::sendOutput(const char text[]) { |
- if (fOutput) { |
- fOutput->show(text); |
- } else { |
- SkDebugf("%s", text); |
- } |
-} |
- |
-void ForthEngine::push(intptr_t value) { |
- if (fStackCurr > fStackBase) { |
- SkASSERT(fStackCurr <= fStackStop && fStackCurr > fStackBase); |
- *--fStackCurr = value; |
- } else { |
- this->signal_error("overflow"); |
- } |
-} |
- |
-intptr_t ForthEngine::peek(size_t index) const { |
- SkASSERT(fStackCurr < fStackStop && fStackCurr >= fStackBase); |
- if (fStackCurr + index < fStackStop) { |
- return fStackCurr[index]; |
- } else { |
- this->signal_error("peek out of range"); |
- return 0x80000001; |
- } |
-} |
- |
-void ForthEngine::setTop(intptr_t value) { |
- if (fStackCurr < fStackStop) { |
- SkASSERT(fStackCurr < fStackStop && fStackCurr >= fStackBase); |
- *fStackCurr = value; |
- } else { |
- this->signal_error("underflow"); |
- } |
-} |
- |
-intptr_t ForthEngine::pop() { |
- if (fStackCurr < fStackStop) { |
- SkASSERT(fStackCurr < fStackStop && fStackCurr >= fStackBase); |
- return *fStackCurr++; |
- } else { |
- this->signal_error("underflow"); |
- return 0x80000001; |
- } |
-} |
- |
-/////////////////////////////////////////////////////////////////////////////// |
- |
-void ForthWord::call(ForthCallBlock* block) { |
- ForthEngine engine(NULL); |
- |
- // setup the initial stack with the callers input data |
- if (block) { |
- // walk the array backwards, so that the top of the stack is data[0] |
- for (size_t i = 0; i < block->in_count; i++) { |
- engine.push(block->in_data[i]); |
- } |
- } |
- |
- // now invoke the word |
- this->exec(&engine); |
- |
- // now copy back the stack into the caller's output data |
- if (block) { |
- size_t n = engine.depth(); |
- block->out_depth = n; |
- if (n > block->out_count) { |
- n = block->out_count; |
- } |
- for (size_t i = 0; i < n; i++) { |
- block->out_data[i] = engine.peek(i); |
- } |
- } |
-} |
- |
-/////////////////////////////////////////////////////////////////////////////// |
- |
-/* |
- reading an initial 32bit value from the code stream: |
- |
- xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx00 |
- |
- Those last two bits are always 0 for a word, so we set those bits for other |
- opcodes |
- |
- 00 -- execute this word |
- 01 -- push (value & ~3) on the data stack |
- 10 -- push value >> 2 on the data stack (sign extended) |
- 11 -- switch (value >>> 2) for Code |
- */ |
- |
-class FCode { |
-public: |
- enum { |
- kCodeShift = 2, |
- kCodeMask = 7, |
- kCodeDataShift = 5 |
- }; |
- static unsigned GetCode(intptr_t c) { |
- return ((uint32_t)c >> kCodeShift) & kCodeMask; |
- } |
- static unsigned GetCodeData(intptr_t c) { |
- return (uint32_t)c >> kCodeDataShift; |
- } |
- |
- enum Bits { |
- kWord_Bits = 0, // must be zero for function address |
- kDataClear2_Bits = 1, |
- kDataShift2_Bits = 2, |
- kCodeShift2_Bits = 3 |
- }; |
- |
- enum Code { |
- kPushInt_Code, // for data that needs more than 30 bits |
- kIF_Code, |
- kELSE_Code, |
- kDone_Code |
- }; |
- static unsigned MakeCode(Code code) { |
- return (code << kCodeShift) | kCodeShift2_Bits; |
- } |
- |
- void appendInt(int32_t); |
- void appendWord(ForthWord*); |
- void appendIF(); |
- bool appendELSE(); |
- bool appendTHEN(); |
- void done(); |
- |
- intptr_t* detach() { |
- this->done(); |
- return fData.detach(); |
- } |
- intptr_t* begin() { |
- this->done(); |
- return fData.begin(); |
- } |
- |
- static void Exec(const intptr_t*, ForthEngine*); |
- |
-private: |
- SkTDArray<intptr_t> fData; |
- SkTDStack<size_t> fIfStack; |
-}; |
- |
-void FCode::appendInt(int32_t value) { |
- if ((value & 3) == 0) { |
- *fData.append() = value | kDataClear2_Bits; |
- } else if ((value << 2 >> 2) == value) { |
- *fData.append() = (value << 2) | kDataShift2_Bits; |
- } else { |
- intptr_t* p = fData.append(2); |
- *p++ = (kPushInt_Code << 2) | kCodeShift2_Bits; |
- *p++ = value; |
- } |
-} |
- |
-void FCode::appendWord(ForthWord* word) { |
- SkASSERT((reinterpret_cast<intptr_t>(word) & 3) == 0); |
- *fData.append() = reinterpret_cast<intptr_t>(word); |
-} |
- |
-void FCode::appendIF() { |
- size_t ifIndex = fData.count(); |
- fIfStack.push(ifIndex); |
- *fData.append() = MakeCode(kIF_Code); |
-} |
- |
-bool FCode::appendELSE() { |
- if (fIfStack.empty()) { |
- return false; |
- } |
- |
- size_t elseIndex = fData.count(); |
- *fData.append() = MakeCode(kELSE_Code); |
- |
- size_t ifIndex = fIfStack.top(); |
- // record the offset in the data part of the if-code |
- fData[ifIndex] |= (elseIndex - ifIndex) << kCodeDataShift; |
- |
- // now reuse this IfStack entry to track the else |
- fIfStack.top() = elseIndex; |
- return true; |
-} |
- |
-bool FCode::appendTHEN() { |
- if (fIfStack.empty()) { |
- return false; |
- } |
- |
- // this is either an IF or an ELSE |
- size_t index = fIfStack.top(); |
- // record the offset in the data part of the code |
- fData[index] |= (fData.count() - index - 1) << kCodeDataShift; |
- |
- fIfStack.pop(); |
- return true; |
-} |
- |
-void FCode::done() { |
- *fData.append() = (kDone_Code << 2) | kCodeShift2_Bits; |
-} |
- |
-void FCode::Exec(const intptr_t* curr, ForthEngine* engine) { |
- for (;;) { |
- intptr_t c = *curr++; |
- switch (c & 3) { |
- case kWord_Bits: |
- reinterpret_cast<ForthWord*>(c)->exec(engine); |
- break; |
- case kDataClear2_Bits: |
- engine->push(c & ~3); |
- break; |
- case kDataShift2_Bits: |
- engine->push(c >> 2); |
- break; |
- case kCodeShift2_Bits: |
- switch (GetCode(c)) { |
- case kPushInt_Code: |
- engine->push(*curr++); |
- break; |
- case kIF_Code: |
- if (!engine->pop()) { |
- // takes us past the ELSE or THEN |
- curr += GetCodeData(c); |
- } |
- break; |
- case kELSE_Code: |
- // takes us past the THEN |
- curr += GetCodeData(c); |
- break; |
- case kDone_Code: |
- return; |
- } |
- break; |
- } |
- } |
-} |
- |
-/////////////////////////////////////////////////////////////////////////////// |
- |
-class CustomWord : public ForthWord { |
-public: |
- // we assume ownership of code[] |
- CustomWord(intptr_t code[]) : fCode(code) {} |
- virtual ~CustomWord() { sk_free(fCode); } |
- |
- virtual void exec(ForthEngine* engine) { |
- FCode::Exec(fCode, engine); |
- } |
- |
-private: |
- intptr_t* fCode; |
-}; |
- |
-/////////////////////////////////////////////////////////////////////////////// |
- |
-ForthParser::ForthParser() : fDict(4096) { |
- this->addStdWords(); |
-} |
- |
-ForthParser::~ForthParser() { |
- SkTDict<ForthWord*>::Iter iter(fDict); |
- ForthWord* word; |
- while (iter.next(&word)) { |
- delete word; |
- } |
-} |
- |
-static const char* parse_error(const char msg[]) { |
- SkDebugf("-- parser error: %s\n", msg); |
- return NULL; |
-} |
- |
-/** returns true if c is whitespace, including null |
- */ |
-static bool is_ws(int c) { |
- return c <= ' '; |
-} |
- |
-static const char* parse_token(const char** text, size_t* len) { |
- const char* s = *text; |
- while (is_ws(*s)) { |
- if (0 == *s) { |
- return NULL; |
- } |
- s++; |
- } |
- const char* token = s++; |
- while (!is_ws(*s)) { |
- s++; |
- } |
- *text = s; |
- *len = s - token; |
- return token; |
-} |
- |
-static bool is_digit(int c) { return (unsigned)(c - '0') <= 9; } |
-static int hex_val(int c) { |
- if (is_digit(c)) { |
- return c - '0'; |
- } else { |
- if (c <= 'Z') { |
- return 10 + c - 'A'; |
- } else { |
- return 10 + c - 'a'; |
- } |
- } |
-} |
- |
-static bool parse_num(const char str[], size_t len, int32_t* numBits) { |
- if (1 == len && !is_digit(*str)) { |
- return false; |
- } |
- const char* start = str; |
- int32_t num = 0; |
- bool neg = false; |
- if (*str == '-') { |
- neg = true; |
- str += 1; |
- } else if (*str == '#') { |
- str++; |
- while (str - start < len) { |
- num = num*16 + hex_val(*str); |
- str += 1; |
- } |
- *numBits = num; |
- return true; |
- } |
- |
- while (is_digit(*str)) { |
- num = 10*num + *str - '0'; |
- str += 1; |
- } |
- SkASSERT(str - start <= len); |
- if (str - start == len) { |
- if (neg) { |
- num = -num; |
- } |
- *numBits = num; |
- return true; |
- } |
- // if we're not done with the token then the next char must be a decimal |
- if (*str != '.') { |
- return false; |
- } |
- str += 1; |
- float x = num; |
- float denom = 1; |
- while (str - start < len && is_digit(*str)) { |
- x = 10*x + *str - '0'; |
- denom *= 10; |
- str += 1; |
- } |
- x /= denom; |
- if (str - start == len) { |
- if (neg) { |
- x = -x; |
- } |
- *numBits = f2i_bits(x); |
- return true; |
- } |
- return false; |
-} |
- |
-static const char* parse_comment(const char text[]) { |
- SkASSERT(*text == '('); |
- while (')' != *++text) { |
- if (0 == *text) { |
- return NULL; |
- } |
- } |
- return text + 1; // skip past the closing ')' |
-} |
- |
-const char* ForthParser::parse(const char text[], FCode* code) { |
- for (;;) { |
- size_t len; |
- const char* token = parse_token(&text, &len); |
- if (NULL == token) { |
- break; |
- } |
- if (1 == len) { |
- if ('(' == *token) { |
- text = parse_comment(token); |
- if (NULL == text) { |
- return NULL; |
- } |
- continue; |
- } |
- if (';' == *token) { |
- break; |
- } |
- if (':' == *token) { |
- token = parse_token(&text, &len); |
- if (NULL == token) { |
- return parse_error("missing name after ':'"); |
- } |
- FCode subCode; |
- text = this->parse(text, &subCode); |
- if (NULL == text) { |
- return NULL; |
- } |
- this->add(token, len, new CustomWord(subCode.detach())); |
- continue; |
- } |
- } |
- int32_t num; |
- if (parse_num(token, len, &num)) { |
- // note that num is just the bit representation of the float |
- code->appendInt(num); |
- } else if (2 == len && memcmp(token, "IF", 2) == 0) { |
- code->appendIF(); |
- } else if (4 == len && memcmp(token, "ELSE", 4) == 0) { |
- if (!code->appendELSE()) { |
- return parse_error("ELSE with no matching IF"); |
- } |
- } else if (4 == len && memcmp(token, "THEN", 4) == 0) { |
- if (!code->appendTHEN()) { |
- return parse_error("THEN with no matching IF"); |
- } |
- } else{ |
- ForthWord* word = this->find(token, len); |
- if (NULL == word) { |
- SkString str(token, len); |
- str.prepend("unknown word "); |
- return parse_error(str.c_str()); |
- } |
- code->appendWord(word); |
- } |
- } |
- return text; |
-} |
- |
-/////////////////////////////////////////////////////////////////////////////// |
- |
-class ForthEnv::Impl { |
-public: |
- ForthParser fParser; |
- FCode fBuilder; |
-}; |
- |
-ForthEnv::ForthEnv() { |
- fImpl = new Impl; |
-} |
- |
-ForthEnv::~ForthEnv() { |
- delete fImpl; |
-} |
- |
-void ForthEnv::addWord(const char name[], ForthWord* word) { |
- fImpl->fParser.addWord(name, word); |
-} |
- |
-void ForthEnv::parse(const char text[]) { |
- fImpl->fParser.parse(text, &fImpl->fBuilder); |
-} |
- |
-ForthWord* ForthEnv::findWord(const char name[]) { |
- return fImpl->fParser.find(name, strlen(name)); |
-} |
- |
-void ForthEnv::run(ForthOutput* output) { |
- ForthEngine engine(output); |
- FCode::Exec(fImpl->fBuilder.begin(), &engine); |
-} |
- |
-#if 0 |
-void ForthEnv::run(const char text[], ForthOutput* output) { |
- FCode builder; |
- |
- if (fImpl->fParser.parse(text, &builder)) { |
- ForthEngine engine(output); |
- FCode::Exec(builder.begin(), &engine); |
- } |
-} |
-#endif |