
struct Parser
{
    enum TokenType { TOK_EOF = 0x100, TOK_IDENT, TOK_INT };

    wxString buf;
    Node *errornode;
    int token;
    int pos;
    wxString attr;

    Parser(wxString _b) : buf(_b), pos(0) { buf += '\0'; }

    Node *Error(wxString err)
    {
        errornode = new Node(T_UNPARSED);
        errornode->up = new Unparsed();
        errornode->up->name = buf;
        errornode->up->error = err;
        errornode->up->errorpos = pos;
        throw 0;    // FIXME: dealloc temp nodes, put in pool?
        return NULL;
    }

    void Next()
    {
        for(;;) switch(token = buf[pos++])
        {
            case 0: pos--; token = TOK_EOF; return;
            case ' ': case '\n': case '\t': continue;
            case '(': case ')': case ',': return;
            default:
            {
                attr = (wxChar)token;
                if(wxIsalpha(token) || token=='_')
                {
                    while(wxIsalnum(buf[pos]) || buf[pos]=='_') attr += buf[pos++];
                    token = TOK_IDENT;
                }
                else if(wxIsdigit(token))
                {
                    while(wxIsdigit(buf[pos])) attr += buf[pos++];
                    token = TOK_INT;
                }
                else
                {
                    Error(L"unknown character: "+attr);
                }
                return;
            }
        }
    }

    wxString Token2Str(int t)
    {
        switch(t)
        {
            case TOK_EOF:   return L"end of code";
            case TOK_IDENT: return L"identifier";
            case TOK_INT:   return L"integer";
            default:        return wxString()+(wxChar)t;
        }
    }

    void Expect(int t) { if(token!=t) Error(Token2Str(t)+L" expected"); Next(); }

    Node *Parse()
    {
        try
        {
            Next();
            Node *exp = ParseExp();
            Expect(TOK_EOF);
            return exp;
        }
        catch(int)
        {
            return errornode;
        }
    }

    Node *ParseExp()
    {
        Node *r;
        switch(token)
        {
            case TOK_INT:
            {
                r = new Node(T_INT);
                long conv;
                attr.ToLong(&conv);
                r->val = conv;
                Next();
                return r;
            }

            case TOK_IDENT:
            {
                wxString name = attr;
                Next();
                if(token=='(')
                {
                    Next();
                    BuiltinFunction *bf = NULL;
                    loopv(i, sys->builtins) if(sys->builtins[i].name==name)
                    {
                        bf = &sys->builtins[i];
                        break;
                    }
                    r = new Node(bf ? T_BUILTINCALL : T_FUNCTIONCALL);
                    r->bf = bf;
                    Node **tail = &r->children;
                    if(token!=')') for(;;)
                    {
                        *tail = ParseExp();
                        (*tail)->parent = r;
                        tail = &(*tail)->sibling;
                        if(token==')') break;
                        Expect(',');
                    }
                    Next();
                    return r;
                }
                else
                {
                    return Error(L"ident unimpl");
                }
            }

            default:
                return Error(L"expression expected");
        }
    }
};

