1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/*
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2011 Google Inc.
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com *
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com */
8f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com#include "Forth.h"
919a89f287f3af6fd34470a7aab92a989109d513freed@android.com#include "ForthParser.h"
10f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com#include "SkTDArray.h"
11f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com#include "SkString.h"
1219a89f287f3af6fd34470a7aab92a989109d513freed@android.com#include "SkTDStack.h"
13f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com
14f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.comForthEngine::ForthEngine(ForthOutput* output) : fOutput(output) {
15f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    size_t size = 32 * sizeof(intptr_t);
16f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    fStackBase = reinterpret_cast<intptr_t*>(sk_malloc_throw(size));
17f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    fStackStop = fStackBase + size/sizeof(intptr_t);
18f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    fStackCurr = fStackStop;
19f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com}
20f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com
21f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.comForthEngine::~ForthEngine() {
22f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    sk_free(fStackBase);
23f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com}
24f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com
25f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.comvoid ForthEngine::sendOutput(const char text[]) {
26f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    if (fOutput) {
27f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        fOutput->show(text);
28f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    } else {
29f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        SkDebugf("%s", text);
30f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    }
31f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com}
32f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com
33f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.comvoid ForthEngine::push(intptr_t value) {
34f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    if (fStackCurr > fStackBase) {
35f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        SkASSERT(fStackCurr <= fStackStop && fStackCurr > fStackBase);
36f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        *--fStackCurr = value;
37f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    } else {
38f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        this->signal_error("overflow");
39f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    }
40f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com}
41f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com
42f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.comintptr_t ForthEngine::peek(size_t index) const {
43f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    SkASSERT(fStackCurr < fStackStop && fStackCurr >= fStackBase);
44f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    if (fStackCurr + index < fStackStop) {
45f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        return fStackCurr[index];
46f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    } else {
47f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        this->signal_error("peek out of range");
48f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        return 0x80000001;
49f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    }
50f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com}
51f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com
52f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.comvoid ForthEngine::setTop(intptr_t value) {
53f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    if (fStackCurr < fStackStop) {
54f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        SkASSERT(fStackCurr < fStackStop && fStackCurr >= fStackBase);
55f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        *fStackCurr = value;
56f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    } else {
57f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        this->signal_error("underflow");
58f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    }
59f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com}
60f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com
61f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.comintptr_t ForthEngine::pop() {
62f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    if (fStackCurr < fStackStop) {
63f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        SkASSERT(fStackCurr < fStackStop && fStackCurr >= fStackBase);
64f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        return *fStackCurr++;
65f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    } else {
66f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        this->signal_error("underflow");
67f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        return 0x80000001;
68f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    }
69f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com}
70f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com
71f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com///////////////////////////////////////////////////////////////////////////////
72f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com
73f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.comvoid ForthWord::call(ForthCallBlock* block) {
74f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    ForthEngine engine(NULL);
7519a89f287f3af6fd34470a7aab92a989109d513freed@android.com
7619a89f287f3af6fd34470a7aab92a989109d513freed@android.com    // setup the initial stack with the callers input data
77f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    if (block) {
78f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        // walk the array backwards, so that the top of the stack is data[0]
79f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        for (size_t i = 0; i < block->in_count; i++) {
80f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com            engine.push(block->in_data[i]);
81f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        }
82f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    }
8319a89f287f3af6fd34470a7aab92a989109d513freed@android.com
8419a89f287f3af6fd34470a7aab92a989109d513freed@android.com    // now invoke the word
85f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    this->exec(&engine);
8619a89f287f3af6fd34470a7aab92a989109d513freed@android.com
8719a89f287f3af6fd34470a7aab92a989109d513freed@android.com    // now copy back the stack into the caller's output data
88f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    if (block) {
89f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        size_t n = engine.depth();
90f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        block->out_depth = n;
91f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        if (n > block->out_count) {
92f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com            n = block->out_count;
93f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        }
94f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        for (size_t i = 0; i < n; i++) {
95f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com            block->out_data[i] = engine.peek(i);
96f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        }
97f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    }
98f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com}
99f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com
100f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com///////////////////////////////////////////////////////////////////////////////
101f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com
102f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com/*
103f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    reading an initial 32bit value from the code stream:
104fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
105f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx00
106fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
107f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    Those last two bits are always 0 for a word, so we set those bits for other
108f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    opcodes
109fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
110f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    00 -- execute this word
111f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    01 -- push (value & ~3) on the data stack
112f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    10 -- push value >> 2 on the data stack (sign extended)
113f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    11 -- switch (value >>> 2) for Code
114f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com */
115f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com
116f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.comclass FCode {
117f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.compublic:
11819a89f287f3af6fd34470a7aab92a989109d513freed@android.com    enum {
11919a89f287f3af6fd34470a7aab92a989109d513freed@android.com        kCodeShift  = 2,
12019a89f287f3af6fd34470a7aab92a989109d513freed@android.com        kCodeMask   = 7,
12119a89f287f3af6fd34470a7aab92a989109d513freed@android.com        kCodeDataShift  = 5
12219a89f287f3af6fd34470a7aab92a989109d513freed@android.com    };
12319a89f287f3af6fd34470a7aab92a989109d513freed@android.com    static unsigned GetCode(intptr_t c) {
12419a89f287f3af6fd34470a7aab92a989109d513freed@android.com        return ((uint32_t)c >> kCodeShift) & kCodeMask;
12519a89f287f3af6fd34470a7aab92a989109d513freed@android.com    }
12619a89f287f3af6fd34470a7aab92a989109d513freed@android.com    static unsigned GetCodeData(intptr_t c) {
12719a89f287f3af6fd34470a7aab92a989109d513freed@android.com        return (uint32_t)c >> kCodeDataShift;
12819a89f287f3af6fd34470a7aab92a989109d513freed@android.com    }
12919a89f287f3af6fd34470a7aab92a989109d513freed@android.com
130f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    enum Bits {
131f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        kWord_Bits          = 0,    // must be zero for function address
132f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        kDataClear2_Bits    = 1,
133f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        kDataShift2_Bits    = 2,
134f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        kCodeShift2_Bits    = 3
135f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    };
13619a89f287f3af6fd34470a7aab92a989109d513freed@android.com
137f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    enum Code {
13819a89f287f3af6fd34470a7aab92a989109d513freed@android.com        kPushInt_Code,  // for data that needs more than 30 bits
13919a89f287f3af6fd34470a7aab92a989109d513freed@android.com        kIF_Code,
14019a89f287f3af6fd34470a7aab92a989109d513freed@android.com        kELSE_Code,
141f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        kDone_Code
142f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    };
14319a89f287f3af6fd34470a7aab92a989109d513freed@android.com    static unsigned MakeCode(Code code) {
14419a89f287f3af6fd34470a7aab92a989109d513freed@android.com        return (code << kCodeShift) | kCodeShift2_Bits;
14519a89f287f3af6fd34470a7aab92a989109d513freed@android.com    }
146fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
147f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    void appendInt(int32_t);
148f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    void appendWord(ForthWord*);
14919a89f287f3af6fd34470a7aab92a989109d513freed@android.com    void appendIF();
15019a89f287f3af6fd34470a7aab92a989109d513freed@android.com    bool appendELSE();
15119a89f287f3af6fd34470a7aab92a989109d513freed@android.com    bool appendTHEN();
152f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    void done();
153f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com
154f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    intptr_t* detach() {
155f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        this->done();
156f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        return fData.detach();
157f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    }
158f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    intptr_t* begin() {
159f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        this->done();
160f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        return fData.begin();
161f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    }
162fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
163f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    static void Exec(const intptr_t*, ForthEngine*);
164f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com
165f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.comprivate:
166f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    SkTDArray<intptr_t> fData;
16719a89f287f3af6fd34470a7aab92a989109d513freed@android.com    SkTDStack<size_t>   fIfStack;
168f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com};
169f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com
170f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.comvoid FCode::appendInt(int32_t value) {
171f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    if ((value & 3) == 0) {
172f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        *fData.append() = value | kDataClear2_Bits;
17319a89f287f3af6fd34470a7aab92a989109d513freed@android.com    } else if ((value << 2 >> 2) == value) {
17419a89f287f3af6fd34470a7aab92a989109d513freed@android.com        *fData.append() = (value << 2) | kDataShift2_Bits;
175f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    } else {
176f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        intptr_t* p = fData.append(2);
177f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        *p++ = (kPushInt_Code << 2) | kCodeShift2_Bits;
178f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        *p++ = value;
179f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    }
180f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com}
181f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com
182f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.comvoid FCode::appendWord(ForthWord* word) {
183f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    SkASSERT((reinterpret_cast<intptr_t>(word) & 3) == 0);
184f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    *fData.append() = reinterpret_cast<intptr_t>(word);
185f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com}
186f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com
18719a89f287f3af6fd34470a7aab92a989109d513freed@android.comvoid FCode::appendIF() {
18819a89f287f3af6fd34470a7aab92a989109d513freed@android.com    size_t ifIndex = fData.count();
18919a89f287f3af6fd34470a7aab92a989109d513freed@android.com    fIfStack.push(ifIndex);
19019a89f287f3af6fd34470a7aab92a989109d513freed@android.com    *fData.append() = MakeCode(kIF_Code);
19119a89f287f3af6fd34470a7aab92a989109d513freed@android.com}
19219a89f287f3af6fd34470a7aab92a989109d513freed@android.com
19319a89f287f3af6fd34470a7aab92a989109d513freed@android.combool FCode::appendELSE() {
19419a89f287f3af6fd34470a7aab92a989109d513freed@android.com    if (fIfStack.empty()) {
19519a89f287f3af6fd34470a7aab92a989109d513freed@android.com        return false;
19619a89f287f3af6fd34470a7aab92a989109d513freed@android.com    }
19719a89f287f3af6fd34470a7aab92a989109d513freed@android.com
19819a89f287f3af6fd34470a7aab92a989109d513freed@android.com    size_t elseIndex = fData.count();
19919a89f287f3af6fd34470a7aab92a989109d513freed@android.com    *fData.append() = MakeCode(kELSE_Code);
20019a89f287f3af6fd34470a7aab92a989109d513freed@android.com
20119a89f287f3af6fd34470a7aab92a989109d513freed@android.com    size_t ifIndex = fIfStack.top();
20219a89f287f3af6fd34470a7aab92a989109d513freed@android.com    // record the offset in the data part of the if-code
20319a89f287f3af6fd34470a7aab92a989109d513freed@android.com    fData[ifIndex] |= (elseIndex - ifIndex) << kCodeDataShift;
20419a89f287f3af6fd34470a7aab92a989109d513freed@android.com
20519a89f287f3af6fd34470a7aab92a989109d513freed@android.com    // now reuse this IfStack entry to track the else
20619a89f287f3af6fd34470a7aab92a989109d513freed@android.com    fIfStack.top() = elseIndex;
20719a89f287f3af6fd34470a7aab92a989109d513freed@android.com    return true;
20819a89f287f3af6fd34470a7aab92a989109d513freed@android.com}
20919a89f287f3af6fd34470a7aab92a989109d513freed@android.com
21019a89f287f3af6fd34470a7aab92a989109d513freed@android.combool FCode::appendTHEN() {
21119a89f287f3af6fd34470a7aab92a989109d513freed@android.com    if (fIfStack.empty()) {
21219a89f287f3af6fd34470a7aab92a989109d513freed@android.com        return false;
21319a89f287f3af6fd34470a7aab92a989109d513freed@android.com    }
21419a89f287f3af6fd34470a7aab92a989109d513freed@android.com
21519a89f287f3af6fd34470a7aab92a989109d513freed@android.com    // this is either an IF or an ELSE
21619a89f287f3af6fd34470a7aab92a989109d513freed@android.com    size_t index = fIfStack.top();
21719a89f287f3af6fd34470a7aab92a989109d513freed@android.com    // record the offset in the data part of the code
21819a89f287f3af6fd34470a7aab92a989109d513freed@android.com    fData[index] |= (fData.count() - index - 1) << kCodeDataShift;
21919a89f287f3af6fd34470a7aab92a989109d513freed@android.com
22019a89f287f3af6fd34470a7aab92a989109d513freed@android.com    fIfStack.pop();
22119a89f287f3af6fd34470a7aab92a989109d513freed@android.com    return true;
22219a89f287f3af6fd34470a7aab92a989109d513freed@android.com}
22319a89f287f3af6fd34470a7aab92a989109d513freed@android.com
224f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.comvoid FCode::done() {
225f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    *fData.append() = (kDone_Code << 2) | kCodeShift2_Bits;
226f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com}
227f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com
228f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.comvoid FCode::Exec(const intptr_t* curr, ForthEngine* engine) {
229f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    for (;;) {
230f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        intptr_t c = *curr++;
231f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        switch (c & 3) {
232f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com            case kWord_Bits:
233f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com                reinterpret_cast<ForthWord*>(c)->exec(engine);
234f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com                break;
235f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com            case kDataClear2_Bits:
236f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com                engine->push(c & ~3);
237f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com                break;
238f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com            case kDataShift2_Bits:
239f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com                engine->push(c >> 2);
240f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com                break;
241f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com            case kCodeShift2_Bits:
24219a89f287f3af6fd34470a7aab92a989109d513freed@android.com                switch (GetCode(c)) {
243f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com                    case kPushInt_Code:
244f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com                        engine->push(*curr++);
245f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com                        break;
24619a89f287f3af6fd34470a7aab92a989109d513freed@android.com                    case kIF_Code:
24719a89f287f3af6fd34470a7aab92a989109d513freed@android.com                        if (!engine->pop()) {
24819a89f287f3af6fd34470a7aab92a989109d513freed@android.com                            // takes us past the ELSE or THEN
24919a89f287f3af6fd34470a7aab92a989109d513freed@android.com                            curr += GetCodeData(c);
25019a89f287f3af6fd34470a7aab92a989109d513freed@android.com                        }
25119a89f287f3af6fd34470a7aab92a989109d513freed@android.com                        break;
25219a89f287f3af6fd34470a7aab92a989109d513freed@android.com                    case kELSE_Code:
25319a89f287f3af6fd34470a7aab92a989109d513freed@android.com                        // takes us past the THEN
25419a89f287f3af6fd34470a7aab92a989109d513freed@android.com                        curr += GetCodeData(c);
25519a89f287f3af6fd34470a7aab92a989109d513freed@android.com                        break;
256f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com                    case kDone_Code:
257f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com                        return;
258f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com                }
259f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com                break;
260f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        }
261f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    }
262f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com}
263f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com
264f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com///////////////////////////////////////////////////////////////////////////////
265f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com
266f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.comclass CustomWord : public ForthWord {
267f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.compublic:
268f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    // we assume ownership of code[]
269f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    CustomWord(intptr_t code[]) : fCode(code) {}
270f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    virtual ~CustomWord() { sk_free(fCode); }
271f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com
272f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    virtual void exec(ForthEngine* engine) {
273f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        FCode::Exec(fCode, engine);
274f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    }
275f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com
276f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.comprivate:
277f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    intptr_t* fCode;
278f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com};
279f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com
280f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com///////////////////////////////////////////////////////////////////////////////
281f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com
28219a89f287f3af6fd34470a7aab92a989109d513freed@android.comForthParser::ForthParser() : fDict(4096) {
28319a89f287f3af6fd34470a7aab92a989109d513freed@android.com    this->addStdWords();
28419a89f287f3af6fd34470a7aab92a989109d513freed@android.com}
285f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com
28619a89f287f3af6fd34470a7aab92a989109d513freed@android.comForthParser::~ForthParser() {
2871d5aaa8ef65f312508e41ec458d4a6457f9cd39ereed@google.com    SkTDict<ForthWord*>::Iter iter(fDict);
2881d5aaa8ef65f312508e41ec458d4a6457f9cd39ereed@google.com    ForthWord* word;
2891d5aaa8ef65f312508e41ec458d4a6457f9cd39ereed@google.com    while (iter.next(&word)) {
2901d5aaa8ef65f312508e41ec458d4a6457f9cd39ereed@google.com        delete word;
2911d5aaa8ef65f312508e41ec458d4a6457f9cd39ereed@google.com    }
29219a89f287f3af6fd34470a7aab92a989109d513freed@android.com}
293f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com
294f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.comstatic const char* parse_error(const char msg[]) {
295f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    SkDebugf("-- parser error: %s\n", msg);
296f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    return NULL;
297f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com}
298f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com
299f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com/** returns true if c is whitespace, including null
300f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com */
301f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.comstatic bool is_ws(int c) {
302f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    return c <= ' ';
303f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com}
304f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com
305f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.comstatic const char* parse_token(const char** text, size_t* len) {
306f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    const char* s = *text;
307f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    while (is_ws(*s)) {
308f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        if (0 == *s) {
309f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com            return NULL;
310f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        }
311f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        s++;
312f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    }
313f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    const char* token = s++;
314f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    while (!is_ws(*s)) {
315f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        s++;
316f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    }
317f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    *text = s;
318f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    *len = s - token;
319f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    return token;
320f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com}
321f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com
322f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.comstatic bool is_digit(int c) { return (unsigned)(c - '0') <= 9; }
323f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.comstatic int hex_val(int c) {
324f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    if (is_digit(c)) {
325f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        return c - '0';
326f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    } else {
327f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        if (c <= 'Z') {
328f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com            return 10 + c - 'A';
329f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        } else {
330f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com            return 10 + c - 'a';
331f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        }
332f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    }
333f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com}
334f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com
335f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.comstatic bool parse_num(const char str[], size_t len, int32_t* numBits) {
336f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    if (1 == len && !is_digit(*str)) {
337f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        return false;
338f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    }
339f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    const char* start = str;
340f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    int32_t num = 0;
341f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    bool neg = false;
342f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    if (*str == '-') {
343f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        neg = true;
344f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        str += 1;
345f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    } else if (*str == '#') {
346f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        str++;
347f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        while (str - start < len) {
348f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com            num = num*16 + hex_val(*str);
349f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com            str += 1;
350f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        }
351f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        *numBits = num;
352f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        return true;
353f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    }
354f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com
355f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    while (is_digit(*str)) {
356f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        num = 10*num + *str - '0';
357f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        str += 1;
358f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    }
359f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    SkASSERT(str - start <= len);
360f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    if (str - start == len) {
361f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        if (neg) {
362f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com            num = -num;
363f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        }
364f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        *numBits = num;
365f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        return true;
366f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    }
367f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    // if we're not done with the token then the next char must be a decimal
368f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    if (*str != '.') {
369f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        return false;
370f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    }
371f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    str += 1;
372f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    float x = num;
373f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    float denom = 1;
374f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    while (str - start < len && is_digit(*str)) {
375f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        x = 10*x + *str - '0';
376f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        denom *= 10;
377f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        str += 1;
378f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    }
379f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    x /= denom;
380f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    if (str - start == len) {
381f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        if (neg) {
382f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com            x = -x;
383f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        }
384f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        *numBits = f2i_bits(x);
385f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        return true;
386f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    }
387f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    return false;
388f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com}
389f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com
390f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.comstatic const char* parse_comment(const char text[]) {
391f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    SkASSERT(*text == '(');
392f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    while (')' != *++text) {
393f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        if (0 == *text) {
394f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com            return NULL;
395f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        }
396f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    }
397f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    return text + 1;    // skip past the closing ')'
398f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com}
399f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com
400f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.comconst char* ForthParser::parse(const char text[], FCode* code) {
401f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    for (;;) {
402f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        size_t len;
403f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        const char* token = parse_token(&text, &len);
404f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        if (NULL == token) {
405f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com            break;
406f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        }
407f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        if (1 == len) {
408f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com            if ('(' == *token) {
409f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com                text = parse_comment(token);
410f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com                if (NULL == text) {
411f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com                    return NULL;
412f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com                }
413f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com                continue;
414f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com            }
415f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com            if (';' == *token) {
416f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com                break;
417f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com            }
418f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com            if (':' == *token) {
419f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com                token = parse_token(&text, &len);
420f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com                if (NULL == token) {
421f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com                    return parse_error("missing name after ':'");
422f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com                }
423f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com                FCode subCode;
424f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com                text = this->parse(text, &subCode);
425f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com                if (NULL == text) {
426f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com                    return NULL;
427f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com                }
428f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com                this->add(token, len, new CustomWord(subCode.detach()));
429f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com                continue;
430f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com            }
431f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        }
432f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        int32_t num;
433f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        if (parse_num(token, len, &num)) {
434f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com            // note that num is just the bit representation of the float
435f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com            code->appendInt(num);
436f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        } else if (2 == len && memcmp(token, "IF", 2) == 0) {
437f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com            code->appendIF();
43819a89f287f3af6fd34470a7aab92a989109d513freed@android.com        } else if (4 == len && memcmp(token, "ELSE", 4) == 0) {
439f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com            if (!code->appendELSE()) {
440f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com                return parse_error("ELSE with no matching IF");
441f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com            }
44219a89f287f3af6fd34470a7aab92a989109d513freed@android.com        } else if (4 == len && memcmp(token, "THEN", 4) == 0) {
443f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com            if (!code->appendTHEN()) {
444f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com                return parse_error("THEN with no matching IF");
445f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com            }
446f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        } else{
447f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com            ForthWord* word = this->find(token, len);
448f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com            if (NULL == word) {
449f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com                SkString str(token, len);
450f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com                str.prepend("unknown word ");
451f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com                return parse_error(str.c_str());
452f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com            }
453f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com            code->appendWord(word);
454f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        }
455f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    }
456f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    return text;
457f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com}
458f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com
459f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com///////////////////////////////////////////////////////////////////////////////
460f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com
461f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.comclass ForthEnv::Impl {
462f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.compublic:
463f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    ForthParser fParser;
464f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    FCode       fBuilder;
465f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com};
466f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com
467f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.comForthEnv::ForthEnv() {
468f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    fImpl = new Impl;
469f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com}
470f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com
471f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.comForthEnv::~ForthEnv() {
472f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    delete fImpl;
473f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com}
474f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com
475f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.comvoid ForthEnv::addWord(const char name[], ForthWord* word) {
476f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    fImpl->fParser.addWord(name, word);
477f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com}
478f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com
479f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.comvoid ForthEnv::parse(const char text[]) {
480f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    fImpl->fParser.parse(text, &fImpl->fBuilder);
481f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com}
482f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com
483f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.comForthWord* ForthEnv::findWord(const char name[]) {
484f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    return fImpl->fParser.find(name, strlen(name));
485f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com}
486f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com
487f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.comvoid ForthEnv::run(ForthOutput* output) {
488f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    ForthEngine engine(output);
489f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    FCode::Exec(fImpl->fBuilder.begin(), &engine);
490f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com}
491f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com
492f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com#if 0
493f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.comvoid ForthEnv::run(const char text[], ForthOutput* output) {
494f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    FCode builder;
495f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com
496f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    if (fImpl->fParser.parse(text, &builder)) {
497f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        ForthEngine engine(output);
498f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com        FCode::Exec(builder.begin(), &engine);
499f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com    }
500f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com}
501f56e295e88f4ed42f4c94c54d5fc544ed0f45f18reed@android.com#endif
502