diff options
author | reed@android.com <reed@android.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2009-08-30 03:24:51 +0000 |
---|---|---|
committer | reed@android.com <reed@android.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2009-08-30 03:24:51 +0000 |
commit | 19a89f287f3af6fd34470a7aab92a989109d513f (patch) | |
tree | 3eb98a091bac5d86303ec70962cc282b141a7798 | |
parent | f56e295e88f4ed42f4c94c54d5fc544ed0f45f18 (diff) |
add boolean tests and IF/ELSE/END
git-svn-id: http://skia.googlecode.com/svn/trunk@344 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r-- | forth/Forth.cpp | 370 | ||||
-rw-r--r-- | forth/SampleForth.cpp | 6 | ||||
-rw-r--r-- | include/core/SkTDStack.h | 2 | ||||
-rw-r--r-- | xcode/sampleapp/SampleApp.xcodeproj/project.pbxproj | 8 |
4 files changed, 101 insertions, 285 deletions
diff --git a/forth/Forth.cpp b/forth/Forth.cpp index 722ed08728..01ed204a4f 100644 --- a/forth/Forth.cpp +++ b/forth/Forth.cpp @@ -1,7 +1,8 @@ #include "Forth.h" +#include "ForthParser.h" #include "SkTDArray.h" -#include "SkTDict.h" #include "SkString.h" +#include "SkTDStack.h" ForthEngine::ForthEngine(ForthOutput* output) : fOutput(output) { size_t size = 32 * sizeof(intptr_t); @@ -22,8 +23,6 @@ void ForthEngine::sendOutput(const char text[]) { } } -///////////////// ints - void ForthEngine::push(intptr_t value) { if (fStackCurr > fStackBase) { SkASSERT(fStackCurr <= fStackStop && fStackCurr > fStackBase); @@ -66,13 +65,19 @@ intptr_t ForthEngine::pop() { 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; @@ -87,220 +92,6 @@ void ForthWord::call(ForthCallBlock* block) { /////////////////////////////////////////////////////////////////////////////// -class drop_ForthWord : public ForthWord { -public: - virtual void exec(ForthEngine* fe) { - (void)fe->pop(); - } -}; - -class clearStack_ForthWord : public ForthWord { -public: - virtual void exec(ForthEngine* fe) { - fe->clearStack(); - } -}; - -class dup_ForthWord : public ForthWord { -public: - virtual void exec(ForthEngine* fe) { - fe->push(fe->top()); - } -}; - -class swap_ForthWord : public ForthWord { -public: - virtual void exec(ForthEngine* fe) { - int32_t a = fe->pop(); - int32_t b = fe->top(); - fe->setTop(a); - fe->push(b); - } -}; - -///////////////// ints - -class add_ForthWord : public ForthWord { -public: - virtual void exec(ForthEngine* fe) { - intptr_t tmp = fe->pop(); - fe->setTop(fe->top() + tmp); - } -}; - -class sub_ForthWord : public ForthWord { -public: - virtual void exec(ForthEngine* fe) { - intptr_t tmp = fe->pop(); - fe->setTop(fe->top() - tmp); - } -}; - -class mul_ForthWord : public ForthWord { -public: - virtual void exec(ForthEngine* fe) { - intptr_t tmp = fe->pop(); - fe->setTop(fe->top() * tmp); - } -}; - -class div_ForthWord : public ForthWord { -public: - virtual void exec(ForthEngine* fe) { - intptr_t tmp = fe->pop(); - fe->setTop(fe->top() / tmp); - } -}; - -class dot_ForthWord : public ForthWord { -public: - virtual void exec(ForthEngine* fe) { - SkString str; - str.printf("%d ", fe->pop()); - fe->sendOutput(str.c_str()); - } -}; - -class abs_ForthWord : public ForthWord { -public: - virtual void exec(ForthEngine* fe) { - int32_t value = fe->top(); - if (value < 0) { - fe->setTop(-value); - } - } -}; - -class min_ForthWord : public ForthWord { -public: - virtual void exec(ForthEngine* fe) { - int32_t value = fe->pop(); - if (value < fe->top()) { - fe->setTop(value); - } - } -}; - -class max_ForthWord : public ForthWord { -public: - virtual void exec(ForthEngine* fe) { - int32_t value = fe->pop(); - if (value > fe->top()) { - fe->setTop(value); - } - } -}; - -///////////////// floats - -class fadd_ForthWord : public ForthWord { -public: - virtual void exec(ForthEngine* fe) { - float tmp = fe->fpop(); - fe->fsetTop(fe->ftop() + tmp); - } -}; - -class fsub_ForthWord : public ForthWord { -public: - virtual void exec(ForthEngine* fe) { - float tmp = fe->fpop(); - fe->fsetTop(fe->ftop() - tmp); - } -}; - -class fmul_ForthWord : public ForthWord { -public: - virtual void exec(ForthEngine* fe) { - float tmp = fe->fpop(); - fe->fsetTop(fe->ftop() * tmp); - } -}; - -class fdiv_ForthWord : public ForthWord { -public: - virtual void exec(ForthEngine* fe) { - float tmp = fe->fpop(); - fe->fsetTop(fe->ftop() / tmp); - } -}; - -class fdot_ForthWord : public ForthWord { -public: - virtual void exec(ForthEngine* fe) { - SkString str; - str.printf("%g ", fe->fpop()); - fe->sendOutput(str.c_str()); - } -}; - -class fabs_ForthWord : public ForthWord { -public: - virtual void exec(ForthEngine* fe) { - float value = fe->ftop(); - if (value < 0) { - fe->fsetTop(-value); - } - } -}; - -class fmin_ForthWord : public ForthWord { -public: - virtual void exec(ForthEngine* fe) { - float value = fe->fpop(); - if (value < fe->ftop()) { - fe->fsetTop(value); - } - } -}; - -class fmax_ForthWord : public ForthWord { -public: - virtual void exec(ForthEngine* fe) { - float value = fe->fpop(); - if (value > fe->ftop()) { - fe->fsetTop(value); - } - } -}; - -class floor_ForthWord : public ForthWord { -public: - virtual void exec(ForthEngine* fe) { - fe->fsetTop(floorf(fe->ftop())); - } -}; - -class ceil_ForthWord : public ForthWord { -public: - virtual void exec(ForthEngine* fe) { - fe->fsetTop(ceilf(fe->ftop())); - } -}; - -class round_ForthWord : public ForthWord { -public: - virtual void exec(ForthEngine* fe) { - fe->fsetTop(floorf(fe->ftop() + 0.5f)); - } -}; - -class f2i_ForthWord : public ForthWord { -public: - virtual void exec(ForthEngine* fe) { - fe->setTop((int)fe->ftop()); - } -}; - -class i2f_ForthWord : public ForthWord { -public: - virtual void exec(ForthEngine* fe) { - fe->fsetTop((float)fe->top()); - } -}; - -/////////////////////////////////////////////////////////////////////////////// - /* reading an initial 32bit value from the code stream: @@ -317,22 +108,40 @@ public: 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, + 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() { return false; } - bool appendTHEN() { return false; } + void appendIF(); + bool appendELSE(); + bool appendTHEN(); void done(); intptr_t* detach() { @@ -348,13 +157,14 @@ public: 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 | kDataShift2_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; @@ -367,6 +177,43 @@ void FCode::appendWord(ForthWord* word) { *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; } @@ -385,10 +232,20 @@ void FCode::Exec(const intptr_t* curr, ForthEngine* engine) { engine->push(c >> 2); break; case kCodeShift2_Bits: - switch ((uint32_t)c >> 2) { + 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; } @@ -415,61 +272,12 @@ private: /////////////////////////////////////////////////////////////////////////////// -class ForthParser { -public: - ForthParser() : fDict(4096) { - this->addStdWords(); - } - - const char* parse(const char text[], FCode*); - - void addWord(const char name[], ForthWord* word) { - this->add(name, strlen(name), word); - } - - ForthWord* find(const char name[], size_t len) const { - ForthWord* word; - return fDict.find(name, len, &word) ? word : NULL; - } - -private: - void add(const char name[], size_t len, ForthWord* word) { - (void)fDict.set(name, len, word); - } +ForthParser::ForthParser() : fDict(4096) { + this->addStdWords(); +} - void addStdWords() { - this->add("clr", 3, new clearStack_ForthWord); - this->add("drop", 4, new drop_ForthWord); - this->add("dup", 3, new dup_ForthWord); - this->add("swap", 4, new swap_ForthWord); - - this->add("+", 1, new add_ForthWord); - this->add("-", 1, new sub_ForthWord); - this->add("*", 1, new mul_ForthWord); - this->add("/", 1, new div_ForthWord); - this->add(".", 1, new dot_ForthWord); - this->add("abs", 3, new abs_ForthWord); - this->add("min", 3, new min_ForthWord); - this->add("max", 3, new max_ForthWord); - - this->add("f+", 2, new fadd_ForthWord); - this->add("f-", 2, new fsub_ForthWord); - this->add("f*", 2, new fmul_ForthWord); - this->add("f/", 2, new fdiv_ForthWord); - this->add("f.", 2, new fdot_ForthWord); - this->add("fabs", 4, new fabs_ForthWord); - this->add("fmin", 4, new fmin_ForthWord); - this->add("fmax", 4, new fmax_ForthWord); - this->add("fmax", 4, new fmax_ForthWord); - this->add("floor", 5, new floor_ForthWord); - this->add("ceil", 4, new ceil_ForthWord); - this->add("round", 5, new round_ForthWord); - this->add("f>i", 3, new f2i_ForthWord); - this->add("i>f", 3, new i2f_ForthWord); - } - - SkTDict<ForthWord*> fDict; -}; +ForthParser::~ForthParser() { +} static const char* parse_error(const char msg[]) { SkDebugf("-- parser error: %s\n", msg); @@ -615,11 +423,11 @@ const char* ForthParser::parse(const char text[], FCode* code) { code->appendInt(num); } else if (2 == len && memcmp(token, "IF", 2) == 0) { code->appendIF(); - } else if (2 == len && memcmp(token, "ELSE", 4) == 0) { + } else if (4 == len && memcmp(token, "ELSE", 4) == 0) { if (!code->appendELSE()) { return parse_error("ELSE with no matching IF"); } - } else if (2 == len && memcmp(token, "THEN", 4) == 0) { + } else if (4 == len && memcmp(token, "THEN", 4) == 0) { if (!code->appendTHEN()) { return parse_error("THEN with no matching IF"); } diff --git a/forth/SampleForth.cpp b/forth/SampleForth.cpp index d207cb891c..3de2fad2c1 100644 --- a/forth/SampleForth.cpp +++ b/forth/SampleForth.cpp @@ -165,7 +165,8 @@ public: fBM.eraseColor(0); fContext.init(fBM); - fEnv.parse(": view.onClick ( x y -- ) 10. drawCircle ;"); + fEnv.parse(": mycolor ( x. y. -- x. y. ) rot rot f< IF #FFFF0000 ELSE #FF0000FF THEN setColor ;"); + fEnv.parse(": view.onClick ( x. y. -- ) mycolor 10. drawCircle ;"); fOnClickWord = fEnv.findWord("view.onClick"); #if 0 env.parse( @@ -181,6 +182,9 @@ public: "draw1 " ); #endif + ForthEnv env; + env.parse("3 5 = IF 42 . ELSE -42 . THEN 99 ."); + env.run(); } protected: diff --git a/include/core/SkTDStack.h b/include/core/SkTDStack.h index 5bc10ee9cb..321c138357 100644 --- a/include/core/SkTDStack.h +++ b/include/core/SkTDStack.h @@ -40,6 +40,8 @@ public: } int count() const { return fTotalCount; } + int depth() const { return fTotalCount; } + bool empty() const { return fTotalCount == 0; } T* push() { diff --git a/xcode/sampleapp/SampleApp.xcodeproj/project.pbxproj b/xcode/sampleapp/SampleApp.xcodeproj/project.pbxproj index f3cf4e78df..ad9053dedd 100644 --- a/xcode/sampleapp/SampleApp.xcodeproj/project.pbxproj +++ b/xcode/sampleapp/SampleApp.xcodeproj/project.pbxproj @@ -74,6 +74,7 @@ 00AF9B18103CD5EB00CBBCB3 /* SampleDitherBitmap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00AF9B17103CD5EB00CBBCB3 /* SampleDitherBitmap.cpp */; }; 00BB289B104781D00057BF7E /* SampleForth.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00BB289A104781D00057BF7E /* SampleForth.cpp */; }; 00C1B809103857A400FA5948 /* SampleFillType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0041CE270F00A12400695E8C /* SampleFillType.cpp */; }; + 00ED55F3104A10EB00F51FF8 /* StdWords.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00ED55F2104A10EB00F51FF8 /* StdWords.cpp */; }; 00F53F480FFCFC4D003FA70A /* SampleGradients.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00C55DA00F8552DC000CAC09 /* SampleGradients.cpp */; }; 00FF39140FC6ED2C00915187 /* SampleEffects.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00FF39130FC6ED2C00915187 /* SampleEffects.cpp */; }; 0156F80407C56A3000C6122B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0156F80307C56A3000C6122B /* Foundation.framework */; }; @@ -203,9 +204,9 @@ 00A729630FD93ED600D5051F /* SampleTestGL.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleTestGL.cpp; path = ../../samplecode/SampleTestGL.cpp; sourceTree = SOURCE_ROOT; }; 00AF9B17103CD5EB00CBBCB3 /* SampleDitherBitmap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleDitherBitmap.cpp; path = ../../samplecode/SampleDitherBitmap.cpp; sourceTree = SOURCE_ROOT; }; 00BB289A104781D00057BF7E /* SampleForth.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleForth.cpp; path = ../../forth/SampleForth.cpp; sourceTree = SOURCE_ROOT; }; - 00BB289D1047826E0057BF7E /* Forth.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Forth.h; path = ../../forth/Forth.h; sourceTree = SOURCE_ROOT; }; 00C55DA00F8552DC000CAC09 /* SampleGradients.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleGradients.cpp; path = ../../samplecode/SampleGradients.cpp; sourceTree = SOURCE_ROOT; }; 00D6B5CB0F72DC4300C466B9 /* SampleFuzz.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleFuzz.cpp; path = ../../samplecode/SampleFuzz.cpp; sourceTree = SOURCE_ROOT; }; + 00ED55F2104A10EB00F51FF8 /* StdWords.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StdWords.cpp; path = ../../forth/StdWords.cpp; sourceTree = SOURCE_ROOT; }; 00FF39130FC6ED2C00915187 /* SampleEffects.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleEffects.cpp; path = ../../samplecode/SampleEffects.cpp; sourceTree = SOURCE_ROOT; }; 0156F80307C56A3000C6122B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; }; 01FC44D407BD3BB800D228F4 /* Quartz.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Quartz.framework; path = /System/Library/Frameworks/Quartz.framework; sourceTree = "<absolute>"; }; @@ -285,8 +286,6 @@ 0041CE260F00A12400695E8C /* SampleEncode.cpp */, 0041CE270F00A12400695E8C /* SampleFillType.cpp */, 00AF9B17103CD5EB00CBBCB3 /* SampleDitherBitmap.cpp */, - 00BB289D1047826E0057BF7E /* Forth.h */, - 00BB289A104781D00057BF7E /* SampleForth.cpp */, 0041CE280F00A12400695E8C /* SampleFilter.cpp */, 0041CE290F00A12400695E8C /* SampleFilter2.cpp */, 0041CE2A0F00A12400695E8C /* SampleFontCache.cpp */, @@ -363,6 +362,8 @@ isa = PBXGroup; children = ( 001B871D1042184D00C84ED4 /* Forth.cpp */, + 00ED55F2104A10EB00F51FF8 /* StdWords.cpp */, + 00BB289A104781D00057BF7E /* SampleForth.cpp */, 2762F66A0FCCCAA2002BD8B4 /* images */, 00003C6A0EFC22AD000FF73A /* views */, 00003C610EFC2287000FF73A /* samples */, @@ -589,6 +590,7 @@ 00AF9B18103CD5EB00CBBCB3 /* SampleDitherBitmap.cpp in Sources */, 001B871E1042184D00C84ED4 /* Forth.cpp in Sources */, 00BB289B104781D00057BF7E /* SampleForth.cpp in Sources */, + 00ED55F3104A10EB00F51FF8 /* StdWords.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; |