From a9b946cf21d5342cdd16f2ec4053703a84732e58 Mon Sep 17 00:00:00 2001 From: Adrian Thurston Date: Tue, 27 Apr 2010 02:26:37 +0000 Subject: Finished off the porting to C. Implemented state table compressions by overlaying arrays and using an 'owner' array to determine which entry belongs to which state. --- colm/Makefile.in | 30 +- colm/bytecode.c | 4175 +++++++++++++++++++++++++++++++++++++++++++++++++++ colm/bytecode.cpp | 4166 -------------------------------------------------- colm/bytecode.h | 27 - colm/bytecode2.h | 2 + colm/ctinput.cpp | 4 + colm/debug.c | 8 + colm/debug.h | 2 + colm/fsmrun.c | 8 +- colm/fsmrun.h | 3 - colm/main.cpp | 4 +- colm/parsedata.cpp | 6 + colm/parsedata.h | 1 + colm/pdabuild.cpp | 129 +- colm/pdacodegen.cpp | 13 + colm/pdacodegen.h | 1 + colm/pdarun.c | 12 +- colm/pdarun.h | 3 +- colm/tree.c | 2033 +++++++++++++++++++++++++ colm/tree.h | 2 - colm/tree2.c | 2033 ------------------------- 21 files changed, 6371 insertions(+), 6291 deletions(-) create mode 100644 colm/bytecode.c delete mode 100644 colm/bytecode.cpp create mode 100644 colm/tree.c delete mode 100644 colm/tree2.c diff --git a/colm/Makefile.in b/colm/Makefile.in index 58b6fa6d..042f6e30 100644 --- a/colm/Makefile.in +++ b/colm/Makefile.in @@ -61,11 +61,10 @@ COLM_SRC = \ pcheck.cpp \ ctinput.cpp -RUNTIME_SRC = bytecode.cpp -RUNTIME_SRC_C = map.c fsmrun.c pdarun.c list.c input.c debug.c codevect.c pool.c string.c tree2.c - - -ALL_SRC = $(COLM_SRC) $(RUNTIME_SRC) +RUNTIME_SRC = \ + map.c fsmrun.c pdarun.c \ + list.c input.c debug.c \ + codevect.c pool.c string.c tree.c bytecode.c # Files in ALL_SRC that are generated. GEN_SRC = version.h lmscan.cpp lmparse.h lmparse.cpp @@ -90,13 +89,10 @@ CC = @CC@ # Get objects and dependencies from sources. COLM_OBJ = $(COLM_SRC:%.cpp=%.o) -RUNTIME_OBJ_P = $(RUNTIME_SRC:%.cpp=%_p.o) -RUNTIME_OBJ_D = $(RUNTIME_SRC:%.cpp=%_d.o) - -RUNTIME_OBJ_C_P = $(RUNTIME_SRC_C:%.c=%_p.o) -RUNTIME_OBJ_C_D = $(RUNTIME_SRC_C:%.c=%_d.o) +RUNTIME_OBJ_P = $(RUNTIME_SRC:%.c=%_p.o) +RUNTIME_OBJ_D = $(RUNTIME_SRC:%.c=%_d.o) -DEPS = $(COLM_SRC:%.cpp=.%.d) $(RUNTIME_SRC:%.cpp=.%_p.d) $(RUNTIME_SRC:%.cpp=.%_d.d) +DEPS = $(COLM_SRC:%.cpp=.%.d) $(RUNTIME_SRC:%.c=.%_p.d) $(RUNTIME_SRC:%.c=.%_d.d) # Rules. all: colm $(RUNTIME_P) $(RUNTIME_D) @@ -133,19 +129,11 @@ $(COLM_OBJ): %.o: %.cpp @$(CXX) -M $(DEFS_COLM) $(INCS) $< > .$*.d $(CXX) -c $(CFLAGS) $(DEFS_COLM) $(INCS) -o $@ $< -$(RUNTIME_OBJ_P): %_p.o: %.cpp - @$(CXX) -M -MT $@ $(DEFS_RT_P) $< > .$*_p.d - $(CXX) -c $(CFLAGS) $(DEFS_RT_P) -o $@ $< - -$(RUNTIME_OBJ_D): %_d.o: %.cpp - @$(CXX) -M -MT $@ $(DEFS_RT_D) $< > .$*_d.d - $(CXX) -c $(CFLAGS) $(DEFS_RT_D) -o $@ $< - -$(RUNTIME_OBJ_C_P): %_p.o: %.c +$(RUNTIME_OBJ_P): %_p.o: %.c @$(CC) -M -MT $@ $(DEFS_RT_P) $< > .$*_p.d $(CC) -c $(CFLAGS) $(DEFS_RT_P) -o $@ $< -$(RUNTIME_OBJ_C_D): %_d.o: %.c +$(RUNTIME_OBJ_D): %_d.o: %.c @$(CC) -M -MT $@ $(DEFS_RT_D) $< > .$*_d.d $(CC) -c $(CFLAGS) $(DEFS_RT_D) -o $@ $< diff --git a/colm/bytecode.c b/colm/bytecode.c new file mode 100644 index 00000000..59afafcb --- /dev/null +++ b/colm/bytecode.c @@ -0,0 +1,4175 @@ +/* + * Copyright 2007-2010 Adrian Thurston + */ + +/* This file is part of Colm. + * + * Colm is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Colm is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Colm; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + +#include "pdarun.h" +#include "fsmrun2.h" +#include "tree.h" +#include "bytecode2.h" +#include "pool.h" +#include "debug.h" +#include "config.h" + +#undef COLM_LOG +#undef COLM_LOG_BYTECODE +#undef COLM_LOG_PARSE +#undef COLM_LOG_MATCH +#undef COLM_LOG_COMPILE + +#define true 1 +#define false 0 + +#define push(i) (*(--sp) = (i)) +#define pop() (*sp++) +#define top() (*sp) +#define top_off(n) (sp[n]) +#define ptop() (sp) +#define popn(n) (sp += (n)) +#define pushn(n) (sp -= (n)) +#define local(o) (exec->frame[o]) +#define plocal(o) (&exec->frame[o]) +#define local_iframe(o) (exec->iframe[o]) +#define plocal_iframe(o) (&exec->iframe[o]) + +#define read_byte( i ) do { \ + i = ((uchar) *instr++); \ +} while(0) + +#define read_word_p( i, p ) do { \ + i = ((Word) p[0]); \ + i |= ((Word) p[1]) << 8; \ + i |= ((Word) p[2]) << 16; \ + i |= ((Word) p[3]) << 24; \ +} while(0) + +/* There are better ways. */ +#if SIZEOF_LONG == 4 + #define read_word( i ) do { \ + i = ((Word) *instr++); \ + i |= ((Word) *instr++) << 8; \ + i |= ((Word) *instr++) << 16; \ + i |= ((Word) *instr++) << 24; \ + } while(0) +#else + #define read_word( i ) do { \ + i = ((Word) *instr++); \ + i |= ((Word) *instr++) << 8; \ + i |= ((Word) *instr++) << 16; \ + i |= ((Word) *instr++) << 24; \ + i |= ((Word) *instr++) << 32; \ + i |= ((Word) *instr++) << 40; \ + i |= ((Word) *instr++) << 48; \ + i |= ((Word) *instr++) << 56; \ + } while(0) +#endif + +/* There are better ways. */ +#if SIZEOF_LONG == 4 + #define read_tree( i ) do { \ + Word w; \ + w = ((Word) *instr++); \ + w |= ((Word) *instr++) << 8; \ + w |= ((Word) *instr++) << 16; \ + w |= ((Word) *instr++) << 24; \ + i = (Tree*) w; \ + } while(0) +#else + #define read_tree( i ) do { \ + Word w; \ + w = ((Word) *instr++); \ + w |= ((Word) *instr++) << 8; \ + w |= ((Word) *instr++) << 16; \ + w |= ((Word) *instr++) << 24; \ + w |= ((Word) *instr++) << 32; \ + w |= ((Word) *instr++) << 40; \ + w |= ((Word) *instr++) << 48; \ + w |= ((Word) *instr++) << 56; \ + i = (Tree*) w; \ + } while(0) +#endif + +#define read_half( i ) do { \ + i = ((Word) *instr++); \ + i |= ((Word) *instr++) << 8; \ +} while(0) + +int colm_log_bytecode = 0; +int colm_log_parse = 0; +int colm_log_match = 0; +int colm_log_compile = 0; +int colm_log_conds = 0; + +Tree *prepParseTree( Program *prg, Tree **sp, Tree *tree ) +{ + /* Seems like we need to always copy here. If it isn't a parse tree it + * needs to be made into one. If it is then we need to make a new one in + * case the old one is still in use by some parsing routine. The case were + * we might be able to avoid a copy would be that it's a parse tree + * already, but it's owning parser is completely finished with it. */ + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "copying tree in send function" << endl; + } + #endif + Kid *unused = 0; + tree = copyRealTree( prg, tree, 0, &unused, true ); + return tree; +} + +void sendTreeFrag( Program *prg, Tree **sp, PdaRun *pdaRun, FsmRun *fsmRun, + InputStream *inputStream, + Tree *tree, int ignore ) +{ + tree = prepParseTree( prg, sp, tree ); + + if ( tree->id >= prg->rtd->firstNonTermId ) + tree->id = prg->rtd->lelInfo[tree->id].termDupId; + + tree->flags |= AF_ARTIFICIAL; + + treeUpref( tree ); + + /* FIXME: Do we need to remove the ignore tokens + * at this point? Will it cause a leak? */ + + Kid *send = kidAllocate( prg ); + send->tree = tree; + + LangElInfo *lelInfo = pdaRun->prg->rtd->lelInfo; + + /* Must clear next, since the parsing algorithm uses it. */ + if ( lelInfo[send->tree->id].ignore ) { + #ifdef COLM_LOG_PARSE + if ( colm_log_parse ) { + cerr << "ignoring queued item: " << + pdaRun->tables->rtd->lelInfo[send->tree->id].name << endl; + } + #endif + + incrementConsumed( pdaRun ); + + ignoreTree( pdaRun, send->tree ); + kidFree( pdaRun->prg, send ); + } + else { + #ifdef COLM_LOG_PARSE + if ( colm_log_parse ) { + cerr << "sending queue item: " << + pdaRun->tables->rtd->lelInfo[send->tree->id].name << endl; + } + #endif + + incrementConsumed( pdaRun ); + + sendHandleError( sp, pdaRun, fsmRun, inputStream, send ); + } +} + +void parserSetContext( Tree **sp, Program *prg, Accum *accum, Tree *val ) +{ + accum->pdaRun->context = splitTree( prg, val ); +} + +Head *treeToStr( Tree **sp, Program *prg, Tree *tree ) +{ + /* Collect the tree data. */ + StrCollect collect; + initStrCollect( &collect ); + + printTree( &collect, sp, prg, tree ); + + /* Set up the input stream. */ + Head *ret = stringAllocFull( prg, collect.data, collect.length ); + + strCollectDestroy( &collect ); + + return ret; +} + +Tree *extractInput( Program *prg, Accum *accum ) +{ + if ( accum->stream == 0 ) { + Stream *res = (Stream*)mapElAllocate( prg ); + res->id = LEL_ID_STREAM; + res->in = newInputStreamAccum(); + treeUpref( (Tree*)res ); + accum->stream = res; + } + + return (Tree*)accum->stream; +} + +void setInput( Program *prg, Tree **sp, Accum *accum, Stream *stream ) +{ + if ( accum->stream != 0 ) + treeDownref( prg, sp, (Tree*)accum->stream ); + + accum->stream = stream; + treeUpref( (Tree*)accum->stream ); +} + +void parseStream( Tree **sp, Program *prg, Tree *input, Accum *accum, long stopId ) +{ + accum->pdaRun->stopTarget = stopId; + + Stream *stream = (Stream*)input; + accum->fsmRun->curStream = input; + parseLoop( sp, accum->pdaRun, accum->fsmRun, stream->in ); +} + +Word streamAppend( Tree **sp, Program *prg, Tree *input, Stream *stream ) +{ + if ( input->id == LEL_ID_STR ) { + //assert(false); + /* Collect the tree data. */ + StrCollect collect; + initStrCollect( &collect ); + printTree( &collect, sp, prg, input ); + + /* Load it into the input. */ + stream->in->funcs->appendData( stream->in, collect.data, collect.length ); + + long length = collect.length; + strCollectDestroy( &collect ); + + return length; + } + else { + input = prepParseTree( prg, sp, input ); + + if ( input->id >= prg->rtd->firstNonTermId ) + input->id = prg->rtd->lelInfo[input->id].termDupId; + + input->flags |= AF_ARTIFICIAL; + + treeUpref( input ); + stream->in->funcs->appendTree( stream->in, input ); + return 0; + } +} + +void parseFrag( Tree **sp, Program *prg, Tree *input, Accum *accum, long stopId ) +{ + accum->pdaRun->stopTarget = stopId; + Stream *stream = (Stream*) extractInput( prg, accum ); + + if ( input->id == LEL_ID_STR ) { + //assert(false); + /* Collect the tree data. */ + StrCollect collect; + initStrCollect( &collect ); + printTree( &collect, sp, prg, input ); + + /* Load it into the input. */ + stream->in->funcs->appendData( stream->in, collect.data, collect.length ); + + /* Parse. */ + parseLoop( sp, accum->pdaRun, accum->fsmRun, stream->in ); + + strCollectDestroy( &collect ); + } + else { + //assert(false); + /* Cause a flush */ + + input = prepParseTree( prg, sp, input ); + + if ( input->id >= prg->rtd->firstNonTermId ) + input->id = prg->rtd->lelInfo[input->id].termDupId; + + input->flags |= AF_ARTIFICIAL; + + treeUpref( input ); + stream->in->funcs->appendTree( stream->in, input ); + + parseLoop( sp, accum->pdaRun, accum->fsmRun, stream->in ); + +// stream->in->flush = true; +// parseLoop( sp, accum->pdaRun, accum->fsmRun, stream->in ); + +// sendTreeFrag( prg, sp, accum->pdaRun, accum->fsmRun, stream->in, input, false ); + } +} + +void undoParseStream( Tree **sp, Program *prg, Stream *input, Accum *accum, long consumed ) +{ + if ( consumed < accum->pdaRun->consumed ) { + accum->pdaRun->numRetry += 1; + accum->pdaRun->targetConsumed = consumed; + parseToken( sp, accum->pdaRun, accum->fsmRun, input->in, 0 ); + accum->pdaRun->targetConsumed = -1; + accum->pdaRun->numRetry -= 1; + + accum->fsmRun->region = pdaRunGetNextRegion( accum->pdaRun, 0 ); + accum->fsmRun->cs = accum->fsmRun->tables->entryByRegion[accum->fsmRun->region]; + } +} + +Tree *parseFinish( Tree **sp, Program *prg, Accum *accum, int revertOn ) +{ + Stream *stream = (Stream*)extractInput( prg, accum ); + + if ( accum->pdaRun->stopTarget > 0 ) { + + } + else { + stream->in->eof = true; + stream->in->later = false; + parseLoop( sp, accum->pdaRun, accum->fsmRun, stream->in ); + } + + if ( !revertOn ) + commitFull( sp, accum->pdaRun, 0 ); + + Tree *tree = getParsedRoot( accum->pdaRun, accum->pdaRun->stopTarget > 0 ); + treeUpref( tree ); + + if ( !revertOn ) + cleanParser( sp, accum->pdaRun ); + + /* Indicate that this tree came out of a parser. */ + tree->flags |= AF_PARSED; + + return tree; +} + +Tree *streamPull2( Program *prg, FsmRun *fsmRun, Stream *stream, Tree *length ) +{ + long len = ((Int*)length)->value; + Head *tokdata = streamPull( prg, fsmRun, stream->in, len ); + return constructString( prg, tokdata ); +} + + +void undoPull( Program *prg, FsmRun *fsmRun, Stream *stream, Tree *str ) +{ + const char *data = stringData( ( (Str*)str )->value ); + long length = stringLength( ( (Str*)str )->value ); + undoStreamPull( fsmRun, stream->in, data, length ); +} + +Word streamPush( Program *prg, Tree **sp, Stream *stream, Tree *tree, int ignore ) +{ + if ( tree->id == LEL_ID_STR ) { + /* This should become a compile error. If it's text, it's up to the + * scanner to decide. Want to force it then send a token. */ + assert( !ignore ); + + /* Collect the tree data. */ + StrCollect collect; + initStrCollect( &collect ); + printTree( &collect, sp, prg, tree ); + + streamPushText( stream->in, collect.data, collect.length ); + long length = collect.length; + strCollectDestroy( &collect ); + + return length; + } + else { + tree = prepParseTree( prg, sp, tree ); + + if ( tree->id >= prg->rtd->firstNonTermId ) + tree->id = prg->rtd->lelInfo[tree->id].termDupId; + + tree->flags |= AF_ARTIFICIAL; + treeUpref( tree ); + streamPushTree( stream->in, tree, ignore ); + return 0; + } +} + +void setLocal( Tree **frame, long field, Tree *tree ) +{ + if ( tree != 0 ) + assert( tree->refs >= 1 ); + frame[field] = tree; +} + +Tree *getLocalSplit( Program *prg, Tree **frame, long field ) +{ + Tree *val = frame[field]; + Tree *split = splitTree( prg, val ); + frame[field] = split; + return split; +} + +void downrefLocalTrees( Program *prg, Tree **sp, Tree **frame, char *trees, long treesLen ) +{ + long i; + for ( i = 0; i < treesLen; i++ ) { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "local tree downref: " << (long)trees[i] << endl; + } + #endif + + treeDownref( prg, sp, frame[((long)trees[i])] ); + } +} + +UserIter *uiterCreate( Tree ***psp, Program *prg, FunctionInfo *fi, long searchId ) +{ + Tree **sp = *psp; + pushn( sizeof(UserIter) / sizeof(Word) ); + void *mem = ptop(); + + UserIter *uiter = mem; + initUserIter( uiter, ptop(), fi->argSize, searchId ); + *psp = sp; + return uiter; +} + +void uiterInit( Program *prg, Tree **sp, UserIter *uiter, + FunctionInfo *fi, int revertOn ) +{ + /* Set up the first yeild so when we resume it starts at the beginning. */ + uiter->ref.kid = 0; + uiter->stackSize = uiter->stackRoot - ptop(); + uiter->frame = &uiter->stackRoot[-IFR_AA]; + + if ( revertOn ) + uiter->resume = prg->rtd->frameInfo[fi->frameId].codeWV; + else + uiter->resume = prg->rtd->frameInfo[fi->frameId].codeWC; +} + +void treeIterDestroy( Tree ***psp, TreeIter *iter ) +{ + Tree **sp = *psp; + long curStackSize = iter->stackRoot - ptop(); + assert( iter->stackSize == curStackSize ); + popn( iter->stackSize ); + *psp = sp; +} + +void userIterDestroy( Tree ***psp, UserIter *uiter ) +{ + Tree **sp = *psp; + + /* We should always be coming from a yield. The current stack size will be + * nonzero and the stack size in the iterator will be correct. */ + long curStackSize = uiter->stackRoot - ptop(); + assert( uiter->stackSize == curStackSize ); + + long argSize = uiter->argSize; + + popn( uiter->stackRoot - ptop() ); + popn( sizeof(UserIter) / sizeof(Word) ); + popn( argSize ); + + *psp = sp; +} + +Tree *constructArgv( Program *prg, int argc, char **argv ) +{ + Tree *list = createGeneric( prg, 1 ); + treeUpref( list ); + int i; + for ( i = 0; i < argc; i++ ) { + Head *head = stringAllocPointer( prg, argv[i], strlen(argv[i]) ); + Tree *arg = constructString( prg, head ); + treeUpref( arg ); + listAppend2( prg, (List*)list, arg ); + } + return list; +} + + +/* + * Execution environment + */ + +void initProgram( Program *prg, int argc, char **argv, int ctxDepParsing, + RuntimeData *rtd ) +{ + prg->argc = argc; + prg->argv = argv; + prg->ctxDepParsing = ctxDepParsing; + prg->rtd = rtd; + prg->global = 0; + prg->heap = 0; + prg->stdinVal = 0; + prg->stdoutVal = 0; + prg->stderrVal = 0; + + initPoolAlloc( &prg->kidPool, sizeof(Kid) ); + initPoolAlloc( &prg->treePool, sizeof(Tree) ); + initPoolAlloc( &prg->parseTreePool, sizeof(ParseTree) ); + initPoolAlloc( &prg->listElPool, sizeof(ListEl) ); + initPoolAlloc( &prg->mapElPool, sizeof(MapEl) ); + initPoolAlloc( &prg->headPool, sizeof(Head) ); + initPoolAlloc( &prg->locationPool, sizeof(Location) ); + + Int *trueInt = (Int*) treeAllocate( prg ); + trueInt->id = LEL_ID_BOOL; + trueInt->refs = 1; + trueInt->value = 1; + + Int *falseInt = (Int*) treeAllocate( prg ); + falseInt->id = LEL_ID_BOOL; + falseInt->refs = 1; + falseInt->value = 0; + + prg->trueVal = (Tree*)trueInt; + prg->falseVal = (Tree*)falseInt; +} + +void clearGlobal( Program *prg, Tree **sp ) +{ + /* Downref all the fields in the global object. */ + int g; + for ( g = 0; g < prg->rtd->globalSize; g++ ) { + //assert( getAttr( global, g )->refs == 1 ); + treeDownref( prg, sp, getAttr( prg->global, g ) ); + } + + /* Free the global object. */ + if ( prg->rtd->globalSize > 0 ) + freeAttrs( prg, prg->global->child ); + treeFree( prg, prg->global ); +} + +void clearProgram( Program *prg, Tree **vm_stack, Tree **sp ) +{ + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "clearing the prg" << endl; + } + #endif + + clearGlobal( prg, sp ); + + /* Clear the heap. */ + Kid *a = prg->heap; + while ( a != 0 ) { + Kid *next = a->next; + treeDownref( prg, sp, a->tree ); + kidFree( prg, a ); + a = next; + } + + //assert( trueVal->refs == 1 ); + //assert( falseVal->refs == 1 ); + treeDownref( prg, sp, prg->trueVal ); + treeDownref( prg, sp, prg->falseVal ); + + treeDownref( prg, sp, (Tree*)prg->stdinVal ); + treeDownref( prg, sp, (Tree*)prg->stdoutVal ); + treeDownref( prg, sp, (Tree*)prg->stderrVal ); + + long kidLost = kidNumLost( prg ); + if ( kidLost ) + message( "warning: lost kids: %ld\n", kidLost ); + + long treeLost = treeNumLost( prg ); + if ( treeLost ) + message( "warning: lost trees: %ld\n", treeLost ); + + long parseTreeLost = parseTreeNumLost( prg ); + if ( parseTreeLost ) + message( "warning: lost parse trees: %ld\n", parseTreeLost ); + + long listLost = listElNumLost( prg ); + if ( listLost ) + message( "warning: lost listEls: %ld\n", listLost ); + + long mapLost = mapElNumLost( prg ); + if ( mapLost ) + message( "warning: lost mapEls: %ld\n", mapLost ); + + long headLost = headNumLost( prg ); + if ( headLost ) + message( "warning: lost heads: %ld\n", headLost ); + + long locationLost = locationNumLost( prg ); + if ( locationLost ) + message( "warning: lost locations: %ld\n", locationLost ); + + kidClear( prg ); + treeClear( prg ); + parseTreeClear( prg ); + listElClear( prg ); + mapElClear( prg ); + locationClear( prg ); + + //exec->reverseCode->empty(); + //memset( vm_stack, 0, sizeof(Tree*) * VM_STACK_SIZE); +} + +void allocGlobal( Program *prg ) +{ + /* Alloc the global. */ + Tree *tree = treeAllocate( prg ); + tree->child = allocAttrs( prg, prg->rtd->globalSize ); + tree->refs = 1; + prg->global = tree; +} + +Tree **stackAlloc() +{ + //return new Tree*[VM_STACK_SIZE]; + + return (Tree**)mmap( 0, sizeof(Tree*)*VM_STACK_SIZE, + PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0 ); +} + +void runProgram( Program *prg ) +{ + assert( sizeof(Int) <= sizeof(Tree) ); + assert( sizeof(Str) <= sizeof(Tree) ); + assert( sizeof(Pointer) <= sizeof(Tree) ); + assert( sizeof(Map) <= sizeof(MapEl) ); + assert( sizeof(List) <= sizeof(MapEl) ); + assert( sizeof(Stream) <= sizeof(MapEl) ); + assert( sizeof(Accum) <= sizeof(MapEl) ); + + /* Allocate the global variable. */ + allocGlobal( prg ); + + /* + * Allocate the VM stack. + */ + + Tree **vm_stack = stackAlloc(); + Tree **root = &vm_stack[VM_STACK_SIZE]; + + /* + * Execute + */ + + if ( prg->rtd->rootCodeLen > 0 ) { + RtCodeVect reverseCode; + Execution execution; + initRtCodeVect( &reverseCode ); + initExecution( &execution, prg, &reverseCode, 0, 0, prg->rtd->rootCode, 0, 0, 0, 0 ); + execute( &execution, root ); + + /* Pull out the reverse code and free it. */ + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "freeing the root reverse code" << endl; + } + #endif + + /* The root code should all be commit code and reverseCode + * should be empty. */ + assert( reverseCode.tabLen == 0 ); + } + + /* Clear */ + clearProgram( prg, vm_stack, root ); +} + +void initExecution( Execution *exec, Program *prg, RtCodeVect *reverseCode, + PdaRun *pdaRun, FsmRun *fsmRun, Code *code, Tree *lhs, + long genId, Head *matchText, char **captures ) +{ + exec->prg = prg; + exec->pdaRun = pdaRun; + exec->fsmRun = fsmRun; + exec->code = code; + exec->frame = 0; + exec->iframe = 0; + exec->lhs = lhs; + exec->parsed = 0; + exec->genId = genId; + exec->matchText = matchText; + exec->reject = false; + exec->reverseCode = reverseCode; + exec->rcodeUnitLen = 0; + exec->captures = captures; + + assert( lhs == 0 || lhs->refs == 1 ); +} + +void rcodeDownrefAll( Program *prg, Tree **sp, RtCodeVect *rev ) +{ + while ( rev->tabLen > 0 ) { + /* Read the length */ + Code *prcode = rev->data + rev->tabLen - SIZEOF_WORD; + Word len; + read_word_p( len, prcode ); + + /* Find the start of block. */ + long start = rev->tabLen - len - SIZEOF_WORD; + prcode = rev->data + start; + + /* Execute it. */ + rcodeDownref( prg, sp, prcode ); + + /* Backup over it. */ + rev->tabLen -= len + SIZEOF_WORD; + } +} + +void rcodeDownref( Program *prg, Tree **sp, Code *instr ) +{ +again: + switch ( *instr++ ) { + case IN_RESTORE_LHS: { + Tree *lhs; + read_tree( lhs ); + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_RESTORE_LHS" << endl; + } + #endif + treeDownref( prg, sp, lhs ); + break; + } + + case IN_EXTRACT_INPUT_BKT: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) + cerr << "IN_EXTRACT_INPUT_BKT" << endl; + #endif + break; + } + case IN_STREAM_APPEND_BKT: { + Tree *stream; + Tree *input; + Word len; + read_tree( stream ); + read_tree( input ); + read_word( len ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_STREAM_APPEND_BKT" << endl; + } + #endif + + treeDownref( prg, sp, stream ); + treeDownref( prg, sp, input ); + break; + } + case IN_PARSE_FRAG_BKT: { + Tree *accum; + Tree *input; + long consumed; + read_tree( accum ); + read_tree( input ); + read_word( consumed ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) + cerr << "IN_PARSE_FRAG_BKT " << consumed << endl; + #endif + + treeDownref( prg, sp, accum ); + treeDownref( prg, sp, input ); + break; + } + case IN_PARSE_FINISH_BKT: { + Tree *accumTree; + Tree *tree; + long consumed; + + read_tree( accumTree ); + read_tree( tree ); + read_word( consumed ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_PARSE_FINISH_BKT " << consumed << endl; + } + #endif + + treeDownref( prg, sp, accumTree ); + treeDownref( prg, sp, tree ); + break; + } + case IN_STREAM_PULL_BKT: { + Tree *string; + read_tree( string ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_STREAM_PULL_BKT" << endl; + } + #endif + + treeDownref( prg, sp, string ); + break; + } + case IN_STREAM_PUSH_BKT: { + Word len; + read_word( len ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_STREAM_PUSH_BKT" << endl; + } + #endif + break; + } + case IN_LOAD_GLOBAL_BKT: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_LOAD_GLOBAL_BKT" << endl; + } + #endif + break; + } + case IN_LOAD_CONTEXT_BKT: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_LOAD_CONTEXT_BKT" << endl; + } + #endif + break; + } + case IN_LOAD_INPUT_BKT: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_LOAD_INPUT_BKT" << endl; + } + #endif + break; + } + case IN_GET_FIELD_BKT: { + short field; + read_half( field ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_GET_FIELD_BKT " << field << endl; + } + #endif + break; + } + case IN_SET_FIELD_BKT: { + short field; + Tree *val; + read_half( field ); + read_tree( val ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_SET_FIELD_BKT " << field << endl; + } + #endif + + treeDownref( prg, sp, val ); + break; + } + case IN_PTR_DEREF_BKT: { + Tree *ptr; + read_tree( ptr ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_PTR_DEREF_BKT" << endl; + } + #endif + + treeDownref( prg, sp, ptr ); + break; + } + case IN_SET_TOKEN_DATA_BKT: { + Word oldval; + read_word( oldval ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_SET_TOKEN_DATA_BKT " << endl; + } + #endif + + Head *head = (Head*)oldval; + stringFree( prg, head ); + break; + } + case IN_LIST_APPEND_BKT: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_LIST_APPEND_BKT" << endl; + } + #endif + break; + } + case IN_LIST_REMOVE_END_BKT: { + Tree *val; + read_tree( val ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_LIST_REMOVE_END_BKT" << endl; + } + #endif + + treeDownref( prg, sp, val ); + break; + } + case IN_GET_LIST_MEM_BKT: { + short field; + read_half( field ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_GET_LIST_MEM_BKT " << field << endl; + } + #endif + break; + } + case IN_SET_LIST_MEM_BKT: { + Half field; + Tree *val; + read_half( field ); + read_tree( val ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_SET_LIST_MEM_BKT " << field << endl; + } + #endif + + treeDownref( prg, sp, val ); + break; + } + case IN_MAP_INSERT_BKT: { + uchar inserted; + Tree *key; + read_byte( inserted ); + read_tree( key ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_MAP_INSERT_BKT" << endl; + } + #endif + + treeDownref( prg, sp, key ); + break; + } + case IN_MAP_STORE_BKT: { + Tree *key, *val; + read_tree( key ); + read_tree( val ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_MAP_STORE_BKT" << endl; + } + #endif + + treeDownref( prg, sp, key ); + treeDownref( prg, sp, val ); + break; + } + case IN_MAP_REMOVE_BKT: { + Tree *key, *val; + read_tree( key ); + read_tree( val ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_MAP_REMOVE_BKT" << endl; + } + #endif + + treeDownref( prg, sp, key ); + treeDownref( prg, sp, val ); + break; + } + case IN_STOP: { + return; + } + default: { + fatal( "UNKNOWN INSTRUCTION: -- reverse code downref\n" ); + assert(false); + break; + } + } + goto again; +} + +void execute( Execution *exec, Tree **sp ) +{ + /* If we have a lhs push it to the stack. */ + int haveLhs = exec->lhs != 0; + if ( haveLhs ) + push( exec->lhs ); + + /* Execution loop. */ + executeCode( exec, sp, exec->code ); + + /* Take the lhs off the stack. */ + if ( haveLhs ) + exec->lhs = (Tree*) pop(); +} + +int makeReverseCode( RtCodeVect *all, RtCodeVect *reverseCode ) +{ + /* Do we need to revert the left hand side? */ + + /* Check if there was anything generated. */ + if ( reverseCode->tabLen == 0 ) + return false; + + long prevAllLength = all->tabLen; + + /* Go backwards, group by group, through the reverse code. Push each group + * to the global reverse code stack. */ + Code *p = reverseCode->data + reverseCode->tabLen; + while ( p != reverseCode->data ) { + p--; + long len = *p; + p = p - len; + append2( all, p, len ); + } + + /* Stop, then place a total length in the global stack. */ + append( all, IN_STOP ); + long length = all->tabLen - prevAllLength; + appendWord( all, length ); + + /* Clear the revere code buffer. */ + reverseCode->tabLen = 0; + + return true; +} + +void rexecute( Execution *exec, Tree **root, RtCodeVect *allRev ) +{ + /* Read the length */ + Code *prcode = allRev->data + allRev->tabLen - SIZEOF_WORD; + Word len; + read_word_p( len, prcode ); + + /* Find the start of block. */ + long start = allRev->tabLen - len - SIZEOF_WORD; + prcode = allRev->data + start; + + /* Execute it. */ + Tree **sp = root; + executeCode( exec, sp, prcode ); + assert( sp == root ); + + /* Backup over it. */ + allRev->tabLen -= len + SIZEOF_WORD; +} + +void executeCode( Execution *exec, Tree **sp, Code *instr ) +{ + /* When we exit we are going to verify that we did not eat up any stack + * space. */ + Tree **root = sp; + Program *prg = exec->prg; + +again: + switch ( *instr++ ) { + case IN_SAVE_LHS: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_SAVE_LHS" << endl; + } + #endif + + assert( exec->lhs != 0 ); + + /* Save and upref before writing. We don't generate a restore + * here. Instead, in the parser we will check if it actually + * changed and insert the instruction then. The presence of this + * instruction here is just a conservative approximation. */ + exec->parsed = exec->lhs; + //treeUpref( parsed ); + break; + } + case IN_RESTORE_LHS: { + Tree *restore; + read_tree( restore ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_RESTORE_LHS" << endl; + } + #endif + assert( exec->lhs == 0 ); + exec->lhs = restore; + break; + } + case IN_LOAD_NIL: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_LOAD_NIL" << endl; + } + #endif + + push( 0 ); + break; + } + case IN_LOAD_TRUE: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_LOAD_TRUE" << endl; + } + #endif + + treeUpref( prg->trueVal ); + push( prg->trueVal ); + break; + } + case IN_LOAD_FALSE: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_LOAD_FALSE" << endl; + } + #endif + + treeUpref( prg->falseVal ); + push( prg->falseVal ); + break; + } + case IN_LOAD_INT: { + Word i; + read_word( i ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_LOAD_INT " << i << endl; + } + #endif + + Tree *tree = constructInteger( prg, i ); + treeUpref( tree ); + push( tree ); + break; + } + case IN_LOAD_STR: { + Word offset; + read_word( offset ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_LOAD_STR " << offset << endl; + } + #endif + + Head *lit = makeLiteral( prg, offset ); + Tree *tree = constructString( prg, lit ); + treeUpref( tree ); + push( tree ); + break; + } + case IN_PRINT: { + int n; + read_byte( n ); + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_PRINT " << n << endl; + } + #endif + + while ( n-- > 0 ) { + Tree *tree = pop(); + printTree2( stdout, sp, prg, tree ); + treeDownref( prg, sp, tree ); + } + break; + } + case IN_PRINT_XML_AC: { + int n; + read_byte( n ); + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_PRINT_XML_AC" << n << endl; + } + #endif + + while ( n-- > 0 ) { + Tree *tree = pop(); + printXmlTree( sp, prg, tree, true ); + treeDownref( prg, sp, tree ); + } + break; + } + case IN_PRINT_XML: { + int n; + read_byte( n ); + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_PRINT_XML" << n << endl; + } + #endif + + while ( n-- > 0 ) { + Tree *tree = pop(); + printXmlTree( sp, prg, tree, false ); + treeDownref( prg, sp, tree ); + } + break; + } + case IN_PRINT_STREAM: { + int n; + read_byte( n ); + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_PRINT_STREAM" << n << endl; + } + #endif + + Stream *stream = (Stream*)pop(); + while ( n-- > 0 ) { + Tree *tree = pop(); + printTree2( stream->file, sp, prg, tree ); + treeDownref( prg, sp, tree ); + } + treeDownref( prg, sp, (Tree*)stream ); + break; + } + case IN_LOAD_CONTEXT_R: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_LOAD_CONTEXT_R" << endl; + } + #endif + + treeUpref( exec->pdaRun->context ); + push( exec->pdaRun->context ); + break; + } + case IN_LOAD_CONTEXT_WV: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_LOAD_CONTEXT_WV" << endl; + } + #endif + + treeUpref( exec->pdaRun->context ); + push( exec->pdaRun->context ); + + /* Set up the reverse instruction. */ + append( exec->reverseCode, IN_LOAD_CONTEXT_BKT ); + exec->rcodeUnitLen = SIZEOF_CODE; + break; + } + case IN_LOAD_CONTEXT_WC: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_LOAD_CONTEXT_WC" << endl; + } + #endif + + /* This is identical to the _R version, but using it for writing + * would be confusing. */ + treeUpref( exec->pdaRun->context ); + push( exec->pdaRun->context ); + break; + } + case IN_LOAD_CONTEXT_BKT: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_LOAD_CONTEXT_BKT" << endl; + } + #endif + + treeUpref( exec->pdaRun->context ); + push( exec->pdaRun->context ); + break; + } + case IN_LOAD_GLOBAL_R: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_LOAD_GLOBAL_R" << endl; + } + #endif + + treeUpref( prg->global ); + push( prg->global ); + break; + } + case IN_LOAD_GLOBAL_WV: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_LOAD_GLOBAL_WV" << endl; + } + #endif + + treeUpref( prg->global ); + push( prg->global ); + + /* Set up the reverse instruction. */ + append( exec->reverseCode, IN_LOAD_GLOBAL_BKT ); + exec->rcodeUnitLen = SIZEOF_CODE; + break; + } + case IN_LOAD_GLOBAL_WC: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_LOAD_GLOBAL_WC" << endl; + } + #endif + + /* This is identical to the _R version, but using it for writing + * would be confusing. */ + treeUpref( prg->global ); + push( prg->global ); + break; + } + case IN_LOAD_GLOBAL_BKT: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_LOAD_GLOBAL_BKT" << endl; + } + #endif + + treeUpref( prg->global ); + push( prg->global ); + break; + } + case IN_LOAD_INPUT_R: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_LOAD_INPUT_R" << endl; + } + #endif + + treeUpref( exec->fsmRun->curStream ); + push( exec->fsmRun->curStream ); + break; + } + case IN_LOAD_INPUT_WV: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_LOAD_INPUT_WV" << endl; + } + #endif + + treeUpref( exec->fsmRun->curStream ); + push( exec->fsmRun->curStream ); + + /* Set up the reverse instruction. */ + append( exec->reverseCode, IN_LOAD_INPUT_BKT ); + exec->rcodeUnitLen = SIZEOF_CODE; + break; + } + case IN_LOAD_INPUT_WC: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_LOAD_INPUT_WC" << endl; + } + #endif + + /* This is identical to the _R version, but using it for writing + * would be confusing. */ + treeUpref( exec->fsmRun->curStream ); + push( exec->fsmRun->curStream ); + break; + } + case IN_LOAD_INPUT_BKT: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_LOAD_INPUT_BKT" << endl; + } + #endif + + treeUpref( exec->fsmRun->curStream ); + push( exec->fsmRun->curStream ); + break; + } + case IN_LOAD_CTX_R: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_LOAD_CTX_R" << endl; + } + #endif + + treeUpref( exec->pdaRun->context ); + push( exec->pdaRun->context ); + break; + } + case IN_LOAD_CTX_WV: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_LOAD_CTX_WV" << endl; + } + #endif + + treeUpref( exec->pdaRun->context ); + push( exec->pdaRun->context ); + + /* Set up the reverse instruction. */ + append( exec->reverseCode, IN_LOAD_INPUT_BKT ); + exec->rcodeUnitLen = SIZEOF_CODE; + break; + } + case IN_LOAD_CTX_WC: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_LOAD_CTX_WC" << endl; + } + #endif + + /* This is identical to the _R version, but using it for writing + * would be confusing. */ + treeUpref( exec->pdaRun->context ); + push( exec->pdaRun->context ); + break; + } + case IN_LOAD_CTX_BKT: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_LOAD_CTX_BKT" << endl; + } + #endif + + treeUpref( exec->pdaRun->context ); + push( exec->pdaRun->context ); + break; + } + case IN_INIT_CAPTURES: { + uchar ncaps; + read_byte( ncaps ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_INIT_CAPTURES " << ncaps << endl; + } + #endif + + /* If there are captures (this is a translate block) then copy them into + * the local frame now. */ + LangElInfo *lelInfo = prg->rtd->lelInfo; + char **mark = exec->captures; + + int i; + for ( i = 0; i < lelInfo[exec->genId].numCaptureAttr; i++ ) { + CaptureAttr *ca = &prg->rtd->captureAttr[lelInfo[exec->genId].captureAttr + i]; + Head *data = stringAllocFull( prg, + mark[ca->mark_enter], mark[ca->mark_leave] - mark[ca->mark_enter] ); + Tree *string = constructString( prg, data ); + treeUpref( string ); + setLocal( exec->frame, -1 - i, string ); + } + break; + } + case IN_INIT_RHS_EL: { + Half position; + short field; + read_half( position ); + read_half( field ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_INIT_RHS_EL " << position << " " << field << endl; + } + #endif + + Tree *val = getRhsEl( prg, exec->lhs, position ); + treeUpref( val ); + local(field) = val; + break; + } + case IN_UITER_ADVANCE: { + short field; + read_half( field ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_UITER_ADVANCE " << field << endl; + } + #endif + + /* Get the iterator. */ + UserIter *uiter = (UserIter*) local(field); + + long stackSize = uiter->stackRoot - ptop(); + assert( uiter->stackSize == stackSize ); + + /* Fix the return instruction pointer. */ + uiter->stackRoot[-IFR_AA + IFR_RIN] = (SW)instr; + + instr = uiter->resume; + exec->frame = uiter->frame; + exec->iframe = &uiter->stackRoot[-IFR_AA]; + break; + } + case IN_UITER_GET_CUR_R: { + short field; + read_half( field ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_UITER_GET_CUR_R " << field << endl; + } + #endif + + UserIter *uiter = (UserIter*) local(field); + Tree *val = uiter->ref.kid->tree; + treeUpref( val ); + push( val ); + break; + } + case IN_UITER_GET_CUR_WC: { + short field; + read_half( field ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_UITER_GET_CUR_WC " << field << endl; + } + #endif + + UserIter *uiter = (UserIter*) local(field); + splitRef( &sp, prg, &uiter->ref ); + Tree *split = uiter->ref.kid->tree; + treeUpref( split ); + push( split ); + break; + } + case IN_UITER_SET_CUR_WC: { + short field; + read_half( field ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_UITER_SET_CUR_WC " << field << endl; + } + #endif + + Tree *t = pop(); + UserIter *uiter = (UserIter*) local(field); + splitRef( &sp, prg, &uiter->ref ); + Tree *old = uiter->ref.kid->tree; + uiter->ref.kid->tree = t; + treeDownref( prg, sp, old ); + break; + } + case IN_GET_LOCAL_R: { + short field; + read_half( field ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_GET_LOCAL_R " << field << endl; + } + #endif + + Tree *val = local(field); + treeUpref( val ); + push( val ); + break; + } + case IN_GET_LOCAL_WC: { + short field; + read_half( field ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_GET_LOCAL_WC " << field << endl; + } + #endif + + Tree *split = getLocalSplit( prg, exec->frame, field ); + treeUpref( split ); + push( split ); + break; + } + case IN_SET_LOCAL_WC: { + short field; + read_half( field ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_SET_LOCAL_WC " << field << endl; + } + #endif + + Tree *val = pop(); + treeDownref( prg, sp, local(field) ); + setLocal( exec->frame, field, val ); + break; + } + case IN_SAVE_RET: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_SAVE_RET " << endl; + } + #endif + + Tree *val = pop(); + local(FR_RV) = val; + break; + } + case IN_GET_LOCAL_REF_R: { + short field; + read_half( field ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_GET_LOCAL_REF_R " << field << endl; + } + #endif + + Ref *ref = (Ref*) plocal(field); + Tree *val = ref->kid->tree; + treeUpref( val ); + push( val ); + break; + } + case IN_GET_LOCAL_REF_WC: { + short field; + read_half( field ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_GET_LOCAL_REF_WC " << field << endl; + } + #endif + + Ref *ref = (Ref*) plocal(field); + splitRef( &sp, prg, ref ); + Tree *val = ref->kid->tree; + treeUpref( val ); + push( val ); + break; + } + case IN_SET_LOCAL_REF_WC: { + short field; + read_half( field ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_SET_LOCAL_REF_WC " << field << endl; + } + #endif + + Tree *val = pop(); + Ref *ref = (Ref*) plocal(field); + splitRef( &sp, prg, ref ); + refSetValue( ref, val ); + break; + } + case IN_GET_FIELD_R: { + short field; + read_half( field ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_GET_FIELD_R " << field << endl; + } + #endif + + Tree *obj = pop(); + treeDownref( prg, sp, obj ); + + Tree *val = getField( obj, field ); + treeUpref( val ); + push( val ); + break; + } + case IN_GET_FIELD_WC: { + short field; + read_half( field ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_GET_FIELD_WC " << field << endl; + } + #endif + + Tree *obj = pop(); + treeDownref( prg, sp, obj ); + + Tree *split = getFieldSplit( prg, obj, field ); + treeUpref( split ); + push( split ); + break; + } + case IN_GET_FIELD_WV: { + short field; + read_half( field ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_GET_FIELD_WV " << field << endl; + } + #endif + + Tree *obj = pop(); + treeDownref( prg, sp, obj ); + + Tree *split = getFieldSplit( prg, obj, field ); + treeUpref( split ); + push( split ); + + /* Set up the reverse instruction. */ + append( exec->reverseCode, IN_GET_FIELD_BKT ); + appendHalf( exec->reverseCode, field ); + exec->rcodeUnitLen += SIZEOF_CODE + SIZEOF_HALF; + break; + } + case IN_GET_FIELD_BKT: { + short field; + read_half( field ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_GET_FIELD_BKT " << field << endl; + } + #endif + + Tree *obj = pop(); + treeDownref( prg, sp, obj ); + + Tree *split = getFieldSplit( prg, obj, field ); + treeUpref( split ); + push( split ); + break; + } + case IN_SET_FIELD_WC: { + short field; + read_half( field ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_SET_FIELD_WC " << field << endl; + } + #endif + + Tree *obj = pop(); + Tree *val = pop(); + treeDownref( prg, sp, obj ); + + /* Downref the old value. */ + Tree *prev = getField( obj, field ); + treeDownref( prg, sp, prev ); + + setField( prg, obj, field, val ); + break; + } + case IN_SET_FIELD_WV: { + short field; + read_half( field ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_SET_FIELD_WV " << field << endl; + } + #endif + + Tree *obj = pop(); + Tree *val = pop(); + treeDownref( prg, sp, obj ); + + /* Save the old value, then set the field. */ + Tree *prev = getField( obj, field ); + setField( prg, obj, field, val ); + + /* Set up the reverse instruction. */ + append( exec->reverseCode, IN_SET_FIELD_BKT ); + appendHalf( exec->reverseCode, field ); + appendWord( exec->reverseCode, (Word)prev ); + exec->rcodeUnitLen += SIZEOF_CODE + SIZEOF_HALF + SIZEOF_WORD; + append( exec->reverseCode, exec->rcodeUnitLen ); + /* FLUSH */ + break; + } + case IN_SET_FIELD_BKT: { + short field; + Tree *val; + read_half( field ); + read_tree( val ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_SET_FIELD_BKT " << field << endl; + } + #endif + + Tree *obj = pop(); + treeDownref( prg, sp, obj ); + + /* Downref the old value. */ + Tree *prev = getField( obj, field ); + treeDownref( prg, sp, prev ); + + setField( prg, obj, field, val ); + break; + } + case IN_SET_FIELD_LEAVE_WC: { + short field; + read_half( field ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_SET_FIELD_LEAVE_WC " << field << endl; + } + #endif + + /* Note that we don't downref the object here because we are + * leaving it on the stack. */ + Tree *obj = pop(); + Tree *val = pop(); + + /* Downref the old value. */ + Tree *prev = getField( obj, field ); + treeDownref( prg, sp, prev ); + + /* Set the field. */ + setField( prg, obj, field, val ); + + /* Leave the object on the top of the stack. */ + push( obj ); + break; + } + case IN_POP: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_POP" << endl; + } + #endif + + Tree *val = pop(); + treeDownref( prg, sp, val ); + break; + } + case IN_POP_N_WORDS: { + short n; + read_half( n ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_POP_N_WORDS " << n << endl; + } + #endif + + popn( n ); + break; + } + case IN_SPRINTF: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_SPRINTF" << endl; + } + #endif + + Tree *f = pop(); + f++; + Tree *integer = pop(); + Tree *format = pop(); + Head *res = stringSprintf( prg, (Str*)format, (Int*)integer ); + Tree *str = constructString( prg, res ); + treeUpref( str ); + push( str ); + treeDownref( prg, sp, integer ); + treeDownref( prg, sp, format ); + break; + } + case IN_STR_ATOI: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_STR_ATOI" << endl; + } + #endif + + Str *str = (Str*)pop(); + Word res = strAtoi( str->value ); + Tree *integer = constructInteger( prg, res ); + treeUpref( integer ); + push( integer ); + treeDownref( prg, sp, (Tree*)str ); + break; + } + case IN_INT_TO_STR: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_INT_TO_STR" << endl; + } + #endif + + Int *i = (Int*)pop(); + Head *res = intToStr( prg, i->value ); + Tree *str = constructString( prg, res ); + treeUpref( str ); + push( str ); + treeDownref( prg, sp, (Tree*) i ); + break; + } + case IN_TREE_TO_STR: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_TREE_TO_STR" << endl; + } + #endif + + Tree *tree = pop(); + Head *res = treeToStr( sp, prg, tree ); + Tree *str = constructString( prg, res ); + treeUpref( str ); + push( str ); + treeDownref( prg, sp, tree ); + break; + } + case IN_CONCAT_STR: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_CONCAT_STR" << endl; + } + #endif + + Str *s2 = (Str*)pop(); + Str *s1 = (Str*)pop(); + Head *res = concatStr( s1->value, s2->value ); + Tree *str = constructString( prg, res ); + treeUpref( str ); + treeDownref( prg, sp, (Tree*)s1 ); + treeDownref( prg, sp, (Tree*)s2 ); + push( str ); + break; + } + case IN_STR_UORD8: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_STR_UORD8" << endl; + } + #endif + + Str *str = (Str*)pop(); + Word res = strUord8( str->value ); + Tree *tree = constructInteger( prg, res ); + treeUpref( tree ); + push( tree ); + treeDownref( prg, sp, (Tree*)str ); + break; + } + case IN_STR_UORD16: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_STR_UORD16" << endl; + } + #endif + + Str *str = (Str*)pop(); + Word res = strUord16( str->value ); + Tree *tree = constructInteger( prg, res ); + treeUpref( tree ); + push( tree ); + treeDownref( prg, sp, (Tree*)str ); + break; + } + + case IN_STR_LENGTH: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_STR_LENGTH" << endl; + } + #endif + + Str *str = (Str*)pop(); + long len = stringLength( str->value ); + Tree *res = constructInteger( prg, len ); + treeUpref( res ); + push( res ); + treeDownref( prg, sp, (Tree*)str ); + break; + } + case IN_JMP_FALSE: { + short dist; + read_half( dist ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_JMP_FALSE " << dist << endl; + } + #endif + + Tree *tree = pop(); + if ( testFalse( prg, tree ) ) + instr += dist; + treeDownref( prg, sp, tree ); + break; + } + case IN_JMP_TRUE: { + short dist; + read_half( dist ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_JMP_TRUE " << dist << endl; + } + #endif + + Tree *tree = pop(); + if ( !testFalse( prg, tree ) ) + instr += dist; + treeDownref( prg, sp, tree ); + break; + } + case IN_JMP: { + short dist; + read_half( dist ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_JMP " << dist << endl; + } + #endif + + instr += dist; + break; + } + case IN_REJECT: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_REJECT" << endl; + } + #endif + exec->reject = true; + break; + } + + /* + * Binary comparison operators. + */ + case IN_TST_EQL: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_TST_EQL" << endl; + } + #endif + + Tree *o2 = pop(); + Tree *o1 = pop(); + long r = cmpTree( prg, o1, o2 ); + Tree *val = r ? prg->falseVal : prg->trueVal; + treeUpref( val ); + push( val ); + treeDownref( prg, sp, o1 ); + treeDownref( prg, sp, o2 ); + break; + } + case IN_TST_NOT_EQL: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_TST_NOT_EQL" << endl; + } + #endif + + Tree *o2 = pop(); + Tree *o1 = pop(); + long r = cmpTree( prg, o1, o2 ); + Tree *val = r ? prg->trueVal : prg->falseVal; + treeUpref( val ); + push( val ); + treeDownref( prg, sp, o1 ); + treeDownref( prg, sp, o2 ); + break; + } + case IN_TST_LESS: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_TST_LESS" << endl; + } + #endif + + Tree *o2 = pop(); + Tree *o1 = pop(); + long r = cmpTree( prg, o1, o2 ); + Tree *val = r < 0 ? prg->trueVal : prg->falseVal; + treeUpref( val ); + push( val ); + treeDownref( prg, sp, o1 ); + treeDownref( prg, sp, o2 ); + break; + } + case IN_TST_LESS_EQL: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_TST_LESS_EQL" << endl; + } + #endif + + Tree *o2 = pop(); + Tree *o1 = pop(); + long r = cmpTree( prg, o1, o2 ); + Tree *val = r <= 0 ? prg->trueVal : prg->falseVal; + treeUpref( val ); + push( val ); + treeDownref( prg, sp, o1 ); + treeDownref( prg, sp, o2 ); + } + case IN_TST_GRTR: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_TST_GRTR" << endl; + } + #endif + + Tree *o2 = pop(); + Tree *o1 = pop(); + long r = cmpTree( prg, o1, o2 ); + Tree *val = r > 0 ? prg->trueVal : prg->falseVal; + treeUpref( val ); + push( val ); + treeDownref( prg, sp, o1 ); + treeDownref( prg, sp, o2 ); + break; + } + case IN_TST_GRTR_EQL: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_TST_GRTR_EQL" << endl; + } + #endif + + Tree *o2 = (Tree*)pop(); + Tree *o1 = (Tree*)pop(); + long r = cmpTree( prg, o1, o2 ); + Tree *val = r >= 0 ? prg->trueVal : prg->falseVal; + treeUpref( val ); + push( val ); + treeDownref( prg, sp, o1 ); + treeDownref( prg, sp, o2 ); + break; + } + case IN_TST_LOGICAL_AND: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_TST_LOGICAL_AND" << endl; + } + #endif + + Tree *o2 = pop(); + Tree *o1 = pop(); + long v2 = !testFalse( prg, o2 ); + long v1 = !testFalse( prg, o1 ); + Word r = v1 && v2; + Tree *val = r ? prg->trueVal : prg->falseVal; + treeUpref( val ); + push( val ); + treeDownref( prg, sp, o1 ); + treeDownref( prg, sp, o2 ); + break; + } + case IN_TST_LOGICAL_OR: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_TST_LOGICAL_OR" << endl; + } + #endif + + Tree *o2 = pop(); + Tree *o1 = pop(); + long v2 = !testFalse( prg, o2 ); + long v1 = !testFalse( prg, o1 ); + Word r = v1 || v2; + Tree *val = r ? prg->trueVal : prg->falseVal; + treeUpref( val ); + push( val ); + treeDownref( prg, sp, o1 ); + treeDownref( prg, sp, o2 ); + break; + } + case IN_NOT: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_NOT" << endl; + } + #endif + + Tree *tree = (Tree*)pop(); + long r = testFalse( prg, tree ); + Tree *val = r ? prg->trueVal : prg->falseVal; + treeUpref( val ); + push( val ); + treeDownref( prg, sp, tree ); + break; + } + + case IN_ADD_INT: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_ADD_INT" << endl; + } + #endif + + Int *o2 = (Int*)pop(); + Int *o1 = (Int*)pop(); + long r = o1->value + o2->value; + Tree *tree = constructInteger( prg, r ); + treeUpref( tree ); + push( tree ); + treeDownref( prg, sp, (Tree*)o1 ); + treeDownref( prg, sp, (Tree*)o2 ); + break; + } + case IN_MULT_INT: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_MULT_INT" << endl; + } + #endif + + Int *o2 = (Int*)pop(); + Int *o1 = (Int*)pop(); + long r = o1->value * o2->value; + Tree *tree = constructInteger( prg, r ); + treeUpref( tree ); + push( tree ); + treeDownref( prg, sp, (Tree*)o1 ); + treeDownref( prg, sp, (Tree*)o2 ); + break; + } + case IN_DIV_INT: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_DIV_INT" << endl; + } + #endif + + Int *o2 = (Int*)pop(); + Int *o1 = (Int*)pop(); + long r = o1->value / o2->value; + Tree *tree = constructInteger( prg, r ); + treeUpref( tree ); + push( tree ); + treeDownref( prg, sp, (Tree*)o1 ); + treeDownref( prg, sp, (Tree*)o2 ); + break; + } + case IN_SUB_INT: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_SUB_INT" << endl; + } + #endif + + Int *o2 = (Int*)pop(); + Int *o1 = (Int*)pop(); + long r = o1->value - o2->value; + Tree *tree = constructInteger( prg, r ); + treeUpref( tree ); + push( tree ); + treeDownref( prg, sp, (Tree*)o1 ); + treeDownref( prg, sp, (Tree*)o2 ); + break; + } + case IN_DUP_TOP_OFF: { + short off; + read_half( off ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_DUP_N " << off << endl; + } + #endif + + Tree *val = top_off(off); + treeUpref( val ); + push( val ); + break; + } + case IN_DUP_TOP: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_DUP_TOP" << endl; + } + #endif + + Tree *val = top(); + treeUpref( val ); + push( val ); + break; + } + case IN_TRITER_FROM_REF: { + short field; + Half searchTypeId; + read_half( field ); + read_half( searchTypeId ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_TRITER_FROM_REF " << field << " " << searchTypeId << endl; + } + #endif + + Ref rootRef; + rootRef.kid = (Kid*)pop(); + rootRef.next = (Ref*)pop(); + void *mem = plocal(field); + initTreeIter( (TreeIter*)mem, &rootRef, searchTypeId, ptop() ); + break; + } + case IN_TRITER_DESTROY: { + short field; + read_half( field ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_TRITER_DESTROY " << field << endl; + } + #endif + + TreeIter *iter = (TreeIter*) plocal(field); + treeIterDestroy( &sp, iter ); + break; + } + case IN_REV_TRITER_FROM_REF: { + short field; + Half searchTypeId; + read_half( field ); + read_half( searchTypeId ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_REV_TRITER_FROM_REF " << field << " " << searchTypeId << endl; + } + #endif + + Ref rootRef; + rootRef.kid = (Kid*)pop(); + rootRef.next = (Ref*)pop(); + + Tree **stackRoot = ptop(); + + int children = 0; + Kid *kid = treeChild( prg, rootRef.kid->tree ); + while ( kid != 0 ) { + children++; + push( (SW) kid ); + kid = kid->next; + } + + void *mem = plocal(field); + initRevTreeIter( (RevTreeIter*)mem, &rootRef, searchTypeId, stackRoot, children ); + break; + } + case IN_REV_TRITER_DESTROY: { + short field; + read_half( field ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_REV_TRITER_DESTROY " << field << endl; + } + #endif + + RevTreeIter *iter = (RevTreeIter*) plocal(field); + long curStackSize = iter->stackRoot - ptop(); + assert( iter->stackSize == curStackSize ); + popn( iter->stackSize ); + break; + } + case IN_TREE_SEARCH: { + Word id; + read_word( id ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_TREE_SEARCH " << id << endl; + } + #endif + + Tree *tree = pop(); + Tree *res = treeSearch2( prg, tree, id ); + treeUpref( res ); + push( res ); + treeDownref( prg, sp, tree ); + break; + } + case IN_TRITER_ADVANCE: { + short field; + read_half( field ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_TRITER_ADVANCE " << field << endl; + } + #endif + + TreeIter *iter = (TreeIter*) plocal(field); + Tree *res = treeIterAdvance( prg, &sp, iter ); + treeUpref( res ); + push( res ); + break; + } + case IN_TRITER_NEXT_CHILD: { + short field; + read_half( field ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_TRITER_NEXT_CHILD " << field << endl; + } + #endif + + TreeIter *iter = (TreeIter*) plocal(field); + Tree *res = treeIterNextChild( prg, &sp, iter ); + treeUpref( res ); + push( res ); + break; + } + case IN_REV_TRITER_PREV_CHILD: { + short field; + read_half( field ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_REV_TRITER_PREV_CHILD " << field << endl; + } + #endif + + RevTreeIter *iter = (RevTreeIter*) plocal(field); + Tree *res = treeRevIterPrevChild( prg, &sp, iter ); + treeUpref( res ); + push( res ); + break; + } + case IN_TRITER_NEXT_REPEAT: { + short field; + read_half( field ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) + cerr << "IN_TRITER_NEXT_REPEAT " << field << endl; + #endif + + TreeIter *iter = (TreeIter*) plocal(field); + Tree *res = treeIterNextRepeat( prg, &sp, iter ); + treeUpref( res ); + push( res ); + break; + } + case IN_TRITER_PREV_REPEAT: { + short field; + read_half( field ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) + cerr << "IN_TRITER_PREV_REPEAT " << field << endl; + #endif + + TreeIter *iter = (TreeIter*) plocal(field); + Tree *res = treeIterPrevRepeat( prg, &sp, iter ); + treeUpref( res ); + push( res ); + break; + } + case IN_TRITER_GET_CUR_R: { + short field; + read_half( field ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_TRITER_GET_CUR_R " << field << endl; + } + #endif + + TreeIter *iter = (TreeIter*) plocal(field); + Tree *tree = treeIterDerefCur( iter ); + treeUpref( tree ); + push( tree ); + break; + } + case IN_TRITER_GET_CUR_WC: { + short field; + read_half( field ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_TRITER_GET_CUR_WC " << field << endl; + } + #endif + + TreeIter *iter = (TreeIter*) plocal(field); + splitIterCur( &sp, prg, iter ); + Tree *tree = treeIterDerefCur( iter ); + treeUpref( tree ); + push( tree ); + break; + } + case IN_TRITER_SET_CUR_WC: { + short field; + read_half( field ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_TRITER_SET_CUR_WC " << field << endl; + } + #endif + + Tree *tree = pop(); + TreeIter *iter = (TreeIter*) plocal(field); + splitIterCur( &sp, prg, iter ); + Tree *old = treeIterDerefCur( iter ); + setTriterCur( iter, tree ); + treeDownref( prg, sp, old ); + break; + } + case IN_MATCH: { + Half patternId; + read_half( patternId ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_MATCH " << patternId << endl; + } + #endif + + Tree *tree = pop(); + + /* Run the match, push the result. */ + int rootNode = prg->rtd->patReplInfo[patternId].offset; + + /* Bindings are indexed starting at 1. Zero bindId to represent no + * binding. We make a space for it here rather than do math at + * access them. */ + long numBindings = prg->rtd->patReplInfo[patternId].numBindings; + Tree *bindings[1+numBindings]; + memset( bindings, 0, sizeof(Tree*)*(1+numBindings) ); + + Kid kid; + kid.tree = tree; + kid.next = 0; + int matched = matchPattern( bindings, prg, rootNode, &kid, false ); + + if ( !matched ) + memset( bindings, 0, sizeof(Tree*)*(1+numBindings) ); + else { + int b; + for ( b = 1; b <= numBindings; b++ ) + assert( bindings[b] != 0 ); + } + + #ifdef COLM_LOG_MATCH + if ( colm_log_match ) { + cerr << "match result: " << matched << endl; + } + #endif + + Tree *result = matched ? tree : 0; + treeUpref( result ); + push( result ? tree : 0 ); + int b; + for ( b = 1; b <= numBindings; b++ ) { + treeUpref( bindings[b] ); + push( bindings[b] ); + } + + treeDownref( prg, sp, tree ); + break; + } + + case IN_GET_ACCUM_CTX_R: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_GET_ACCUM_CTX_R" << endl; + } + #endif + + Tree *obj = pop(); + Tree *ctx = ((Accum*)obj)->pdaRun->context; + treeUpref( ctx ); + push( ctx ); + treeDownref( prg, sp, obj ); + break; + } + + case IN_SET_ACCUM_CTX_WC: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_SET_ACCUM_CTX_WC" << endl; + } + #endif + + Tree *obj = pop(); + Tree *val = pop(); + parserSetContext( sp, prg, (Accum*)obj, val ); + treeDownref( prg, sp, obj ); + //treeDownref( prg, sp, val ); + break; + } + +// case IN_GET_ACCUM_CTX_WC: +// case IN_GET_ACCUM_CTX_WV: +// case IN_SET_ACCUM_CTX_WC: +// case IN_SET_ACCUM_CTX_WV: +// break; + + case IN_EXTRACT_INPUT_WC: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_EXTRACT_INPUT_WC " << endl; + } + #endif + + Tree *accum = pop(); + Tree *input = extractInput( prg, (Accum*)accum ); + treeUpref( input ); + push( input ); + treeDownref( prg, sp, accum ); + break; + } + + case IN_EXTRACT_INPUT_WV: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_EXTRACT_INPUT_WV " << endl; + } + #endif + + Tree *accum = pop(); + Tree *input = extractInput( prg, (Accum*)accum ); + treeUpref( input ); + push( input ); + treeDownref( prg, sp, accum ); +// +// append( exec->reverseCode, IN_EXTRACT_INPUT_BKT ); +// exec->rcodeUnitLen += SIZEOF_CODE; + break; + } + + case IN_EXTRACT_INPUT_BKT: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) + cerr << "IN_EXTRACT_INPUT_BKT" << endl; + #endif + break; + } + + case IN_SET_INPUT_WC: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_SET_INPUT_WC " << endl; + } + #endif + + Tree *accum = pop(); + Tree *input = pop(); + setInput( prg, sp, (Accum*)accum, (Stream*)input ); + treeDownref( prg, sp, accum ); + treeDownref( prg, sp, input ); + break; + } + + case IN_STREAM_APPEND_WC: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_STREAM_APPEND_WC " << endl; + } + #endif + + Tree *stream = pop(); + Tree *input = pop(); + streamAppend( sp, prg, input, (Stream*)stream ); + + treeDownref( prg, sp, input ); + push( stream ); + break; + } + case IN_STREAM_APPEND_WV: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_STREAM_APPEND_WV " << endl; + } + #endif + + Tree *stream = pop(); + Tree *input = pop(); + Word len = streamAppend( sp, prg, input, (Stream*)stream ); + + treeUpref( stream ); + push( stream ); + + append( exec->reverseCode, IN_STREAM_APPEND_BKT ); + appendWord( exec->reverseCode, (Word) stream ); + appendWord( exec->reverseCode, (Word) input ); + appendWord( exec->reverseCode, (Word) len ); + append( exec->reverseCode, SIZEOF_CODE + 3 * SIZEOF_WORD ); + break; + } + case IN_STREAM_APPEND_BKT: { + Tree *stream; + Tree *input; + Word len; + read_tree( stream ); + read_tree( input ); + read_word( len ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_STREAM_APPEND_BKT" << endl; + } + #endif + + undoStreamAppend( prg, sp, ((Stream*)stream)->in, len ); + treeDownref( prg, sp, stream ); + treeDownref( prg, sp, input ); + break; + } + + case IN_PARSE_FRAG_WC: { + Half stopId; + read_half( stopId ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) + cerr << "IN_PARSE_FRAG_WC " << endl; + #endif + + Tree *accum = pop(); + Tree *stream = pop(); + + parseStream( sp, prg, stream, (Accum*)accum, stopId ); + + treeDownref( prg, sp, stream ); + treeDownref( prg, sp, accum ); + break; + } + + case IN_PARSE_FRAG_WV: { + Half stopId; + read_half( stopId ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_PARSE_FRAG_WV " << endl; + } + #endif + + Tree *accum = pop(); + Tree *stream = pop(); + + long consumed = ((Accum*)accum)->pdaRun->consumed; + parseStream( sp, prg, stream, (Accum*)accum, stopId ); + + //treeDownref( prg, sp, stream ); + //treeDownref( prg, sp, accum ); + + append( exec->reverseCode, IN_PARSE_FRAG_BKT ); + appendWord( exec->reverseCode, (Word) accum ); + appendWord( exec->reverseCode, (Word) stream ); + appendWord( exec->reverseCode, consumed ); + append( exec->reverseCode, SIZEOF_CODE + 3 * SIZEOF_WORD ); + break; + } + + case IN_PARSE_FRAG_BKT: { + Tree *accum; + Tree *input; + long consumed; + read_tree( accum ); + read_tree( input ); + read_word( consumed ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) + cerr << "IN_PARSE_FRAG_BKT " << consumed << endl; + #endif + + undoParseStream( sp, prg, (Stream*)input, (Accum*)accum, consumed ); + + treeDownref( prg, sp, accum ); + treeDownref( prg, sp, input ); + break; + } + + case IN_PARSE_FINISH_WC: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_PARSE_FINISH_WC " << endl; + } + #endif + + Tree *accum = pop(); + Tree *result = parseFinish( sp, prg, (Accum*)accum, false ); + push( result ); + treeDownref( prg, sp, accum ); + break; + } + case IN_PARSE_FINISH_WV: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_PARSE_FINISH_WV " << endl; + } + #endif + + Tree *accum = pop(); + long consumed = ((Accum*)accum)->pdaRun->consumed; + Tree *result = parseFinish( sp, prg, (Accum*)accum, true ); + push( result ); + + treeUpref( result ); + append( exec->reverseCode, IN_PARSE_FINISH_BKT ); + appendWord( exec->reverseCode, (Word) accum ); + appendWord( exec->reverseCode, (Word) result ); + appendWord( exec->reverseCode, (Word) consumed ); + append( exec->reverseCode, SIZEOF_CODE + 3*SIZEOF_WORD ); + break; + } + case IN_PARSE_FINISH_BKT: { + Tree *parser; + Tree *tree; + Word consumed; + + read_tree( parser ); + read_tree( tree ); + read_word( consumed ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) + cerr << "IN_PARSE_FINISH_BKT " << consumed << endl; + #endif + + undoParseStream( sp, prg, ((Accum*)parser)->stream, (Accum*)parser, consumed ); + ((Accum*)parser)->stream->in->eof = false; + + /* This needs an implementation. */ + treeDownref( prg, sp, parser ); + treeDownref( prg, sp, tree ); + break; + } + case IN_STREAM_PULL: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_STREAM_PULL" << endl; + } + #endif + Tree *stream = pop(); + Tree *len = pop(); + Tree *string = streamPull2( prg, exec->fsmRun, (Stream*)stream, len ); + treeUpref( string ); + push( string ); + + /* Single unit. */ + treeUpref( string ); + append( exec->reverseCode, IN_STREAM_PULL_BKT ); + appendWord( exec->reverseCode, (Word) string ); + exec->rcodeUnitLen += SIZEOF_CODE + SIZEOF_WORD; + append( exec->reverseCode, exec->rcodeUnitLen ); + + treeDownref( prg, sp, stream ); + treeDownref( prg, sp, len ); + break; + } + case IN_STREAM_PULL_BKT: { + Tree *string; + read_tree( string ); + + Tree *stream = pop(); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_STREAM_PULL_BKT" << endl; + } + #endif + + undoPull( prg, exec->fsmRun, (Stream*)stream, string ); + treeDownref( prg, sp, stream ); + treeDownref( prg, sp, string ); + break; + } + case IN_STREAM_PUSH_WV: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_STREAM_PUSH_WV" << endl; + } + #endif + Tree *stream = pop(); + Tree *tree = pop(); + Word len = streamPush( prg, sp, ((Stream*)stream), tree, false ); + push( 0 ); + + /* Single unit. */ + append( exec->reverseCode, IN_STREAM_PUSH_BKT ); + appendWord( exec->reverseCode, len ); + exec->rcodeUnitLen += SIZEOF_CODE + SIZEOF_WORD; + append( exec->reverseCode, exec->rcodeUnitLen ); + + treeDownref( prg, sp, stream ); + treeDownref( prg, sp, tree ); + break; + } + case IN_STREAM_PUSH_IGNORE_WV: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_STREAM_PUSH_IGNORE_WV" << endl; + } + #endif + Tree *stream = pop(); + Tree *tree = pop(); + Word len = streamPush( prg, sp, ((Stream*)stream), tree, true ); + push( 0 ); + + /* Single unit. */ + append( exec->reverseCode, IN_STREAM_PUSH_BKT ); + appendWord( exec->reverseCode, len ); + exec->rcodeUnitLen += SIZEOF_CODE + SIZEOF_WORD; + append( exec->reverseCode, exec->rcodeUnitLen ); + + treeDownref( prg, sp, stream ); + treeDownref( prg, sp, tree ); + break; + } + case IN_STREAM_PUSH_BKT: { + Word len; + read_word( len ); + + Tree *stream = pop(); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_STREAM_PUSH_BKT" << endl; + } + #endif + + undoStreamPush( prg, sp, ((Stream*)stream)->in, len ); + treeDownref( prg, sp, stream ); + break; + } + case IN_CONSTRUCT: { + Half patternId; + read_half( patternId ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_CONSTRUCT " << patternId << endl; + } + #endif + + int rootNode = prg->rtd->patReplInfo[patternId].offset; + + /* Note that bindIds are indexed at one. Add one spot for them. */ + int numBindings = prg->rtd->patReplInfo[patternId].numBindings; + Tree *bindings[1+numBindings]; + + int b; + for ( b = 1; b <= numBindings; b++ ) { + bindings[b] = pop(); + assert( bindings[b] != 0 ); + } + + Tree *replTree = 0; + PatReplNode *nodes = prg->rtd->patReplNodes; + LangElInfo *lelInfo = prg->rtd->lelInfo; + long genericId = lelInfo[nodes[rootNode].id].genericId; + if ( genericId > 0 ) { + replTree = createGeneric( prg, genericId ); + treeUpref( replTree ); + } + else { + replTree = constructReplacementTree( bindings, + prg, rootNode ); + } + + push( replTree ); + break; + } + case IN_CONSTRUCT_TERM: { + Half tokenId; + read_half( tokenId ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_CONSTRUCT_TERM " << tokenId << endl; + } + #endif + + /* Pop the string we are constructing the token from. */ + Str *str = (Str*)pop(); + Tree *res = constructTerm( prg, tokenId, str->value ); + treeUpref( res ); + push( res ); + break; + } + case IN_MAKE_TOKEN: { + uchar nargs; + read_byte( nargs ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_MAKE_TOKEN " << (ulong) nargs << endl; + } + #endif + + Tree *result = makeToken2( sp, prg, nargs ); + long i; + for ( i = 0; i < nargs; i++ ) { + Tree *arg = pop(); + treeDownref( prg, sp, arg ); + } + push( result ); + break; + } + case IN_MAKE_TREE: { + uchar nargs; + read_byte( nargs ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_MAKE_TREE " << (ulong) nargs << endl; + } + #endif + + Tree *result = makeTree( sp, prg, nargs ); + long i; + for ( i = 0; i < nargs; i++ ) { + Tree *arg = pop(); + treeDownref( prg, sp, arg ); + } + push( result ); + break; + } + case IN_TREE_NEW: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_TREE_NEW " << endl; + } + #endif + + Tree *tree = pop(); + Tree *res = constructPointer( prg, tree ); + treeUpref( res ); + push( res ); + break; + } + case IN_PTR_DEREF_R: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_PTR_DEREF_R" << endl; + } + #endif + + Pointer *ptr = (Pointer*)pop(); + treeDownref( prg, sp, (Tree*)ptr ); + + Tree *dval = getPtrVal( ptr ); + treeUpref( dval ); + push( dval ); + break; + } + case IN_PTR_DEREF_WC: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_PTR_DEREF_WC" << endl; + } + #endif + + Pointer *ptr = (Pointer*)pop(); + treeDownref( prg, sp, (Tree*)ptr ); + + Tree *dval = getPtrValSplit( prg, ptr ); + treeUpref( dval ); + push( dval ); + break; + } + case IN_PTR_DEREF_WV: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_PTR_DEREF_WV" << endl; + } + #endif + + Pointer *ptr = (Pointer*)pop(); + /* Don't downref the pointer since it is going into the reverse + * instruction. */ + + Tree *dval = getPtrValSplit( prg, ptr ); + treeUpref( dval ); + push( dval ); + + /* This is an initial global load. Need to reverse execute it. */ + append( exec->reverseCode, IN_PTR_DEREF_BKT ); + appendWord( exec->reverseCode, (Word) ptr ); + exec->rcodeUnitLen = SIZEOF_CODE + SIZEOF_WORD; + break; + } + case IN_PTR_DEREF_BKT: { + Word p; + read_word( p ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_PTR_DEREF_BKT" << endl; + } + #endif + + Pointer *ptr = (Pointer*)p; + + Tree *dval = getPtrValSplit( prg, ptr ); + treeUpref( dval ); + push( dval ); + + treeDownref( prg, sp, (Tree*)ptr ); + break; + } + case IN_REF_FROM_LOCAL: { + short int field; + read_half( field ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_REF_FROM_LOCAL " << field << endl; + } + #endif + + /* First push the null next pointer, then the kid pointer. */ + Tree **ptr = plocal(field); + push( 0 ); + push( (SW)ptr ); + break; + } + case IN_REF_FROM_REF: { + short int field; + read_half( field ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_REF_FROM_REF " << field << endl; + } + #endif + + Ref *ref = (Ref*)plocal(field); + push( (SW)ref ); + push( (SW)ref->kid ); + break; + } + case IN_REF_FROM_QUAL_REF: { + short int back; + short int field; + read_half( back ); + read_half( field ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_REF_FROM_QUAL_REF " << back << " " << field << endl; + } + #endif + + Ref *ref = (Ref*)(sp + back); + + Tree *obj = ref->kid->tree; + Kid *attr_kid = getFieldKid( obj, field ); + + push( (SW)ref ); + push( (SW)attr_kid ); + break; + } + case IN_TRITER_REF_FROM_CUR: { + short int field; + read_half( field ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_TRITER_REF_FROM_CUR " << field << endl; + } + #endif + + /* Push the next pointer first, then the kid. */ + TreeIter *iter = (TreeIter*) plocal(field); + push( (SW)&iter->ref ); + push( (SW)iter->ref.kid ); + break; + } + case IN_UITER_REF_FROM_CUR: { + short int field; + read_half( field ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_UITER_REF_FROM_CUR " << field << endl; + } + #endif + + /* Push the next pointer first, then the kid. */ + UserIter *uiter = (UserIter*) local(field); + push( (SW)uiter->ref.next ); + push( (SW)uiter->ref.kid ); + break; + } + case IN_GET_TOKEN_DATA_R: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_GET_TOKEN_DATA_R" << endl; + } + #endif + + Tree *tree = (Tree*) pop(); + Head *data = stringCopy( prg, tree->tokdata ); + Tree *str = constructString( prg, data ); + treeUpref( str ); + push( str ); + treeDownref( prg, sp, tree ); + break; + } + case IN_SET_TOKEN_DATA_WC: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_SET_TOKEN_DATA_WC" << endl; + } + #endif + + Tree *tree = pop(); + Tree *val = pop(); + Head *head = stringCopy( prg, ((Str*)val)->value ); + stringFree( prg, tree->tokdata ); + tree->tokdata = head; + + treeDownref( prg, sp, tree ); + treeDownref( prg, sp, val ); + break; + } + case IN_SET_TOKEN_DATA_WV: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_SET_TOKEN_DATA_WV" << endl; + } + #endif + + Tree *tree = pop(); + Tree *val = pop(); + + Head *oldval = tree->tokdata; + Head *head = stringCopy( prg, ((Str*)val)->value ); + tree->tokdata = head; + + /* Set up reverse code. Needs no args. */ + append( exec->reverseCode, IN_SET_TOKEN_DATA_BKT ); + appendWord( exec->reverseCode, (Word)oldval ); + exec->rcodeUnitLen += SIZEOF_CODE + SIZEOF_WORD; + append( exec->reverseCode, exec->rcodeUnitLen ); + + treeDownref( prg, sp, tree ); + treeDownref( prg, sp, val ); + break; + } + case IN_SET_TOKEN_DATA_BKT: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_SET_TOKEN_DATA_BKT " << endl; + } + #endif + + Word oldval; + read_word( oldval ); + + Tree *tree = pop(); + Head *head = (Head*)oldval; + stringFree( prg, tree->tokdata ); + tree->tokdata = head; + treeDownref( prg, sp, tree ); + break; + } + case IN_GET_TOKEN_POS_R: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_GET_TOKEN_POS_R" << endl; + } + #endif + + Tree *tree = (Tree*) pop(); + Tree *integer = 0; + if ( tree->tokdata->location ) { + integer = constructInteger( prg, tree->tokdata->location->byte ); + treeUpref( integer ); + } + push( integer ); + treeDownref( prg, sp, tree ); + break; + } + case IN_GET_MATCH_LENGTH_R: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_GET_MATCH_LENGTH_R" << endl; + } + #endif + Tree *integer = constructInteger( prg, stringLength(exec->matchText) ); + treeUpref( integer ); + push( integer ); + break; + } + case IN_GET_MATCH_TEXT_R: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_GET_MATCH_TEXT_R" << endl; + } + #endif + Head *s = stringCopy( prg, exec->matchText ); + Tree *tree = constructString( prg, s ); + treeUpref( tree ); + push( tree ); + break; + } + case IN_LIST_LENGTH: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_LIST_LENGTH" << endl; + } + #endif + + List *list = (List*) pop(); + long len = listLength( list ); + Tree *res = constructInteger( prg, len ); + treeUpref( res ); + push( res ); + break; + } + case IN_LIST_APPEND_WV: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_LIST_APPEND_WV" << endl; + } + #endif + + Tree *obj = pop(); + Tree *val = pop(); + + treeDownref( prg, sp, obj ); + + listAppend2( prg, (List*)obj, val ); + treeUpref( prg->trueVal ); + push( prg->trueVal ); + + /* Set up reverse code. Needs no args. */ + append( exec->reverseCode, IN_LIST_APPEND_BKT ); + exec->rcodeUnitLen += SIZEOF_CODE; + append( exec->reverseCode, exec->rcodeUnitLen ); + /* FLUSH */ + break; + } + case IN_LIST_APPEND_WC: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_LIST_APPEND_WC" << endl; + } + #endif + + Tree *obj = pop(); + Tree *val = pop(); + + treeDownref( prg, sp, obj ); + + listAppend2( prg, (List*)obj, val ); + treeUpref( prg->trueVal ); + push( prg->trueVal ); + break; + } + case IN_LIST_APPEND_BKT: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_LIST_APPEND_BKT" << endl; + } + #endif + + Tree *obj = pop(); + treeDownref( prg, sp, obj ); + + Tree *tree = listRemoveEnd( prg, (List*)obj ); + treeDownref( prg, sp, tree ); + break; + } + case IN_LIST_REMOVE_END_WC: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_LIST_REMOVE_END_WC" << endl; + } + #endif + + Tree *obj = pop(); + treeDownref( prg, sp, obj ); + + Tree *end = listRemoveEnd( prg, (List*)obj ); + push( end ); + break; + } + case IN_LIST_REMOVE_END_WV: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_LIST_REMOVE_END_WV" << endl; + } + #endif + + Tree *obj = pop(); + treeDownref( prg, sp, obj ); + + Tree *end = listRemoveEnd( prg, (List*)obj ); + push( end ); + + /* Set up reverse. The result comes off the list downrefed. + * Need it up referenced for the reverse code too. */ + treeUpref( end ); + append( exec->reverseCode, IN_LIST_REMOVE_END_BKT ); + appendWord( exec->reverseCode, (Word)end ); + exec->rcodeUnitLen += SIZEOF_CODE + SIZEOF_WORD; + append( exec->reverseCode, exec->rcodeUnitLen ); + /* FLUSH */ + break; + } + case IN_LIST_REMOVE_END_BKT: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_LIST_REMOVE_END_BKT" << endl; + } + #endif + + Tree *val; + read_tree( val ); + + Tree *obj = pop(); + treeDownref( prg, sp, obj ); + + listAppend2( prg, (List*)obj, val ); + break; + } + case IN_GET_LIST_MEM_R: { + short field; + read_half( field ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_GET_LIST_MEM_R " << field << endl; + } + #endif + + Tree *obj = pop(); + treeDownref( prg, sp, obj ); + + Tree *val = getListMem( (List*)obj, field ); + treeUpref( val ); + push( val ); + break; + } + case IN_GET_LIST_MEM_WC: { + short field; + read_half( field ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_GET_LIST_MEM_WC " << field << endl; + } + #endif + + Tree *obj = pop(); + treeDownref( prg, sp, obj ); + + Tree *val = getListMemSplit( prg, (List*)obj, field ); + treeUpref( val ); + push( val ); + break; + } + case IN_GET_LIST_MEM_WV: { + short field; + read_half( field ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_GET_LIST_MEM_WV " << field << endl; + } + #endif + + Tree *obj = pop(); + treeDownref( prg, sp, obj ); + + Tree *val = getListMemSplit( prg, (List*)obj, field ); + treeUpref( val ); + push( val ); + + /* Set up the reverse instruction. */ + append( exec->reverseCode, IN_GET_LIST_MEM_BKT ); + appendHalf( exec->reverseCode, field ); + exec->rcodeUnitLen += SIZEOF_CODE + SIZEOF_HALF; + break; + } + case IN_GET_LIST_MEM_BKT: { + short field; + read_half( field ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_GET_LIST_MEM_BKT " << field << endl; + } + #endif + + Tree *obj = pop(); + treeDownref( prg, sp, obj ); + + Tree *res = getListMemSplit( prg, (List*)obj, field ); + treeUpref( res ); + push( res ); + break; + } + case IN_SET_LIST_MEM_WC: { + Half field; + read_half( field ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_SET_LIST_MEM_WC " << field << endl; + } + #endif + + Tree *obj = pop(); + treeDownref( prg, sp, obj ); + + Tree *val = pop(); + Tree *existing = setListMem( (List*)obj, field, val ); + treeDownref( prg, sp, existing ); + break; + } + case IN_SET_LIST_MEM_WV: { + Half field; + read_half( field ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_SET_LIST_MEM_WV " << field << endl; + } + #endif + + Tree *obj = pop(); + treeDownref( prg, sp, obj ); + + Tree *val = pop(); + Tree *existing = setListMem( (List*)obj, field, val ); + + /* Set up the reverse instruction. */ + append( exec->reverseCode, IN_SET_LIST_MEM_BKT ); + appendHalf( exec->reverseCode, field ); + appendWord( exec->reverseCode, (Word)existing ); + exec->rcodeUnitLen += SIZEOF_CODE + SIZEOF_HALF + SIZEOF_WORD; + append( exec->reverseCode, exec->rcodeUnitLen ); + /* FLUSH */ + break; + } + case IN_SET_LIST_MEM_BKT: { + Half field; + Tree *val; + read_half( field ); + read_tree( val ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_SET_LIST_MEM_BKT " << field << endl; + } + #endif + + Tree *obj = pop(); + treeDownref( prg, sp, obj ); + + Tree *undid = setListMem( (List*)obj, field, val ); + treeDownref( prg, sp, undid ); + break; + } + case IN_MAP_INSERT_WV: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_MAP_INSERT_WV" << endl; + } + #endif + + Tree *obj = pop(); + Tree *val = pop(); + Tree *key = pop(); + + treeDownref( prg, sp, obj ); + + int inserted = mapInsert( prg, (Map*)obj, key, val ); + Tree *result = inserted ? prg->trueVal : prg->falseVal; + treeUpref( result ); + push( result ); + + /* Set up the reverse instruction. If the insert fails still need + * to pop the loaded map object. Just use the reverse instruction + * since it's nice to see it in the logs. */ + + /* Need to upref key for storage in reverse code. */ + treeUpref( key ); + append( exec->reverseCode, IN_MAP_INSERT_BKT ); + append( exec->reverseCode, inserted ); + appendWord( exec->reverseCode, (Word)key ); + exec->rcodeUnitLen += SIZEOF_CODE + SIZEOF_CODE + SIZEOF_WORD; + append( exec->reverseCode, exec->rcodeUnitLen ); + + if ( ! inserted ) { + treeDownref( prg, sp, key ); + treeDownref( prg, sp, val ); + } + break; + } + case IN_MAP_INSERT_WC: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_MAP_INSERT_WC" << endl; + } + #endif + + Tree *obj = pop(); + Tree *val = pop(); + Tree *key = pop(); + + treeDownref( prg, sp, obj ); + + int inserted = mapInsert( prg, (Map*)obj, key, val ); + Tree *result = inserted ? prg->trueVal : prg->falseVal; + treeUpref( result ); + push( result ); + + if ( ! inserted ) { + treeDownref( prg, sp, key ); + treeDownref( prg, sp, val ); + } + break; + } + case IN_MAP_INSERT_BKT: { + uchar inserted; + Tree *key; + read_byte( inserted ); + read_tree( key ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_MAP_INSERT_BKT" << endl; + } + #endif + + Tree *obj = pop(); + if ( inserted ) { + Tree *val = mapUninsert( prg, (Map*)obj, key ); + treeDownref( prg, sp, key ); + treeDownref( prg, sp, val ); + } + + treeDownref( prg, sp, obj ); + treeDownref( prg, sp, key ); + break; + } + case IN_MAP_STORE_WC: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_MAP_STORE_WC" << endl; + } + #endif + + Tree *obj = pop(); + Tree *element = pop(); + Tree *key = pop(); + + Tree *existing = mapStore( prg, (Map*)obj, key, element ); + Tree *result = existing == 0 ? prg->trueVal : prg->falseVal; + treeUpref( result ); + push( result ); + + treeDownref( prg, sp, obj ); + if ( existing != 0 ) { + treeDownref( prg, sp, key ); + treeDownref( prg, sp, existing ); + } + break; + } + case IN_MAP_STORE_WV: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_MAP_STORE_WV" << endl; + } + #endif + + Tree *obj = pop(); + Tree *element = pop(); + Tree *key = pop(); + + Tree *existing = mapStore( prg, (Map*)obj, key, element ); + Tree *result = existing == 0 ? prg->trueVal : prg->falseVal; + treeUpref( result ); + push( result ); + + /* Set up the reverse instruction. */ + treeUpref( key ); + treeUpref( existing ); + append( exec->reverseCode, IN_MAP_STORE_BKT ); + appendWord( exec->reverseCode, (Word)key ); + appendWord( exec->reverseCode, (Word)existing ); + exec->rcodeUnitLen += SIZEOF_CODE + SIZEOF_WORD + SIZEOF_WORD; + append( exec->reverseCode, exec->rcodeUnitLen ); + /* FLUSH */ + + treeDownref( prg, sp, obj ); + if ( existing != 0 ) { + treeDownref( prg, sp, key ); + treeDownref( prg, sp, existing ); + } + break; + } + case IN_MAP_STORE_BKT: { + Tree *key, *val; + read_tree( key ); + read_tree( val ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_MAP_STORE_BKT" << endl; + } + #endif + + Tree *obj = pop(); + Tree *stored = mapUnstore( prg, (Map*)obj, key, val ); + + treeDownref( prg, sp, stored ); + if ( val == 0 ) + treeDownref( prg, sp, key ); + + treeDownref( prg, sp, obj ); + treeDownref( prg, sp, key ); + break; + } + case IN_MAP_REMOVE_WC: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_MAP_REMOVE_WC" << endl; + } + #endif + + Tree *obj = pop(); + Tree *key = pop(); + TreePair pair = mapRemove( prg, (Map*)obj, key ); + + push( pair.val ); + + treeDownref( prg, sp, obj ); + treeDownref( prg, sp, key ); + treeDownref( prg, sp, pair.key ); + break; + } + case IN_MAP_REMOVE_WV: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_MAP_REMOVE_WV" << endl; + } + #endif + + Tree *obj = pop(); + Tree *key = pop(); + TreePair pair = mapRemove( prg, (Map*)obj, key ); + + treeUpref( pair.val ); + push( pair.val ); + + /* Reverse instruction. */ + append( exec->reverseCode, IN_MAP_REMOVE_BKT ); + appendWord( exec->reverseCode, (Word)pair.key ); + appendWord( exec->reverseCode, (Word)pair.val ); + exec->rcodeUnitLen += SIZEOF_CODE + SIZEOF_WORD + SIZEOF_WORD; + append( exec->reverseCode, exec->rcodeUnitLen ); + + treeDownref( prg, sp, obj ); + treeDownref( prg, sp, key ); + break; + } + case IN_MAP_REMOVE_BKT: { + Tree *key, *val; + read_tree( key ); + read_tree( val ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_MAP_REMOVE_BKT" << endl; + } + #endif + + /* Either both or neither. */ + assert( ( key == 0 ) ^ ( val != 0 ) ); + + Tree *obj = pop(); + if ( key != 0 ) + mapUnremove( prg, (Map*)obj, key, val ); + + treeDownref( prg, sp, obj ); + break; + } + case IN_MAP_LENGTH: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_MAP_LENGTH" << endl; + } + #endif + + Tree *obj = pop(); + long len = mapLength( (Map*)obj ); + Tree *res = constructInteger( prg, len ); + treeUpref( res ); + push( res ); + + treeDownref( prg, sp, obj ); + break; + } + case IN_MAP_FIND: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_MAP_FIND" << endl; + } + #endif + + Tree *obj = pop(); + Tree *key = pop(); + Tree *result = mapFind( prg, (Map*)obj, key ); + treeUpref( result ); + push( result ); + + treeDownref( prg, sp, obj ); + treeDownref( prg, sp, key ); + break; + } + case IN_INIT_LOCALS: { + Half size; + read_half( size ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_INIT_LOCALS " << size << endl; + } + #endif + + exec->frame = ptop(); + pushn( size ); + memset( ptop(), 0, sizeof(Word) * size ); + break; + } + case IN_POP_LOCALS: { + Half frameId, size; + read_half( frameId ); + read_half( size ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_POP_LOCALS " << frameId << " " << size << endl; + } + #endif + + FrameInfo *fi = &prg->rtd->frameInfo[frameId]; + downrefLocalTrees( prg, sp, exec->frame, fi->trees, fi->treesLen ); + popn( size ); + break; + } + case IN_CALL_WV: { + Half funcId; + read_half( funcId ); + + FunctionInfo *fi = &prg->rtd->functionInfo[funcId]; + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_CALL_WV " << fi->name << endl; + } + #endif + + push( 0 ); /* Return value. */ + push( (SW)instr ); + push( (SW)exec->frame ); + + instr = prg->rtd->frameInfo[fi->frameId].codeWV; + exec->frame = ptop(); + break; + } + case IN_CALL_WC: { + Half funcId; + read_half( funcId ); + + FunctionInfo *fi = &prg->rtd->functionInfo[funcId]; + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_CALL_WC " << fi->name << endl; + } + #endif + + push( 0 ); /* Return value. */ + push( (SW)instr ); + push( (SW)exec->frame ); + + instr = prg->rtd->frameInfo[fi->frameId].codeWC; + exec->frame = ptop(); + break; + } + case IN_YIELD: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_YIELD" << endl; + } + #endif + + Kid *kid = (Kid*)pop(); + Ref *next = (Ref*)pop(); + UserIter *uiter = (UserIter*) plocal_iframe( IFR_AA ); + + if ( kid == 0 || kid->tree == 0 || + kid->tree->id == uiter->searchId || + uiter->searchId == prg->rtd->anyId ) + { + /* Store the yeilded value. */ + uiter->ref.kid = kid; + uiter->ref.next = next; + uiter->stackSize = uiter->stackRoot - ptop(); + uiter->resume = instr; + uiter->frame = exec->frame; + + /* Restore the instruction and frame pointer. */ + instr = (Code*) local_iframe(IFR_RIN); + exec->frame = (Tree**) local_iframe(IFR_RFR); + exec->iframe = (Tree**) local_iframe(IFR_RIF); + + /* Return the yield result on the top of the stack. */ + Tree *result = uiter->ref.kid != 0 ? prg->trueVal : prg->falseVal; + treeUpref( result ); + push( result ); + } + break; + } + case IN_UITER_CREATE_WV: { + short field; + Half funcId, searchId; + read_half( field ); + read_half( funcId ); + read_half( searchId ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_UITER_CREATE_WV " << field << " " << + funcId << " " << searchId << endl; + } + #endif + + FunctionInfo *fi = prg->rtd->functionInfo + funcId; + UserIter *uiter = uiterCreate( &sp, prg, fi, searchId ); + local(field) = (SW) uiter; + + /* This is a setup similar to as a call, only the frame structure + * is slightly different for user iterators. We aren't going to do + * the call. We don't need to set up the return ip because the + * uiter advance will set it. The frame we need to do because it + * is set once for the lifetime of the iterator. */ + push( 0 ); /* Return instruction pointer, */ + push( (SW)exec->iframe ); /* Return iframe. */ + push( (SW)exec->frame ); /* Return frame. */ + + uiterInit( prg, sp, uiter, fi, true ); + break; + } + case IN_UITER_CREATE_WC: { + short field; + Half funcId, searchId; + read_half( field ); + read_half( funcId ); + read_half( searchId ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_UITER_CREATE_WC " << field << " " << + funcId << " " << searchId << endl; + } + #endif + + FunctionInfo *fi = prg->rtd->functionInfo + funcId; + UserIter *uiter = uiterCreate( &sp, prg, fi, searchId ); + local(field) = (SW) uiter; + + /* This is a setup similar to as a call, only the frame structure + * is slightly different for user iterators. We aren't going to do + * the call. We don't need to set up the return ip because the + * uiter advance will set it. The frame we need to do because it + * is set once for the lifetime of the iterator. */ + push( 0 ); /* Return instruction pointer, */ + push( (SW)exec->iframe ); /* Return iframe. */ + push( (SW)exec->frame ); /* Return frame. */ + + uiterInit( prg, sp, uiter, fi, false ); + break; + } + case IN_UITER_DESTROY: { + short field; + read_half( field ); + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_UITER_DESTROY " << field << endl; + } + #endif + + UserIter *uiter = (UserIter*) local(field); + userIterDestroy( &sp, uiter ); + break; + } + case IN_RET: { + Half funcId; + read_half( funcId ); + + FunctionInfo *fui = &prg->rtd->functionInfo[funcId]; + + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_RET " << fui->name << endl; + } + #endif + + FrameInfo *fi = &prg->rtd->frameInfo[fui->frameId]; + downrefLocalTrees( prg, sp, exec->frame, fi->trees, fi->treesLen ); + + popn( fui->frameSize ); + exec->frame = (Tree**) pop(); + instr = (Code*) pop(); + Tree *retVal = pop(); + popn( fui->argSize ); + push( retVal ); + break; + } + case IN_TO_UPPER: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_TO_UPPER" << endl; + } + #endif + Tree *in = pop(); + Head *head = stringToUpper( in->tokdata ); + Tree *upper = constructString( prg, head ); + treeUpref( upper ); + push( upper ); + treeDownref( prg, sp, in ); + break; + } + case IN_TO_LOWER: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_TO_LOWER" << endl; + } + #endif + Tree *in = pop(); + Head *head = stringToLower( in->tokdata ); + Tree *lower = constructString( prg, head ); + treeUpref( lower ); + push( lower ); + treeDownref( prg, sp, in ); + break; + } + case IN_EXIT: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_EXIT" << endl; + } + #endif + + Int *status = (Int*)pop(); + exit( status->value ); + break; + } + case IN_OPEN_FILE: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_OPEN_FILE" << endl; + } + #endif + + Tree *mode = pop(); + Tree *name = pop(); + Tree *res = (Tree*)openFile( prg, name, mode ); + treeUpref( res ); + push( res ); + treeDownref( prg, sp, name ); + treeDownref( prg, sp, mode ); + break; + } + case IN_GET_STDIN: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_GET_STDIN" << endl; + } + #endif + + /* Pop the root object. */ + Tree *obj = pop(); + treeDownref( prg, sp, obj ); + if ( prg->stdinVal == 0 ) { + prg->stdinVal = openStreamFd( prg, 0 ); + treeUpref( (Tree*)prg->stdinVal ); + } + + treeUpref( (Tree*)prg->stdinVal ); + push( (Tree*)prg->stdinVal ); + break; + } + case IN_LOAD_ARGV: { + Half field; + read_half( field ); + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_LOAD_ARGV " << field << endl; + } + #endif + + /* Tree comes back upreffed. */ + Tree *tree = constructArgv( prg, prg->argc, prg->argv ); + setField( prg, prg->global, field, tree ); + break; + } + case IN_STOP: { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "IN_STOP" << endl; + } + #endif + + fflush( stdout ); + goto out; + } + + /* Halt is a default instruction given by the compiler when it is + * asked to generate and instruction it doesn't have. It is deliberate + * and can represent "not implemented" or "compiler error" because a + * variable holding instructions was not properly initialize. */ + case IN_HALT: { + fatal( "IN_HALT -- compiler did something wrong\n" ); + exit(1); + break; + } + default: { + fatal( "UNKNOWN INSTRUCTION: -- something is wrong\n" ); + assert(false); + break; + } + } + goto again; + +out: + assert( sp == root ); +} + +void parseError( InputStream *inputStream, FsmRun *fsmRun, PdaRun *pdaRun, int tokId, Tree *tree ) +{ + fprintf( stderr, "error: %ld:\n", inputStream->line ); +// cerr << "error:" << inputStream->line << ": at token "; +// if ( tokId < 128 ) +// cerr << "\"" << pdaRun->tables->rtd->lelInfo[tokId].name << "\""; +//// else +// cerr << pdaRun->tables->rtd->lelInfo[tokId].name; +// if ( stringLength( tree->tokdata ) > 0 ) { +// cerr << " with data \""; +// cerr.write( stringData( tree->tokdata ), +// stringLength( tree->tokdata ) ); +// cerr << "\""; +// } +// cerr << ": "; +} diff --git a/colm/bytecode.cpp b/colm/bytecode.cpp deleted file mode 100644 index 9ec10703..00000000 --- a/colm/bytecode.cpp +++ /dev/null @@ -1,4166 +0,0 @@ -/* - * Copyright 2007-2010 Adrian Thurston - */ - -/* This file is part of Colm. - * - * Colm is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * Colm is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Colm; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "bytecode.h" -#include "pdarun.h" -#include "fsmrun.h" -#include "pdarun.h" - -using std::cout; -using std::cerr; -using std::endl; -using std::ostringstream; -using std::string; -using std::hex; - -exit_object endp; - -void operator<<( ostream &out, exit_object & ) -{ - out << endl; - exit(1); -} - - -#define push(i) (*(--sp) = (i)) -#define pop() (*sp++) -#define top() (*sp) -#define top_off(n) (sp[n]) -#define ptop() (sp) -#define popn(n) (sp += (n)) -#define pushn(n) (sp -= (n)) -#define local(o) (exec->frame[o]) -#define plocal(o) (&exec->frame[o]) -#define local_iframe(o) (exec->iframe[o]) -#define plocal_iframe(o) (&exec->iframe[o]) - -#define read_byte( i ) do { \ - i = ((uchar) *instr++); \ -} while(0) - -#define read_word_p( i, p ) do { \ - i = ((Word) p[0]); \ - i |= ((Word) p[1]) << 8; \ - i |= ((Word) p[2]) << 16; \ - i |= ((Word) p[3]) << 24; \ -} while(0) - -/* There are better ways. */ -#if SIZEOF_LONG == 4 - #define read_word( i ) do { \ - i = ((Word) *instr++); \ - i |= ((Word) *instr++) << 8; \ - i |= ((Word) *instr++) << 16; \ - i |= ((Word) *instr++) << 24; \ - } while(0) -#else - #define read_word( i ) do { \ - i = ((Word) *instr++); \ - i |= ((Word) *instr++) << 8; \ - i |= ((Word) *instr++) << 16; \ - i |= ((Word) *instr++) << 24; \ - i |= ((Word) *instr++) << 32; \ - i |= ((Word) *instr++) << 40; \ - i |= ((Word) *instr++) << 48; \ - i |= ((Word) *instr++) << 56; \ - } while(0) -#endif - -/* There are better ways. */ -#if SIZEOF_LONG == 4 - #define read_tree( i ) do { \ - Word w; \ - w = ((Word) *instr++); \ - w |= ((Word) *instr++) << 8; \ - w |= ((Word) *instr++) << 16; \ - w |= ((Word) *instr++) << 24; \ - i = (Tree*) w; \ - } while(0) -#else - #define read_tree( i ) do { \ - Word w; \ - w = ((Word) *instr++); \ - w |= ((Word) *instr++) << 8; \ - w |= ((Word) *instr++) << 16; \ - w |= ((Word) *instr++) << 24; \ - w |= ((Word) *instr++) << 32; \ - w |= ((Word) *instr++) << 40; \ - w |= ((Word) *instr++) << 48; \ - w |= ((Word) *instr++) << 56; \ - i = (Tree*) w; \ - } while(0) -#endif - -#define read_half( i ) do { \ - i = ((Word) *instr++); \ - i |= ((Word) *instr++) << 8; \ -} while(0) - -int colm_log_bytecode = 0; -int colm_log_parse = 0; -int colm_log_match = 0; -int colm_log_compile = 0; -int colm_log_conds = 0; - -Tree *prepParseTree( Program *prg, Tree **sp, Tree *tree ) -{ - /* Seems like we need to always copy here. If it isn't a parse tree it - * needs to be made into one. If it is then we need to make a new one in - * case the old one is still in use by some parsing routine. The case were - * we might be able to avoid a copy would be that it's a parse tree - * already, but it's owning parser is completely finished with it. */ - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "copying tree in send function" << endl; - } - #endif - Kid *unused = 0; - tree = copyRealTree( prg, tree, 0, &unused, true ); - return tree; -} - -void sendTreeFrag( Program *prg, Tree **sp, PdaRun *pdaRun, FsmRun *fsmRun, - InputStream *inputStream, - Tree *tree, bool ignore ) -{ - tree = prepParseTree( prg, sp, tree ); - - if ( tree->id >= prg->rtd->firstNonTermId ) - tree->id = prg->rtd->lelInfo[tree->id].termDupId; - - tree->flags |= AF_ARTIFICIAL; - - treeUpref( tree ); - - /* FIXME: Do we need to remove the ignore tokens - * at this point? Will it cause a leak? */ - - Kid *send = kidAllocate( prg ); - send->tree = tree; - - LangElInfo *lelInfo = pdaRun->prg->rtd->lelInfo; - - /* Must clear next, since the parsing algorithm uses it. */ - if ( lelInfo[send->tree->id].ignore ) { - #ifdef COLM_LOG_PARSE - if ( colm_log_parse ) { - cerr << "ignoring queued item: " << - pdaRun->tables->rtd->lelInfo[send->tree->id].name << endl; - } - #endif - - incrementConsumed( pdaRun ); - - ::ignore( pdaRun, send->tree ); - kidFree( pdaRun->prg, send ); - } - else { - #ifdef COLM_LOG_PARSE - if ( colm_log_parse ) { - cerr << "sending queue item: " << - pdaRun->tables->rtd->lelInfo[send->tree->id].name << endl; - } - #endif - - incrementConsumed( pdaRun ); - - sendHandleError( sp, pdaRun, fsmRun, inputStream, send ); - } -} - -void parserSetContext( Tree **&sp, Program *prg, Accum *accum, Tree *val ) -{ - accum->pdaRun->context = splitTree( prg, val ); -} - -Head *treeToStr( Tree **sp, Program *prg, Tree *tree ) -{ - /* Collect the tree data. */ - StrCollect collect; - initStrCollect( &collect ); - - printTree( &collect, sp, prg, tree ); - - /* Set up the input stream. */ - Head *ret = stringAllocFull( prg, collect.data, collect.length ); - - strCollectDestroy( &collect ); - - return ret; -} - -Tree *extractInput( Program *prg, Accum *accum ) -{ - if ( accum->stream == 0 ) { - Stream *res = (Stream*)mapElAllocate( prg ); - res->id = LEL_ID_STREAM; - res->in = newInputStreamAccum(); - treeUpref( (Tree*)res ); - accum->stream = res; - } - - return (Tree*)accum->stream; -} - -void setInput( Program *prg, Tree **sp, Accum *accum, Stream *stream ) -{ - if ( accum->stream != 0 ) - treeDownref( prg, sp, (Tree*)accum->stream ); - - accum->stream = stream; - treeUpref( (Tree*)accum->stream ); -} - -void parseStream( Tree **&sp, Program *prg, Tree *input, Accum *accum, long stopId ) -{ - accum->pdaRun->stopTarget = stopId; - - Stream *stream = (Stream*)input; - accum->fsmRun->curStream = input; - parseLoop( sp, accum->pdaRun, accum->fsmRun, stream->in ); -} - -Word streamAppend( Tree **&sp, Program *prg, Tree *input, Stream *stream ) -{ - if ( input->id == LEL_ID_STR ) { - //assert(false); - /* Collect the tree data. */ - StrCollect collect; - initStrCollect( &collect ); - printTree( &collect, sp, prg, input ); - - /* Load it into the input. */ - stream->in->funcs->appendData( stream->in, collect.data, collect.length ); - - long length = collect.length; - strCollectDestroy( &collect ); - - return length; - } - else { - input = prepParseTree( prg, sp, input ); - - if ( input->id >= prg->rtd->firstNonTermId ) - input->id = prg->rtd->lelInfo[input->id].termDupId; - - input->flags |= AF_ARTIFICIAL; - - treeUpref( input ); - stream->in->funcs->appendTree( stream->in, input ); - return 0; - } -} - -void parseFrag( Tree **&sp, Program *prg, Tree *input, Accum *accum, long stopId ) -{ - accum->pdaRun->stopTarget = stopId; - Stream *stream = (Stream*) extractInput( prg, accum ); - - if ( input->id == LEL_ID_STR ) { - //assert(false); - /* Collect the tree data. */ - StrCollect collect; - initStrCollect( &collect ); - printTree( &collect, sp, prg, input ); - - /* Load it into the input. */ - stream->in->funcs->appendData( stream->in, collect.data, collect.length ); - - /* Parse. */ - parseLoop( sp, accum->pdaRun, accum->fsmRun, stream->in ); - - strCollectDestroy( &collect ); - } - else { - //assert(false); - /* Cause a flush */ - - input = prepParseTree( prg, sp, input ); - - if ( input->id >= prg->rtd->firstNonTermId ) - input->id = prg->rtd->lelInfo[input->id].termDupId; - - input->flags |= AF_ARTIFICIAL; - - treeUpref( input ); - stream->in->funcs->appendTree( stream->in, input ); - - parseLoop( sp, accum->pdaRun, accum->fsmRun, stream->in ); - -// stream->in->flush = true; -// parseLoop( sp, accum->pdaRun, accum->fsmRun, stream->in ); - -// sendTreeFrag( prg, sp, accum->pdaRun, accum->fsmRun, stream->in, input, false ); - } -} - -void undoParseStream( Tree **&sp, Program *prg, Stream *input, Accum *accum, long consumed ) -{ - if ( consumed < accum->pdaRun->consumed ) { - accum->pdaRun->numRetry += 1; - accum->pdaRun->targetConsumed = consumed; - parseToken( sp, accum->pdaRun, accum->fsmRun, input->in, 0 ); - accum->pdaRun->targetConsumed = -1; - accum->pdaRun->numRetry -= 1; - - accum->fsmRun->region = pdaRunGetNextRegion( accum->pdaRun, 0 ); - accum->fsmRun->cs = accum->fsmRun->tables->entryByRegion[accum->fsmRun->region]; - } -} - -Tree *parseFinish( Tree **&sp, Program *prg, Accum *accum, bool revertOn ) -{ - Stream *stream = (Stream*)extractInput( prg, accum ); - - if ( accum->pdaRun->stopTarget > 0 ) { - - } - else { - stream->in->eof = true; - stream->in->later = false; - parseLoop( sp, accum->pdaRun, accum->fsmRun, stream->in ); - } - - if ( !revertOn ) - commitFull( sp, accum->pdaRun, 0 ); - - Tree *tree = getParsedRoot( accum->pdaRun, accum->pdaRun->stopTarget > 0 ); - treeUpref( tree ); - - if ( !revertOn ) - cleanParser( sp, accum->pdaRun ); - - /* Indicate that this tree came out of a parser. */ - tree->flags |= AF_PARSED; - - return tree; -} - -Tree *streamPull( Program *prg, FsmRun *fsmRun, Stream *stream, Tree *length ) -{ - long len = ((Int*)length)->value; - Head *tokdata = streamPull( prg, fsmRun, stream->in, len ); - return constructString( prg, tokdata ); -} - - -void undoPull( Program *prg, FsmRun *fsmRun, Stream *stream, Tree *str ) -{ - const char *data = stringData( ( (Str*)str )->value ); - long length = stringLength( ( (Str*)str )->value ); - undoStreamPull( fsmRun, stream->in, data, length ); -} - -Word streamPush( Program *prg, Tree **&sp, Stream *stream, Tree *tree, bool ignore ) -{ - if ( tree->id == LEL_ID_STR ) { - /* This should become a compile error. If it's text, it's up to the - * scanner to decide. Want to force it then send a token. */ - assert( !ignore ); - - /* Collect the tree data. */ - StrCollect collect; - initStrCollect( &collect ); - printTree( &collect, sp, prg, tree ); - - streamPushText( stream->in, collect.data, collect.length ); - long length = collect.length; - strCollectDestroy( &collect ); - - return length; - } - else { - tree = prepParseTree( prg, sp, tree ); - - if ( tree->id >= prg->rtd->firstNonTermId ) - tree->id = prg->rtd->lelInfo[tree->id].termDupId; - - tree->flags |= AF_ARTIFICIAL; - treeUpref( tree ); - streamPushTree( stream->in, tree, ignore ); - return 0; - } -} - -void setLocal( Tree **frame, long field, Tree *tree ) -{ - if ( tree != 0 ) - assert( tree->refs >= 1 ); - frame[field] = tree; -} - -Tree *getLocalSplit( Program *prg, Tree **frame, long field ) -{ - Tree *val = frame[field]; - Tree *split = splitTree( prg, val ); - frame[field] = split; - return split; -} - -void downrefLocalTrees( Program *prg, Tree **sp, Tree **frame, char *trees, long treesLen ) -{ - for ( long i = 0; i < treesLen; i++ ) { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "local tree downref: " << (long)trees[i] << endl; - } - #endif - - treeDownref( prg, sp, frame[((long)trees[i])] ); - } -} - -UserIter *uiterCreate( Tree **&sp, Program *prg, FunctionInfo *fi, long searchId ) -{ - pushn( sizeof(UserIter) / sizeof(Word) ); - void *mem = ptop(); - - UserIter *uiter = new(mem) UserIter; - initUserIter( uiter, ptop(), fi->argSize, searchId ); - return uiter; -} - -void uiterInit( Program *prg, Tree **sp, UserIter *uiter, - FunctionInfo *fi, bool revertOn ) -{ - /* Set up the first yeild so when we resume it starts at the beginning. */ - uiter->ref.kid = 0; - uiter->stackSize = uiter->stackRoot - ptop(); - uiter->frame = &uiter->stackRoot[-IFR_AA]; - - if ( revertOn ) - uiter->resume = prg->rtd->frameInfo[fi->frameId].codeWV; - else - uiter->resume = prg->rtd->frameInfo[fi->frameId].codeWC; -} - -void treeIterDestroy( Tree **&sp, TreeIter *iter ) -{ - long curStackSize = iter->stackRoot - ptop(); - assert( iter->stackSize == curStackSize ); - popn( iter->stackSize ); -} - -void userIterDestroy( Tree **&sp, UserIter *uiter ) -{ - /* We should always be coming from a yield. The current stack size will be - * nonzero and the stack size in the iterator will be correct. */ - long curStackSize = uiter->stackRoot - ptop(); - assert( uiter->stackSize == curStackSize ); - - long argSize = uiter->argSize; - - popn( uiter->stackRoot - ptop() ); - popn( sizeof(UserIter) / sizeof(Word) ); - popn( argSize ); -} - -Tree *constructArgv( Program *prg, int argc, char **argv ) -{ - Tree *list = createGeneric( prg, 1 ); - treeUpref( list ); - for ( int i = 0; i < argc; i++ ) { - Head *head = stringAllocPointer( prg, argv[i], strlen(argv[i]) ); - Tree *arg = constructString( prg, head ); - treeUpref( arg ); - listAppend2( prg, (List*)list, arg ); - } - return list; -} - - -/* - * Execution environment - */ - -void initProgram( Program *prg, int argc, char **argv, int ctxDepParsing, - RuntimeData *rtd ) -{ - prg->argc = argc; - prg->argv = argv; - prg->ctxDepParsing = ctxDepParsing; - prg->rtd = rtd; - prg->global = 0; - prg->heap = 0; - prg->stdinVal = 0; - prg->stdoutVal = 0; - prg->stderrVal = 0; - - initPoolAlloc( &prg->kidPool, sizeof(Kid) ); - initPoolAlloc( &prg->treePool, sizeof(Tree) ); - initPoolAlloc( &prg->parseTreePool, sizeof(ParseTree) ); - initPoolAlloc( &prg->listElPool, sizeof(ListEl) ); - initPoolAlloc( &prg->mapElPool, sizeof(MapEl) ); - initPoolAlloc( &prg->headPool, sizeof(Head) ); - initPoolAlloc( &prg->locationPool, sizeof(Location) ); - - Int *trueInt = (Int*) treeAllocate( prg ); - trueInt->id = LEL_ID_BOOL; - trueInt->refs = 1; - trueInt->value = 1; - - Int *falseInt = (Int*) treeAllocate( prg ); - falseInt->id = LEL_ID_BOOL; - falseInt->refs = 1; - falseInt->value = 0; - - prg->trueVal = (Tree*)trueInt; - prg->falseVal = (Tree*)falseInt; -} - -void clearGlobal( Program *prg, Tree **sp ) -{ - /* Downref all the fields in the global object. */ - for ( int g = 0; g < prg->rtd->globalSize; g++ ) { - //assert( getAttr( global, g )->refs == 1 ); - treeDownref( prg, sp, getAttr( prg->global, g ) ); - } - - /* Free the global object. */ - if ( prg->rtd->globalSize > 0 ) - freeAttrs( prg, prg->global->child ); - treeFree( prg, prg->global ); -} - -void clearProgram( Program *prg, Tree **vm_stack, Tree **sp ) -{ - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "clearing the prg" << endl; - } - #endif - - clearGlobal( prg, sp ); - - /* Clear the heap. */ - Kid *a = prg->heap; - while ( a != 0 ) { - Kid *next = a->next; - treeDownref( prg, sp, a->tree ); - kidFree( prg, a ); - a = next; - } - - //assert( trueVal->refs == 1 ); - //assert( falseVal->refs == 1 ); - treeDownref( prg, sp, prg->trueVal ); - treeDownref( prg, sp, prg->falseVal ); - - treeDownref( prg, sp, (Tree*)prg->stdinVal ); - treeDownref( prg, sp, (Tree*)prg->stdoutVal ); - treeDownref( prg, sp, (Tree*)prg->stderrVal ); - - long kidLost = kidNumLost( prg ); - if ( kidLost ) - cerr << "warning: lost kids: " << kidLost << endl; - - long treeLost = treeNumLost( prg ); - if ( treeLost ) - cerr << "warning: lost trees: " << treeLost << endl; - - long parseTreeLost = parseTreeNumLost( prg ); - if ( parseTreeLost ) - cerr << "warning: lost parse trees: " << parseTreeLost << endl; - - long listLost = listElNumLost( prg ); - if ( listLost ) - cerr << "warning: lost listEls: " << listLost << endl; - - long mapLost = mapElNumLost( prg ); - if ( mapLost ) - cerr << "warning: lost mapEls: " << mapLost << endl; - - long headLost = headNumLost( prg ); - if ( headLost ) - cerr << "warning: lost heads: " << headLost << endl; - - long locationLost = locationNumLost( prg ); - if ( locationLost ) - cerr << "warning: lost locations: " << locationLost << endl; - - kidClear( prg ); - treeClear( prg ); - parseTreeClear( prg ); - listElClear( prg ); - mapElClear( prg ); - locationClear( prg ); - - //exec->reverseCode->empty(); - //memset( vm_stack, 0, sizeof(Tree*) * VM_STACK_SIZE); -} - -void allocGlobal( Program *prg ) -{ - /* Alloc the global. */ - Tree *tree = treeAllocate( prg ); - tree->child = allocAttrs( prg, prg->rtd->globalSize ); - tree->refs = 1; - prg->global = tree; -} - -Tree **stackAlloc() -{ - //return new Tree*[VM_STACK_SIZE]; - - return (Tree**)mmap( 0, sizeof(Tree*)*VM_STACK_SIZE, - PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0 ); -} - -void runProgram( Program *prg ) -{ - assert( sizeof(Int) <= sizeof(Tree) ); - assert( sizeof(Str) <= sizeof(Tree) ); - assert( sizeof(Pointer) <= sizeof(Tree) ); - assert( sizeof(Map) <= sizeof(MapEl) ); - assert( sizeof(List) <= sizeof(MapEl) ); - assert( sizeof(Stream) <= sizeof(MapEl) ); - assert( sizeof(Accum) <= sizeof(MapEl) ); - - /* Allocate the global variable. */ - allocGlobal( prg ); - - /* - * Allocate the VM stack. - */ - - Tree **vm_stack = stackAlloc(); - Tree **root = &vm_stack[VM_STACK_SIZE]; - - /* - * Execute - */ - - if ( prg->rtd->rootCodeLen > 0 ) { - RtCodeVect reverseCode; - Execution execution; - initRtCodeVect( &reverseCode ); - initExecution( &execution, prg, &reverseCode, 0, 0, prg->rtd->rootCode, 0, 0, 0, 0 ); - execute( &execution, root ); - - /* Pull out the reverse code and free it. */ - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "freeing the root reverse code" << endl; - } - #endif - - /* The root code should all be commit code and reverseCode - * should be empty. */ - assert( reverseCode.tabLen == 0 ); - } - - /* Clear */ - clearProgram( prg, vm_stack, root ); -} - -void initExecution( Execution *exec, Program *prg, RtCodeVect *reverseCode, - PdaRun *pdaRun, FsmRun *fsmRun, Code *code, Tree *lhs, - long genId, Head *matchText, char **captures ) -{ - exec->prg = prg; - exec->pdaRun = pdaRun; - exec->fsmRun = fsmRun; - exec->code = code; - exec->frame = 0; - exec->iframe = 0; - exec->lhs = lhs; - exec->parsed = 0; - exec->genId = genId; - exec->matchText = matchText; - exec->reject = false; - exec->reverseCode = reverseCode; - exec->rcodeUnitLen = 0; - exec->captures = captures; - - assert( lhs == 0 || lhs->refs == 1 ); -} - -void rcodeDownrefAll( Program *prg, Tree **sp, RtCodeVect *rev ) -{ - while ( rev->tabLen > 0 ) { - /* Read the length */ - Code *prcode = rev->data + rev->tabLen - SIZEOF_WORD; - Word len; - read_word_p( len, prcode ); - - /* Find the start of block. */ - long start = rev->tabLen - len - SIZEOF_WORD; - prcode = rev->data + start; - - /* Execute it. */ - rcodeDownref( prg, sp, prcode ); - - /* Backup over it. */ - rev->tabLen -= len + SIZEOF_WORD; - } -} - -void rcodeDownref( Program *prg, Tree **sp, Code *instr ) -{ -again: - switch ( *instr++ ) { - case IN_RESTORE_LHS: { - Tree *lhs; - read_tree( lhs ); - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_RESTORE_LHS" << endl; - } - #endif - treeDownref( prg, sp, lhs ); - break; - } - - case IN_EXTRACT_INPUT_BKT: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) - cerr << "IN_EXTRACT_INPUT_BKT" << endl; - #endif - break; - } - case IN_STREAM_APPEND_BKT: { - Tree *stream; - Tree *input; - Word len; - read_tree( stream ); - read_tree( input ); - read_word( len ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_STREAM_APPEND_BKT" << endl; - } - #endif - - treeDownref( prg, sp, stream ); - treeDownref( prg, sp, input ); - break; - } - case IN_PARSE_FRAG_BKT: { - Tree *accum; - Tree *input; - long consumed; - read_tree( accum ); - read_tree( input ); - read_word( consumed ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) - cerr << "IN_PARSE_FRAG_BKT " << consumed << endl; - #endif - - treeDownref( prg, sp, accum ); - treeDownref( prg, sp, input ); - break; - } - case IN_PARSE_FINISH_BKT: { - Tree *accumTree; - Tree *tree; - long consumed; - - read_tree( accumTree ); - read_tree( tree ); - read_word( consumed ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_PARSE_FINISH_BKT " << consumed << endl; - } - #endif - - treeDownref( prg, sp, accumTree ); - treeDownref( prg, sp, tree ); - break; - } - case IN_STREAM_PULL_BKT: { - Tree *string; - read_tree( string ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_STREAM_PULL_BKT" << endl; - } - #endif - - treeDownref( prg, sp, string ); - break; - } - case IN_STREAM_PUSH_BKT: { - Word len; - read_word( len ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_STREAM_PUSH_BKT" << endl; - } - #endif - break; - } - case IN_LOAD_GLOBAL_BKT: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_LOAD_GLOBAL_BKT" << endl; - } - #endif - break; - } - case IN_LOAD_CONTEXT_BKT: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_LOAD_CONTEXT_BKT" << endl; - } - #endif - break; - } - case IN_LOAD_INPUT_BKT: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_LOAD_INPUT_BKT" << endl; - } - #endif - break; - } - case IN_GET_FIELD_BKT: { - short field; - read_half( field ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_GET_FIELD_BKT " << field << endl; - } - #endif - break; - } - case IN_SET_FIELD_BKT: { - short field; - Tree *val; - read_half( field ); - read_tree( val ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_SET_FIELD_BKT " << field << endl; - } - #endif - - treeDownref( prg, sp, val ); - break; - } - case IN_PTR_DEREF_BKT: { - Tree *ptr; - read_tree( ptr ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_PTR_DEREF_BKT" << endl; - } - #endif - - treeDownref( prg, sp, ptr ); - break; - } - case IN_SET_TOKEN_DATA_BKT: { - Word oldval; - read_word( oldval ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_SET_TOKEN_DATA_BKT " << endl; - } - #endif - - Head *head = (Head*)oldval; - stringFree( prg, head ); - break; - } - case IN_LIST_APPEND_BKT: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_LIST_APPEND_BKT" << endl; - } - #endif - break; - } - case IN_LIST_REMOVE_END_BKT: { - Tree *val; - read_tree( val ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_LIST_REMOVE_END_BKT" << endl; - } - #endif - - treeDownref( prg, sp, val ); - break; - } - case IN_GET_LIST_MEM_BKT: { - short field; - read_half( field ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_GET_LIST_MEM_BKT " << field << endl; - } - #endif - break; - } - case IN_SET_LIST_MEM_BKT: { - Half field; - Tree *val; - read_half( field ); - read_tree( val ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_SET_LIST_MEM_BKT " << field << endl; - } - #endif - - treeDownref( prg, sp, val ); - break; - } - case IN_MAP_INSERT_BKT: { - uchar inserted; - Tree *key; - read_byte( inserted ); - read_tree( key ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_MAP_INSERT_BKT" << endl; - } - #endif - - treeDownref( prg, sp, key ); - break; - } - case IN_MAP_STORE_BKT: { - Tree *key, *val; - read_tree( key ); - read_tree( val ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_MAP_STORE_BKT" << endl; - } - #endif - - treeDownref( prg, sp, key ); - treeDownref( prg, sp, val ); - break; - } - case IN_MAP_REMOVE_BKT: { - Tree *key, *val; - read_tree( key ); - read_tree( val ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_MAP_REMOVE_BKT" << endl; - } - #endif - - treeDownref( prg, sp, key ); - treeDownref( prg, sp, val ); - break; - } - case IN_STOP: { - return; - } - default: { - cerr << "UNKNOWN INSTRUCTION: 0x" << hex << (ulong)instr[-1] << - " -- reverse code downref" << endl; - assert(false); - break; - } - } - goto again; -} - -void execute( Execution *exec, Tree **sp ) -{ - /* If we have a lhs push it to the stack. */ - bool haveLhs = exec->lhs != 0; - if ( haveLhs ) - push( exec->lhs ); - - /* Execution loop. */ - executeCode( exec, sp, exec->code ); - - /* Take the lhs off the stack. */ - if ( haveLhs ) - exec->lhs = (Tree*) pop(); -} - -int makeReverseCode( RtCodeVect *all, RtCodeVect *reverseCode ) -{ - /* Do we need to revert the left hand side? */ - - /* Check if there was anything generated. */ - if ( reverseCode->tabLen == 0 ) - return false; - - long prevAllLength = all->tabLen; - - /* Go backwards, group by group, through the reverse code. Push each group - * to the global reverse code stack. */ - Code *p = reverseCode->data + reverseCode->tabLen; - while ( p != reverseCode->data ) { - p--; - long len = *p; - p = p - len; - append2( all, p, len ); - } - - /* Stop, then place a total length in the global stack. */ - append( all, IN_STOP ); - long length = all->tabLen - prevAllLength; - appendWord( all, length ); - - /* Clear the revere code buffer. */ - reverseCode->tabLen = 0; - - return true; -} - -void rexecute( Execution *exec, Tree **root, RtCodeVect *allRev ) -{ - /* Read the length */ - Code *prcode = allRev->data + allRev->tabLen - SIZEOF_WORD; - Word len; - read_word_p( len, prcode ); - - /* Find the start of block. */ - long start = allRev->tabLen - len - SIZEOF_WORD; - prcode = allRev->data + start; - - /* Execute it. */ - Tree **sp = root; - executeCode( exec, sp, prcode ); - assert( sp == root ); - - /* Backup over it. */ - allRev->tabLen -= len + SIZEOF_WORD; -} - -void executeCode( Execution *exec, Tree **sp, Code *instr ) -{ - /* When we exit we are going to verify that we did not eat up any stack - * space. */ - Tree **root = sp; - Program *prg = exec->prg; - -again: - switch ( *instr++ ) { - case IN_SAVE_LHS: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_SAVE_LHS" << endl; - } - #endif - - assert( exec->lhs != 0 ); - - /* Save and upref before writing. We don't generate a restore - * here. Instead, in the parser we will check if it actually - * changed and insert the instruction then. The presence of this - * instruction here is just a conservative approximation. */ - exec->parsed = exec->lhs; - //treeUpref( parsed ); - break; - } - case IN_RESTORE_LHS: { - Tree *restore; - read_tree( restore ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_RESTORE_LHS" << endl; - } - #endif - assert( exec->lhs == 0 ); - exec->lhs = restore; - break; - } - case IN_LOAD_NIL: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_LOAD_NIL" << endl; - } - #endif - - push( 0 ); - break; - } - case IN_LOAD_TRUE: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_LOAD_TRUE" << endl; - } - #endif - - treeUpref( prg->trueVal ); - push( prg->trueVal ); - break; - } - case IN_LOAD_FALSE: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_LOAD_FALSE" << endl; - } - #endif - - treeUpref( prg->falseVal ); - push( prg->falseVal ); - break; - } - case IN_LOAD_INT: { - Word i; - read_word( i ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_LOAD_INT " << i << endl; - } - #endif - - Tree *tree = constructInteger( prg, i ); - treeUpref( tree ); - push( tree ); - break; - } - case IN_LOAD_STR: { - Word offset; - read_word( offset ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_LOAD_STR " << offset << endl; - } - #endif - - Head *lit = makeLiteral( prg, offset ); - Tree *tree = constructString( prg, lit ); - treeUpref( tree ); - push( tree ); - break; - } - case IN_PRINT: { - int n; - read_byte( n ); - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_PRINT " << n << endl; - } - #endif - - while ( n-- > 0 ) { - Tree *tree = pop(); - printTree2( stdout, sp, prg, tree ); - treeDownref( prg, sp, tree ); - } - break; - } - case IN_PRINT_XML_AC: { - int n; - read_byte( n ); - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_PRINT_XML_AC" << n << endl; - } - #endif - - while ( n-- > 0 ) { - Tree *tree = pop(); - printXmlTree( sp, prg, tree, true ); - treeDownref( prg, sp, tree ); - } - break; - } - case IN_PRINT_XML: { - int n; - read_byte( n ); - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_PRINT_XML" << n << endl; - } - #endif - - while ( n-- > 0 ) { - Tree *tree = pop(); - printXmlTree( sp, prg, tree, false ); - treeDownref( prg, sp, tree ); - } - break; - } - case IN_PRINT_STREAM: { - int n; - read_byte( n ); - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_PRINT_STREAM" << n << endl; - } - #endif - - Stream *stream = (Stream*)pop(); - while ( n-- > 0 ) { - Tree *tree = pop(); - printTree2( stream->file, sp, prg, tree ); - treeDownref( prg, sp, tree ); - } - treeDownref( prg, sp, (Tree*)stream ); - break; - } - case IN_LOAD_CONTEXT_R: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_LOAD_CONTEXT_R" << endl; - } - #endif - - treeUpref( exec->pdaRun->context ); - push( exec->pdaRun->context ); - break; - } - case IN_LOAD_CONTEXT_WV: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_LOAD_CONTEXT_WV" << endl; - } - #endif - - treeUpref( exec->pdaRun->context ); - push( exec->pdaRun->context ); - - /* Set up the reverse instruction. */ - append( exec->reverseCode, IN_LOAD_CONTEXT_BKT ); - exec->rcodeUnitLen = SIZEOF_CODE; - break; - } - case IN_LOAD_CONTEXT_WC: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_LOAD_CONTEXT_WC" << endl; - } - #endif - - /* This is identical to the _R version, but using it for writing - * would be confusing. */ - treeUpref( exec->pdaRun->context ); - push( exec->pdaRun->context ); - break; - } - case IN_LOAD_CONTEXT_BKT: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_LOAD_CONTEXT_BKT" << endl; - } - #endif - - treeUpref( exec->pdaRun->context ); - push( exec->pdaRun->context ); - break; - } - case IN_LOAD_GLOBAL_R: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_LOAD_GLOBAL_R" << endl; - } - #endif - - treeUpref( prg->global ); - push( prg->global ); - break; - } - case IN_LOAD_GLOBAL_WV: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_LOAD_GLOBAL_WV" << endl; - } - #endif - - treeUpref( prg->global ); - push( prg->global ); - - /* Set up the reverse instruction. */ - append( exec->reverseCode, IN_LOAD_GLOBAL_BKT ); - exec->rcodeUnitLen = SIZEOF_CODE; - break; - } - case IN_LOAD_GLOBAL_WC: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_LOAD_GLOBAL_WC" << endl; - } - #endif - - /* This is identical to the _R version, but using it for writing - * would be confusing. */ - treeUpref( prg->global ); - push( prg->global ); - break; - } - case IN_LOAD_GLOBAL_BKT: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_LOAD_GLOBAL_BKT" << endl; - } - #endif - - treeUpref( prg->global ); - push( prg->global ); - break; - } - case IN_LOAD_INPUT_R: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_LOAD_INPUT_R" << endl; - } - #endif - - treeUpref( exec->fsmRun->curStream ); - push( exec->fsmRun->curStream ); - break; - } - case IN_LOAD_INPUT_WV: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_LOAD_INPUT_WV" << endl; - } - #endif - - treeUpref( exec->fsmRun->curStream ); - push( exec->fsmRun->curStream ); - - /* Set up the reverse instruction. */ - append( exec->reverseCode, IN_LOAD_INPUT_BKT ); - exec->rcodeUnitLen = SIZEOF_CODE; - break; - } - case IN_LOAD_INPUT_WC: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_LOAD_INPUT_WC" << endl; - } - #endif - - /* This is identical to the _R version, but using it for writing - * would be confusing. */ - treeUpref( exec->fsmRun->curStream ); - push( exec->fsmRun->curStream ); - break; - } - case IN_LOAD_INPUT_BKT: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_LOAD_INPUT_BKT" << endl; - } - #endif - - treeUpref( exec->fsmRun->curStream ); - push( exec->fsmRun->curStream ); - break; - } - case IN_LOAD_CTX_R: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_LOAD_CTX_R" << endl; - } - #endif - - treeUpref( exec->pdaRun->context ); - push( exec->pdaRun->context ); - break; - } - case IN_LOAD_CTX_WV: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_LOAD_CTX_WV" << endl; - } - #endif - - treeUpref( exec->pdaRun->context ); - push( exec->pdaRun->context ); - - /* Set up the reverse instruction. */ - append( exec->reverseCode, IN_LOAD_INPUT_BKT ); - exec->rcodeUnitLen = SIZEOF_CODE; - break; - } - case IN_LOAD_CTX_WC: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_LOAD_CTX_WC" << endl; - } - #endif - - /* This is identical to the _R version, but using it for writing - * would be confusing. */ - treeUpref( exec->pdaRun->context ); - push( exec->pdaRun->context ); - break; - } - case IN_LOAD_CTX_BKT: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_LOAD_CTX_BKT" << endl; - } - #endif - - treeUpref( exec->pdaRun->context ); - push( exec->pdaRun->context ); - break; - } - case IN_INIT_CAPTURES: { - uchar ncaps; - read_byte( ncaps ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_INIT_CAPTURES " << ncaps << endl; - } - #endif - - /* If there are captures (this is a translate block) then copy them into - * the local frame now. */ - LangElInfo *lelInfo = prg->rtd->lelInfo; - char **mark = exec->captures; - - for ( int i = 0; i < lelInfo[exec->genId].numCaptureAttr; i++ ) { - CaptureAttr *ca = &prg->rtd->captureAttr[lelInfo[exec->genId].captureAttr + i]; - Head *data = stringAllocFull( prg, - mark[ca->mark_enter], mark[ca->mark_leave] - mark[ca->mark_enter] ); - Tree *string = constructString( prg, data ); - treeUpref( string ); - setLocal( exec->frame, -1 - i, string ); - } - break; - } - case IN_INIT_RHS_EL: { - Half position; - short field; - read_half( position ); - read_half( field ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_INIT_RHS_EL " << position << " " << field << endl; - } - #endif - - Tree *val = getRhsEl( prg, exec->lhs, position ); - treeUpref( val ); - local(field) = val; - break; - } - case IN_UITER_ADVANCE: { - short field; - read_half( field ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_UITER_ADVANCE " << field << endl; - } - #endif - - /* Get the iterator. */ - UserIter *uiter = (UserIter*) local(field); - - long stackSize = uiter->stackRoot - ptop(); - assert( uiter->stackSize == stackSize ); - - /* Fix the return instruction pointer. */ - uiter->stackRoot[-IFR_AA + IFR_RIN] = (SW)instr; - - instr = uiter->resume; - exec->frame = uiter->frame; - exec->iframe = &uiter->stackRoot[-IFR_AA]; - break; - } - case IN_UITER_GET_CUR_R: { - short field; - read_half( field ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_UITER_GET_CUR_R " << field << endl; - } - #endif - - UserIter *uiter = (UserIter*) local(field); - Tree *val = uiter->ref.kid->tree; - treeUpref( val ); - push( val ); - break; - } - case IN_UITER_GET_CUR_WC: { - short field; - read_half( field ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_UITER_GET_CUR_WC " << field << endl; - } - #endif - - UserIter *uiter = (UserIter*) local(field); - splitRef( &sp, prg, &uiter->ref ); - Tree *split = uiter->ref.kid->tree; - treeUpref( split ); - push( split ); - break; - } - case IN_UITER_SET_CUR_WC: { - short field; - read_half( field ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_UITER_SET_CUR_WC " << field << endl; - } - #endif - - Tree *t = pop(); - UserIter *uiter = (UserIter*) local(field); - splitRef( &sp, prg, &uiter->ref ); - Tree *old = uiter->ref.kid->tree; - uiter->ref.kid->tree = t; - treeDownref( prg, sp, old ); - break; - } - case IN_GET_LOCAL_R: { - short field; - read_half( field ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_GET_LOCAL_R " << field << endl; - } - #endif - - Tree *val = local(field); - treeUpref( val ); - push( val ); - break; - } - case IN_GET_LOCAL_WC: { - short field; - read_half( field ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_GET_LOCAL_WC " << field << endl; - } - #endif - - Tree *split = getLocalSplit( prg, exec->frame, field ); - treeUpref( split ); - push( split ); - break; - } - case IN_SET_LOCAL_WC: { - short field; - read_half( field ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_SET_LOCAL_WC " << field << endl; - } - #endif - - Tree *val = pop(); - treeDownref( prg, sp, local(field) ); - setLocal( exec->frame, field, val ); - break; - } - case IN_SAVE_RET: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_SAVE_RET " << endl; - } - #endif - - Tree *val = pop(); - local(FR_RV) = val; - break; - } - case IN_GET_LOCAL_REF_R: { - short field; - read_half( field ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_GET_LOCAL_REF_R " << field << endl; - } - #endif - - Ref *ref = (Ref*) plocal(field); - Tree *val = ref->kid->tree; - treeUpref( val ); - push( val ); - break; - } - case IN_GET_LOCAL_REF_WC: { - short field; - read_half( field ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_GET_LOCAL_REF_WC " << field << endl; - } - #endif - - Ref *ref = (Ref*) plocal(field); - splitRef( &sp, prg, ref ); - Tree *val = ref->kid->tree; - treeUpref( val ); - push( val ); - break; - } - case IN_SET_LOCAL_REF_WC: { - short field; - read_half( field ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_SET_LOCAL_REF_WC " << field << endl; - } - #endif - - Tree *val = pop(); - Ref *ref = (Ref*) plocal(field); - splitRef( &sp, prg, ref ); - refSetValue( ref, val ); - break; - } - case IN_GET_FIELD_R: { - short field; - read_half( field ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_GET_FIELD_R " << field << endl; - } - #endif - - Tree *obj = pop(); - treeDownref( prg, sp, obj ); - - Tree *val = getField( obj, field ); - treeUpref( val ); - push( val ); - break; - } - case IN_GET_FIELD_WC: { - short field; - read_half( field ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_GET_FIELD_WC " << field << endl; - } - #endif - - Tree *obj = pop(); - treeDownref( prg, sp, obj ); - - Tree *split = getFieldSplit( prg, obj, field ); - treeUpref( split ); - push( split ); - break; - } - case IN_GET_FIELD_WV: { - short field; - read_half( field ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_GET_FIELD_WV " << field << endl; - } - #endif - - Tree *obj = pop(); - treeDownref( prg, sp, obj ); - - Tree *split = getFieldSplit( prg, obj, field ); - treeUpref( split ); - push( split ); - - /* Set up the reverse instruction. */ - append( exec->reverseCode, IN_GET_FIELD_BKT ); - appendHalf( exec->reverseCode, field ); - exec->rcodeUnitLen += SIZEOF_CODE + SIZEOF_HALF; - break; - } - case IN_GET_FIELD_BKT: { - short field; - read_half( field ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_GET_FIELD_BKT " << field << endl; - } - #endif - - Tree *obj = pop(); - treeDownref( prg, sp, obj ); - - Tree *split = getFieldSplit( prg, obj, field ); - treeUpref( split ); - push( split ); - break; - } - case IN_SET_FIELD_WC: { - short field; - read_half( field ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_SET_FIELD_WC " << field << endl; - } - #endif - - Tree *obj = pop(); - Tree *val = pop(); - treeDownref( prg, sp, obj ); - - /* Downref the old value. */ - Tree *prev = getField( obj, field ); - treeDownref( prg, sp, prev ); - - setField( prg, obj, field, val ); - break; - } - case IN_SET_FIELD_WV: { - short field; - read_half( field ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_SET_FIELD_WV " << field << endl; - } - #endif - - Tree *obj = pop(); - Tree *val = pop(); - treeDownref( prg, sp, obj ); - - /* Save the old value, then set the field. */ - Tree *prev = getField( obj, field ); - setField( prg, obj, field, val ); - - /* Set up the reverse instruction. */ - append( exec->reverseCode, IN_SET_FIELD_BKT ); - appendHalf( exec->reverseCode, field ); - appendWord( exec->reverseCode, (Word)prev ); - exec->rcodeUnitLen += SIZEOF_CODE + SIZEOF_HALF + SIZEOF_WORD; - append( exec->reverseCode, exec->rcodeUnitLen ); - /* FLUSH */ - break; - } - case IN_SET_FIELD_BKT: { - short field; - Tree *val; - read_half( field ); - read_tree( val ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_SET_FIELD_BKT " << field << endl; - } - #endif - - Tree *obj = pop(); - treeDownref( prg, sp, obj ); - - /* Downref the old value. */ - Tree *prev = getField( obj, field ); - treeDownref( prg, sp, prev ); - - setField( prg, obj, field, val ); - break; - } - case IN_SET_FIELD_LEAVE_WC: { - short field; - read_half( field ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_SET_FIELD_LEAVE_WC " << field << endl; - } - #endif - - /* Note that we don't downref the object here because we are - * leaving it on the stack. */ - Tree *obj = pop(); - Tree *val = pop(); - - /* Downref the old value. */ - Tree *prev = getField( obj, field ); - treeDownref( prg, sp, prev ); - - /* Set the field. */ - setField( prg, obj, field, val ); - - /* Leave the object on the top of the stack. */ - push( obj ); - break; - } - case IN_POP: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_POP" << endl; - } - #endif - - Tree *val = pop(); - treeDownref( prg, sp, val ); - break; - } - case IN_POP_N_WORDS: { - short n; - read_half( n ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_POP_N_WORDS " << n << endl; - } - #endif - - popn( n ); - break; - } - case IN_SPRINTF: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_SPRINTF" << endl; - } - #endif - - pop(); - Tree *integer = pop(); - Tree *format = pop(); - Head *res = stringSprintf( prg, (Str*)format, (Int*)integer ); - Tree *str = constructString( prg, res ); - treeUpref( str ); - push( str ); - treeDownref( prg, sp, integer ); - treeDownref( prg, sp, format ); - break; - } - case IN_STR_ATOI: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_STR_ATOI" << endl; - } - #endif - - Str *str = (Str*)pop(); - Word res = strAtoi( str->value ); - Tree *integer = constructInteger( prg, res ); - treeUpref( integer ); - push( integer ); - treeDownref( prg, sp, (Tree*)str ); - break; - } - case IN_INT_TO_STR: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_INT_TO_STR" << endl; - } - #endif - - Int *i = (Int*)pop(); - Head *res = intToStr( prg, i->value ); - Tree *str = constructString( prg, res ); - treeUpref( str ); - push( str ); - treeDownref( prg, sp, (Tree*) i ); - break; - } - case IN_TREE_TO_STR: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_TREE_TO_STR" << endl; - } - #endif - - Tree *tree = pop(); - Head *res = treeToStr( sp, prg, tree ); - Tree *str = constructString( prg, res ); - treeUpref( str ); - push( str ); - treeDownref( prg, sp, tree ); - break; - } - case IN_CONCAT_STR: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_CONCAT_STR" << endl; - } - #endif - - Str *s2 = (Str*)pop(); - Str *s1 = (Str*)pop(); - Head *res = concatStr( s1->value, s2->value ); - Tree *str = constructString( prg, res ); - treeUpref( str ); - treeDownref( prg, sp, (Tree*)s1 ); - treeDownref( prg, sp, (Tree*)s2 ); - push( str ); - break; - } - case IN_STR_UORD8: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_STR_UORD8" << endl; - } - #endif - - Str *str = (Str*)pop(); - Word res = strUord8( str->value ); - Tree *tree = constructInteger( prg, res ); - treeUpref( tree ); - push( tree ); - treeDownref( prg, sp, (Tree*)str ); - break; - } - case IN_STR_UORD16: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_STR_UORD16" << endl; - } - #endif - - Str *str = (Str*)pop(); - Word res = strUord16( str->value ); - Tree *tree = constructInteger( prg, res ); - treeUpref( tree ); - push( tree ); - treeDownref( prg, sp, (Tree*)str ); - break; - } - - case IN_STR_LENGTH: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_STR_LENGTH" << endl; - } - #endif - - Str *str = (Str*)pop(); - long len = stringLength( str->value ); - Tree *res = constructInteger( prg, len ); - treeUpref( res ); - push( res ); - treeDownref( prg, sp, (Tree*)str ); - break; - } - case IN_JMP_FALSE: { - short dist; - read_half( dist ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_JMP_FALSE " << dist << endl; - } - #endif - - Tree *tree = pop(); - if ( testFalse( prg, tree ) ) - instr += dist; - treeDownref( prg, sp, tree ); - break; - } - case IN_JMP_TRUE: { - short dist; - read_half( dist ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_JMP_TRUE " << dist << endl; - } - #endif - - Tree *tree = pop(); - if ( !testFalse( prg, tree ) ) - instr += dist; - treeDownref( prg, sp, tree ); - break; - } - case IN_JMP: { - short dist; - read_half( dist ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_JMP " << dist << endl; - } - #endif - - instr += dist; - break; - } - case IN_REJECT: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_REJECT" << endl; - } - #endif - exec->reject = true; - break; - } - - /* - * Binary comparison operators. - */ - case IN_TST_EQL: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_TST_EQL" << endl; - } - #endif - - Tree *o2 = pop(); - Tree *o1 = pop(); - long r = cmpTree( prg, o1, o2 ); - Tree *val = r ? prg->falseVal : prg->trueVal; - treeUpref( val ); - push( val ); - treeDownref( prg, sp, o1 ); - treeDownref( prg, sp, o2 ); - break; - } - case IN_TST_NOT_EQL: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_TST_NOT_EQL" << endl; - } - #endif - - Tree *o2 = pop(); - Tree *o1 = pop(); - long r = cmpTree( prg, o1, o2 ); - Tree *val = r ? prg->trueVal : prg->falseVal; - treeUpref( val ); - push( val ); - treeDownref( prg, sp, o1 ); - treeDownref( prg, sp, o2 ); - break; - } - case IN_TST_LESS: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_TST_LESS" << endl; - } - #endif - - Tree *o2 = pop(); - Tree *o1 = pop(); - long r = cmpTree( prg, o1, o2 ); - Tree *val = r < 0 ? prg->trueVal : prg->falseVal; - treeUpref( val ); - push( val ); - treeDownref( prg, sp, o1 ); - treeDownref( prg, sp, o2 ); - break; - } - case IN_TST_LESS_EQL: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_TST_LESS_EQL" << endl; - } - #endif - - Tree *o2 = pop(); - Tree *o1 = pop(); - long r = cmpTree( prg, o1, o2 ); - Tree *val = r <= 0 ? prg->trueVal : prg->falseVal; - treeUpref( val ); - push( val ); - treeDownref( prg, sp, o1 ); - treeDownref( prg, sp, o2 ); - } - case IN_TST_GRTR: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_TST_GRTR" << endl; - } - #endif - - Tree *o2 = pop(); - Tree *o1 = pop(); - long r = cmpTree( prg, o1, o2 ); - Tree *val = r > 0 ? prg->trueVal : prg->falseVal; - treeUpref( val ); - push( val ); - treeDownref( prg, sp, o1 ); - treeDownref( prg, sp, o2 ); - break; - } - case IN_TST_GRTR_EQL: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_TST_GRTR_EQL" << endl; - } - #endif - - Tree *o2 = (Tree*)pop(); - Tree *o1 = (Tree*)pop(); - long r = cmpTree( prg, o1, o2 ); - Tree *val = r >= 0 ? prg->trueVal : prg->falseVal; - treeUpref( val ); - push( val ); - treeDownref( prg, sp, o1 ); - treeDownref( prg, sp, o2 ); - break; - } - case IN_TST_LOGICAL_AND: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_TST_LOGICAL_AND" << endl; - } - #endif - - Tree *o2 = pop(); - Tree *o1 = pop(); - long v2 = !testFalse( prg, o2 ); - long v1 = !testFalse( prg, o1 ); - Word r = v1 && v2; - Tree *val = r ? prg->trueVal : prg->falseVal; - treeUpref( val ); - push( val ); - treeDownref( prg, sp, o1 ); - treeDownref( prg, sp, o2 ); - break; - } - case IN_TST_LOGICAL_OR: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_TST_LOGICAL_OR" << endl; - } - #endif - - Tree *o2 = pop(); - Tree *o1 = pop(); - long v2 = !testFalse( prg, o2 ); - long v1 = !testFalse( prg, o1 ); - Word r = v1 || v2; - Tree *val = r ? prg->trueVal : prg->falseVal; - treeUpref( val ); - push( val ); - treeDownref( prg, sp, o1 ); - treeDownref( prg, sp, o2 ); - break; - } - case IN_NOT: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_NOT" << endl; - } - #endif - - Tree *tree = (Tree*)pop(); - long r = testFalse( prg, tree ); - Tree *val = r ? prg->trueVal : prg->falseVal; - treeUpref( val ); - push( val ); - treeDownref( prg, sp, tree ); - break; - } - - case IN_ADD_INT: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_ADD_INT" << endl; - } - #endif - - Int *o2 = (Int*)pop(); - Int *o1 = (Int*)pop(); - long r = o1->value + o2->value; - Tree *tree = constructInteger( prg, r ); - treeUpref( tree ); - push( tree ); - treeDownref( prg, sp, (Tree*)o1 ); - treeDownref( prg, sp, (Tree*)o2 ); - break; - } - case IN_MULT_INT: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_MULT_INT" << endl; - } - #endif - - Int *o2 = (Int*)pop(); - Int *o1 = (Int*)pop(); - long r = o1->value * o2->value; - Tree *tree = constructInteger( prg, r ); - treeUpref( tree ); - push( tree ); - treeDownref( prg, sp, (Tree*)o1 ); - treeDownref( prg, sp, (Tree*)o2 ); - break; - } - case IN_DIV_INT: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_DIV_INT" << endl; - } - #endif - - Int *o2 = (Int*)pop(); - Int *o1 = (Int*)pop(); - long r = o1->value / o2->value; - Tree *tree = constructInteger( prg, r ); - treeUpref( tree ); - push( tree ); - treeDownref( prg, sp, (Tree*)o1 ); - treeDownref( prg, sp, (Tree*)o2 ); - break; - } - case IN_SUB_INT: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_SUB_INT" << endl; - } - #endif - - Int *o2 = (Int*)pop(); - Int *o1 = (Int*)pop(); - long r = o1->value - o2->value; - Tree *tree = constructInteger( prg, r ); - treeUpref( tree ); - push( tree ); - treeDownref( prg, sp, (Tree*)o1 ); - treeDownref( prg, sp, (Tree*)o2 ); - break; - } - case IN_DUP_TOP_OFF: { - short off; - read_half( off ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_DUP_N " << off << endl; - } - #endif - - Tree *val = top_off(off); - treeUpref( val ); - push( val ); - break; - } - case IN_DUP_TOP: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_DUP_TOP" << endl; - } - #endif - - Tree *val = top(); - treeUpref( val ); - push( val ); - break; - } - case IN_TRITER_FROM_REF: { - short field; - Half searchTypeId; - read_half( field ); - read_half( searchTypeId ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_TRITER_FROM_REF " << field << " " << searchTypeId << endl; - } - #endif - - Ref rootRef; - rootRef.kid = (Kid*)pop(); - rootRef.next = (Ref*)pop(); - void *mem = plocal(field); - initTreeIter( (TreeIter*)mem, &rootRef, searchTypeId, ptop() ); - break; - } - case IN_TRITER_DESTROY: { - short field; - read_half( field ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_TRITER_DESTROY " << field << endl; - } - #endif - - TreeIter *iter = (TreeIter*) plocal(field); - treeIterDestroy( sp, iter ); - break; - } - case IN_REV_TRITER_FROM_REF: { - short field; - Half searchTypeId; - read_half( field ); - read_half( searchTypeId ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_REV_TRITER_FROM_REF " << field << " " << searchTypeId << endl; - } - #endif - - Ref rootRef; - rootRef.kid = (Kid*)pop(); - rootRef.next = (Ref*)pop(); - - Tree **stackRoot = ptop(); - - int children = 0; - Kid *kid = treeChild( prg, rootRef.kid->tree ); - while ( kid != 0 ) { - children++; - push( (SW) kid ); - kid = kid->next; - } - - void *mem = plocal(field); - initRevTreeIter( (RevTreeIter*)mem, &rootRef, searchTypeId, stackRoot, children ); - break; - } - case IN_REV_TRITER_DESTROY: { - short field; - read_half( field ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_REV_TRITER_DESTROY " << field << endl; - } - #endif - - RevTreeIter *iter = (RevTreeIter*) plocal(field); - long curStackSize = iter->stackRoot - ptop(); - assert( iter->stackSize == curStackSize ); - popn( iter->stackSize ); - break; - } - case IN_TREE_SEARCH: { - Word id; - read_word( id ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_TREE_SEARCH " << id << endl; - } - #endif - - Tree *tree = pop(); - Tree *res = treeSearch2( prg, tree, id ); - treeUpref( res ); - push( res ); - treeDownref( prg, sp, tree ); - break; - } - case IN_TRITER_ADVANCE: { - short field; - read_half( field ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_TRITER_ADVANCE " << field << endl; - } - #endif - - TreeIter *iter = (TreeIter*) plocal(field); - Tree *res = treeIterAdvance( prg, &sp, iter ); - treeUpref( res ); - push( res ); - break; - } - case IN_TRITER_NEXT_CHILD: { - short field; - read_half( field ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_TRITER_NEXT_CHILD " << field << endl; - } - #endif - - TreeIter *iter = (TreeIter*) plocal(field); - Tree *res = treeIterNextChild( prg, &sp, iter ); - treeUpref( res ); - push( res ); - break; - } - case IN_REV_TRITER_PREV_CHILD: { - short field; - read_half( field ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_REV_TRITER_PREV_CHILD " << field << endl; - } - #endif - - RevTreeIter *iter = (RevTreeIter*) plocal(field); - Tree *res = treeRevIterPrevChild( prg, &sp, iter ); - treeUpref( res ); - push( res ); - break; - } - case IN_TRITER_NEXT_REPEAT: { - short field; - read_half( field ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) - cerr << "IN_TRITER_NEXT_REPEAT " << field << endl; - #endif - - TreeIter *iter = (TreeIter*) plocal(field); - Tree *res = treeIterNextRepeat( prg, &sp, iter ); - treeUpref( res ); - push( res ); - break; - } - case IN_TRITER_PREV_REPEAT: { - short field; - read_half( field ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) - cerr << "IN_TRITER_PREV_REPEAT " << field << endl; - #endif - - TreeIter *iter = (TreeIter*) plocal(field); - Tree *res = treeIterPrevRepeat( prg, &sp, iter ); - treeUpref( res ); - push( res ); - break; - } - case IN_TRITER_GET_CUR_R: { - short field; - read_half( field ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_TRITER_GET_CUR_R " << field << endl; - } - #endif - - TreeIter *iter = (TreeIter*) plocal(field); - Tree *tree = treeIterDerefCur( iter ); - treeUpref( tree ); - push( tree ); - break; - } - case IN_TRITER_GET_CUR_WC: { - short field; - read_half( field ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_TRITER_GET_CUR_WC " << field << endl; - } - #endif - - TreeIter *iter = (TreeIter*) plocal(field); - splitIterCur( &sp, prg, iter ); - Tree *tree = treeIterDerefCur( iter ); - treeUpref( tree ); - push( tree ); - break; - } - case IN_TRITER_SET_CUR_WC: { - short field; - read_half( field ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_TRITER_SET_CUR_WC " << field << endl; - } - #endif - - Tree *tree = pop(); - TreeIter *iter = (TreeIter*) plocal(field); - splitIterCur( &sp, prg, iter ); - Tree *old = treeIterDerefCur( iter ); - setTriterCur( iter, tree ); - treeDownref( prg, sp, old ); - break; - } - case IN_MATCH: { - Half patternId; - read_half( patternId ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_MATCH " << patternId << endl; - } - #endif - - Tree *tree = pop(); - - /* Run the match, push the result. */ - int rootNode = prg->rtd->patReplInfo[patternId].offset; - - /* Bindings are indexed starting at 1. Zero bindId to represent no - * binding. We make a space for it here rather than do math at - * access them. */ - long numBindings = prg->rtd->patReplInfo[patternId].numBindings; - Tree *bindings[1+numBindings]; - memset( bindings, 0, sizeof(Tree*)*(1+numBindings) ); - - Kid kid; - kid.tree = tree; - kid.next = 0; - bool matched = matchPattern( bindings, prg, rootNode, &kid, false ); - - if ( !matched ) - memset( bindings, 0, sizeof(Tree*)*(1+numBindings) ); - else { - for ( int b = 1; b <= numBindings; b++ ) - assert( bindings[b] != 0 ); - } - - #ifdef COLM_LOG_MATCH - if ( colm_log_match ) { - cerr << "match result: " << matched << endl; - } - #endif - - Tree *result = matched ? tree : 0; - treeUpref( result ); - push( result ? tree : 0 ); - for ( int b = 1; b <= numBindings; b++ ) { - treeUpref( bindings[b] ); - push( bindings[b] ); - } - - treeDownref( prg, sp, tree ); - break; - } - - case IN_GET_ACCUM_CTX_R: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_GET_ACCUM_CTX_R" << endl; - } - #endif - - Tree *obj = pop(); - Tree *ctx = ((Accum*)obj)->pdaRun->context; - treeUpref( ctx ); - push( ctx ); - treeDownref( prg, sp, obj ); - break; - } - - case IN_SET_ACCUM_CTX_WC: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_SET_ACCUM_CTX_WC" << endl; - } - #endif - - Tree *obj = pop(); - Tree *val = pop(); - parserSetContext( sp, prg, (Accum*)obj, val ); - treeDownref( prg, sp, obj ); - //treeDownref( prg, sp, val ); - break; - } - -// case IN_GET_ACCUM_CTX_WC: -// case IN_GET_ACCUM_CTX_WV: -// case IN_SET_ACCUM_CTX_WC: -// case IN_SET_ACCUM_CTX_WV: -// break; - - case IN_EXTRACT_INPUT_WC: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_EXTRACT_INPUT_WC " << endl; - } - #endif - - Tree *accum = pop(); - Tree *input = extractInput( prg, (Accum*)accum ); - treeUpref( input ); - push( input ); - treeDownref( prg, sp, accum ); - break; - } - - case IN_EXTRACT_INPUT_WV: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_EXTRACT_INPUT_WV " << endl; - } - #endif - - Tree *accum = pop(); - Tree *input = extractInput( prg, (Accum*)accum ); - treeUpref( input ); - push( input ); - treeDownref( prg, sp, accum ); -// -// append( exec->reverseCode, IN_EXTRACT_INPUT_BKT ); -// exec->rcodeUnitLen += SIZEOF_CODE; - break; - } - - case IN_EXTRACT_INPUT_BKT: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) - cerr << "IN_EXTRACT_INPUT_BKT" << endl; - #endif - break; - } - - case IN_SET_INPUT_WC: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_SET_INPUT_WC " << endl; - } - #endif - - Tree *accum = pop(); - Tree *input = pop(); - setInput( prg, sp, (Accum*)accum, (Stream*)input ); - treeDownref( prg, sp, accum ); - treeDownref( prg, sp, input ); - break; - } - - case IN_STREAM_APPEND_WC: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_STREAM_APPEND_WC " << endl; - } - #endif - - Tree *stream = pop(); - Tree *input = pop(); - streamAppend( sp, prg, input, (Stream*)stream ); - - treeDownref( prg, sp, input ); - push( stream ); - break; - } - case IN_STREAM_APPEND_WV: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_STREAM_APPEND_WV " << endl; - } - #endif - - Tree *stream = pop(); - Tree *input = pop(); - Word len = streamAppend( sp, prg, input, (Stream*)stream ); - - treeUpref( stream ); - push( stream ); - - append( exec->reverseCode, IN_STREAM_APPEND_BKT ); - appendWord( exec->reverseCode, (Word) stream ); - appendWord( exec->reverseCode, (Word) input ); - appendWord( exec->reverseCode, (Word) len ); - append( exec->reverseCode, SIZEOF_CODE + 3 * SIZEOF_WORD ); - break; - } - case IN_STREAM_APPEND_BKT: { - Tree *stream; - Tree *input; - Word len; - read_tree( stream ); - read_tree( input ); - read_word( len ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_STREAM_APPEND_BKT" << endl; - } - #endif - - undoStreamAppend( prg, sp, ((Stream*)stream)->in, len ); - treeDownref( prg, sp, stream ); - treeDownref( prg, sp, input ); - break; - } - - case IN_PARSE_FRAG_WC: { - Half stopId; - read_half( stopId ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) - cerr << "IN_PARSE_FRAG_WC " << endl; - #endif - - Tree *accum = pop(); - Tree *stream = pop(); - - parseStream( sp, prg, stream, (Accum*)accum, stopId ); - - treeDownref( prg, sp, stream ); - treeDownref( prg, sp, accum ); - break; - } - - case IN_PARSE_FRAG_WV: { - Half stopId; - read_half( stopId ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_PARSE_FRAG_WV " << endl; - } - #endif - - Tree *accum = pop(); - Tree *stream = pop(); - - long consumed = ((Accum*)accum)->pdaRun->consumed; - parseStream( sp, prg, stream, (Accum*)accum, stopId ); - - //treeDownref( prg, sp, stream ); - //treeDownref( prg, sp, accum ); - - append( exec->reverseCode, IN_PARSE_FRAG_BKT ); - appendWord( exec->reverseCode, (Word) accum ); - appendWord( exec->reverseCode, (Word) stream ); - appendWord( exec->reverseCode, consumed ); - append( exec->reverseCode, SIZEOF_CODE + 3 * SIZEOF_WORD ); - break; - } - - case IN_PARSE_FRAG_BKT: { - Tree *accum; - Tree *input; - long consumed; - read_tree( accum ); - read_tree( input ); - read_word( consumed ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) - cerr << "IN_PARSE_FRAG_BKT " << consumed << endl; - #endif - - undoParseStream( sp, prg, (Stream*)input, (Accum*)accum, consumed ); - - treeDownref( prg, sp, accum ); - treeDownref( prg, sp, input ); - break; - } - - case IN_PARSE_FINISH_WC: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_PARSE_FINISH_WC " << endl; - } - #endif - - Tree *accum = pop(); - Tree *result = parseFinish( sp, prg, (Accum*)accum, false ); - push( result ); - treeDownref( prg, sp, accum ); - break; - } - case IN_PARSE_FINISH_WV: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_PARSE_FINISH_WV " << endl; - } - #endif - - Tree *accum = pop(); - long consumed = ((Accum*)accum)->pdaRun->consumed; - Tree *result = parseFinish( sp, prg, (Accum*)accum, true ); - push( result ); - - treeUpref( result ); - append( exec->reverseCode, IN_PARSE_FINISH_BKT ); - appendWord( exec->reverseCode, (Word) accum ); - appendWord( exec->reverseCode, (Word) result ); - appendWord( exec->reverseCode, (Word) consumed ); - append( exec->reverseCode, SIZEOF_CODE + 3*SIZEOF_WORD ); - break; - } - case IN_PARSE_FINISH_BKT: { - Tree *parser; - Tree *tree; - Word consumed; - - read_tree( parser ); - read_tree( tree ); - read_word( consumed ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) - cerr << "IN_PARSE_FINISH_BKT " << consumed << endl; - #endif - - undoParseStream( sp, prg, ((Accum*)parser)->stream, (Accum*)parser, consumed ); - ((Accum*)parser)->stream->in->eof = false; - - /* This needs an implementation. */ - treeDownref( prg, sp, parser ); - treeDownref( prg, sp, tree ); - break; - } - case IN_STREAM_PULL: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_STREAM_PULL" << endl; - } - #endif - Tree *stream = pop(); - Tree *len = pop(); - Tree *string = streamPull( prg, exec->fsmRun, (Stream*)stream, len ); - treeUpref( string ); - push( string ); - - /* Single unit. */ - treeUpref( string ); - append( exec->reverseCode, IN_STREAM_PULL_BKT ); - appendWord( exec->reverseCode, (Word) string ); - exec->rcodeUnitLen += SIZEOF_CODE + SIZEOF_WORD; - append( exec->reverseCode, exec->rcodeUnitLen ); - - treeDownref( prg, sp, stream ); - treeDownref( prg, sp, len ); - break; - } - case IN_STREAM_PULL_BKT: { - Tree *string; - read_tree( string ); - - Tree *stream = pop(); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_STREAM_PULL_BKT" << endl; - } - #endif - - undoPull( prg, exec->fsmRun, (Stream*)stream, string ); - treeDownref( prg, sp, stream ); - treeDownref( prg, sp, string ); - break; - } - case IN_STREAM_PUSH_WV: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_STREAM_PUSH_WV" << endl; - } - #endif - Tree *stream = pop(); - Tree *tree = pop(); - Word len = streamPush( prg, sp, ((Stream*)stream), tree, false ); - push( 0 ); - - /* Single unit. */ - append( exec->reverseCode, IN_STREAM_PUSH_BKT ); - appendWord( exec->reverseCode, len ); - exec->rcodeUnitLen += SIZEOF_CODE + SIZEOF_WORD; - append( exec->reverseCode, exec->rcodeUnitLen ); - - treeDownref( prg, sp, stream ); - treeDownref( prg, sp, tree ); - break; - } - case IN_STREAM_PUSH_IGNORE_WV: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_STREAM_PUSH_IGNORE_WV" << endl; - } - #endif - Tree *stream = pop(); - Tree *tree = pop(); - Word len = streamPush( prg, sp, ((Stream*)stream), tree, true ); - push( 0 ); - - /* Single unit. */ - append( exec->reverseCode, IN_STREAM_PUSH_BKT ); - appendWord( exec->reverseCode, len ); - exec->rcodeUnitLen += SIZEOF_CODE + SIZEOF_WORD; - append( exec->reverseCode, exec->rcodeUnitLen ); - - treeDownref( prg, sp, stream ); - treeDownref( prg, sp, tree ); - break; - } - case IN_STREAM_PUSH_BKT: { - Word len; - read_word( len ); - - Tree *stream = pop(); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_STREAM_PUSH_BKT" << endl; - } - #endif - - undoStreamPush( prg, sp, ((Stream*)stream)->in, len ); - treeDownref( prg, sp, stream ); - break; - } - case IN_CONSTRUCT: { - Half patternId; - read_half( patternId ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_CONSTRUCT " << patternId << endl; - } - #endif - - int rootNode = prg->rtd->patReplInfo[patternId].offset; - - /* Note that bindIds are indexed at one. Add one spot for them. */ - int numBindings = prg->rtd->patReplInfo[patternId].numBindings; - Tree *bindings[1+numBindings]; - - for ( int b = 1; b <= numBindings; b++ ) { - bindings[b] = pop(); - assert( bindings[b] != 0 ); - } - - Tree *replTree = 0; - PatReplNode *nodes = prg->rtd->patReplNodes; - LangElInfo *lelInfo = prg->rtd->lelInfo; - long genericId = lelInfo[nodes[rootNode].id].genericId; - if ( genericId > 0 ) { - replTree = createGeneric( prg, genericId ); - treeUpref( replTree ); - } - else { - replTree = constructReplacementTree( bindings, - prg, rootNode ); - } - - push( replTree ); - break; - } - case IN_CONSTRUCT_TERM: { - Half tokenId; - read_half( tokenId ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_CONSTRUCT_TERM " << tokenId << endl; - } - #endif - - /* Pop the string we are constructing the token from. */ - Str *str = (Str*)pop(); - Tree *res = constructTerm( prg, tokenId, str->value ); - treeUpref( res ); - push( res ); - break; - } - case IN_MAKE_TOKEN: { - uchar nargs; - read_byte( nargs ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_MAKE_TOKEN " << (ulong) nargs << endl; - } - #endif - - Tree *result = makeToken2( sp, prg, nargs ); - for ( long i = 0; i < nargs; i++ ) { - Tree *arg = pop(); - treeDownref( prg, sp, arg ); - } - push( result ); - break; - } - case IN_MAKE_TREE: { - uchar nargs; - read_byte( nargs ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_MAKE_TREE " << (ulong) nargs << endl; - } - #endif - - Tree *result = makeTree( sp, prg, nargs ); - for ( long i = 0; i < nargs; i++ ) { - Tree *arg = pop(); - treeDownref( prg, sp, arg ); - } - push( result ); - break; - } - case IN_TREE_NEW: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_TREE_NEW " << endl; - } - #endif - - Tree *tree = pop(); - Tree *res = constructPointer( prg, tree ); - treeUpref( res ); - push( res ); - break; - } - case IN_PTR_DEREF_R: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_PTR_DEREF_R" << endl; - } - #endif - - Pointer *ptr = (Pointer*)pop(); - treeDownref( prg, sp, (Tree*)ptr ); - - Tree *dval = getPtrVal( ptr ); - treeUpref( dval ); - push( dval ); - break; - } - case IN_PTR_DEREF_WC: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_PTR_DEREF_WC" << endl; - } - #endif - - Pointer *ptr = (Pointer*)pop(); - treeDownref( prg, sp, (Tree*)ptr ); - - Tree *dval = getPtrValSplit( prg, ptr ); - treeUpref( dval ); - push( dval ); - break; - } - case IN_PTR_DEREF_WV: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_PTR_DEREF_WV" << endl; - } - #endif - - Pointer *ptr = (Pointer*)pop(); - /* Don't downref the pointer since it is going into the reverse - * instruction. */ - - Tree *dval = getPtrValSplit( prg, ptr ); - treeUpref( dval ); - push( dval ); - - /* This is an initial global load. Need to reverse execute it. */ - append( exec->reverseCode, IN_PTR_DEREF_BKT ); - appendWord( exec->reverseCode, (Word) ptr ); - exec->rcodeUnitLen = SIZEOF_CODE + SIZEOF_WORD; - break; - } - case IN_PTR_DEREF_BKT: { - Word p; - read_word( p ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_PTR_DEREF_BKT" << endl; - } - #endif - - Pointer *ptr = (Pointer*)p; - - Tree *dval = getPtrValSplit( prg, ptr ); - treeUpref( dval ); - push( dval ); - - treeDownref( prg, sp, (Tree*)ptr ); - break; - } - case IN_REF_FROM_LOCAL: { - short int field; - read_half( field ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_REF_FROM_LOCAL " << field << endl; - } - #endif - - /* First push the null next pointer, then the kid pointer. */ - Tree **ptr = plocal(field); - push( 0 ); - push( (SW)ptr ); - break; - } - case IN_REF_FROM_REF: { - short int field; - read_half( field ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_REF_FROM_REF " << field << endl; - } - #endif - - Ref *ref = (Ref*)plocal(field); - push( (SW)ref ); - push( (SW)ref->kid ); - break; - } - case IN_REF_FROM_QUAL_REF: { - short int back; - short int field; - read_half( back ); - read_half( field ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_REF_FROM_QUAL_REF " << back << " " << field << endl; - } - #endif - - Ref *ref = (Ref*)(sp + back); - - Tree *obj = ref->kid->tree; - Kid *attr_kid = getFieldKid( obj, field ); - - push( (SW)ref ); - push( (SW)attr_kid ); - break; - } - case IN_TRITER_REF_FROM_CUR: { - short int field; - read_half( field ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_TRITER_REF_FROM_CUR " << field << endl; - } - #endif - - /* Push the next pointer first, then the kid. */ - TreeIter *iter = (TreeIter*) plocal(field); - push( (SW)&iter->ref ); - push( (SW)iter->ref.kid ); - break; - } - case IN_UITER_REF_FROM_CUR: { - short int field; - read_half( field ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_UITER_REF_FROM_CUR " << field << endl; - } - #endif - - /* Push the next pointer first, then the kid. */ - UserIter *uiter = (UserIter*) local(field); - push( (SW)uiter->ref.next ); - push( (SW)uiter->ref.kid ); - break; - } - case IN_GET_TOKEN_DATA_R: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_GET_TOKEN_DATA_R" << endl; - } - #endif - - Tree *tree = (Tree*) pop(); - Head *data = stringCopy( prg, tree->tokdata ); - Tree *str = constructString( prg, data ); - treeUpref( str ); - push( str ); - treeDownref( prg, sp, tree ); - break; - } - case IN_SET_TOKEN_DATA_WC: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_SET_TOKEN_DATA_WC" << endl; - } - #endif - - Tree *tree = pop(); - Tree *val = pop(); - Head *head = stringCopy( prg, ((Str*)val)->value ); - stringFree( prg, tree->tokdata ); - tree->tokdata = head; - - treeDownref( prg, sp, tree ); - treeDownref( prg, sp, val ); - break; - } - case IN_SET_TOKEN_DATA_WV: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_SET_TOKEN_DATA_WV" << endl; - } - #endif - - Tree *tree = pop(); - Tree *val = pop(); - - Head *oldval = tree->tokdata; - Head *head = stringCopy( prg, ((Str*)val)->value ); - tree->tokdata = head; - - /* Set up reverse code. Needs no args. */ - append( exec->reverseCode, IN_SET_TOKEN_DATA_BKT ); - appendWord( exec->reverseCode, (Word)oldval ); - exec->rcodeUnitLen += SIZEOF_CODE + SIZEOF_WORD; - append( exec->reverseCode, exec->rcodeUnitLen ); - - treeDownref( prg, sp, tree ); - treeDownref( prg, sp, val ); - break; - } - case IN_SET_TOKEN_DATA_BKT: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_SET_TOKEN_DATA_BKT " << endl; - } - #endif - - Word oldval; - read_word( oldval ); - - Tree *tree = pop(); - Head *head = (Head*)oldval; - stringFree( prg, tree->tokdata ); - tree->tokdata = head; - treeDownref( prg, sp, tree ); - break; - } - case IN_GET_TOKEN_POS_R: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_GET_TOKEN_POS_R" << endl; - } - #endif - - Tree *tree = (Tree*) pop(); - Tree *integer = 0; - if ( tree->tokdata->location ) { - integer = constructInteger( prg, tree->tokdata->location->byte ); - treeUpref( integer ); - } - push( integer ); - treeDownref( prg, sp, tree ); - break; - } - case IN_GET_MATCH_LENGTH_R: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_GET_MATCH_LENGTH_R" << endl; - } - #endif - Tree *integer = constructInteger( prg, stringLength(exec->matchText) ); - treeUpref( integer ); - push( integer ); - break; - } - case IN_GET_MATCH_TEXT_R: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_GET_MATCH_TEXT_R" << endl; - } - #endif - Head *s = stringCopy( prg, exec->matchText ); - Tree *tree = constructString( prg, s ); - treeUpref( tree ); - push( tree ); - break; - } - case IN_LIST_LENGTH: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_LIST_LENGTH" << endl; - } - #endif - - List *list = (List*) pop(); - long len = listLength( list ); - Tree *res = constructInteger( prg, len ); - treeUpref( res ); - push( res ); - break; - } - case IN_LIST_APPEND_WV: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_LIST_APPEND_WV" << endl; - } - #endif - - Tree *obj = pop(); - Tree *val = pop(); - - treeDownref( prg, sp, obj ); - - listAppend2( prg, (List*)obj, val ); - treeUpref( prg->trueVal ); - push( prg->trueVal ); - - /* Set up reverse code. Needs no args. */ - append( exec->reverseCode, IN_LIST_APPEND_BKT ); - exec->rcodeUnitLen += SIZEOF_CODE; - append( exec->reverseCode, exec->rcodeUnitLen ); - /* FLUSH */ - break; - } - case IN_LIST_APPEND_WC: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_LIST_APPEND_WC" << endl; - } - #endif - - Tree *obj = pop(); - Tree *val = pop(); - - treeDownref( prg, sp, obj ); - - listAppend2( prg, (List*)obj, val ); - treeUpref( prg->trueVal ); - push( prg->trueVal ); - break; - } - case IN_LIST_APPEND_BKT: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_LIST_APPEND_BKT" << endl; - } - #endif - - Tree *obj = pop(); - treeDownref( prg, sp, obj ); - - Tree *tree = listRemoveEnd( prg, (List*)obj ); - treeDownref( prg, sp, tree ); - break; - } - case IN_LIST_REMOVE_END_WC: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_LIST_REMOVE_END_WC" << endl; - } - #endif - - Tree *obj = pop(); - treeDownref( prg, sp, obj ); - - Tree *end = listRemoveEnd( prg, (List*)obj ); - push( end ); - break; - } - case IN_LIST_REMOVE_END_WV: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_LIST_REMOVE_END_WV" << endl; - } - #endif - - Tree *obj = pop(); - treeDownref( prg, sp, obj ); - - Tree *end = listRemoveEnd( prg, (List*)obj ); - push( end ); - - /* Set up reverse. The result comes off the list downrefed. - * Need it up referenced for the reverse code too. */ - treeUpref( end ); - append( exec->reverseCode, IN_LIST_REMOVE_END_BKT ); - appendWord( exec->reverseCode, (Word)end ); - exec->rcodeUnitLen += SIZEOF_CODE + SIZEOF_WORD; - append( exec->reverseCode, exec->rcodeUnitLen ); - /* FLUSH */ - break; - } - case IN_LIST_REMOVE_END_BKT: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_LIST_REMOVE_END_BKT" << endl; - } - #endif - - Tree *val; - read_tree( val ); - - Tree *obj = pop(); - treeDownref( prg, sp, obj ); - - listAppend2( prg, (List*)obj, val ); - break; - } - case IN_GET_LIST_MEM_R: { - short field; - read_half( field ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_GET_LIST_MEM_R " << field << endl; - } - #endif - - Tree *obj = pop(); - treeDownref( prg, sp, obj ); - - Tree *val = getListMem( (List*)obj, field ); - treeUpref( val ); - push( val ); - break; - } - case IN_GET_LIST_MEM_WC: { - short field; - read_half( field ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_GET_LIST_MEM_WC " << field << endl; - } - #endif - - Tree *obj = pop(); - treeDownref( prg, sp, obj ); - - Tree *val = getListMemSplit( prg, (List*)obj, field ); - treeUpref( val ); - push( val ); - break; - } - case IN_GET_LIST_MEM_WV: { - short field; - read_half( field ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_GET_LIST_MEM_WV " << field << endl; - } - #endif - - Tree *obj = pop(); - treeDownref( prg, sp, obj ); - - Tree *val = getListMemSplit( prg, (List*)obj, field ); - treeUpref( val ); - push( val ); - - /* Set up the reverse instruction. */ - append( exec->reverseCode, IN_GET_LIST_MEM_BKT ); - appendHalf( exec->reverseCode, field ); - exec->rcodeUnitLen += SIZEOF_CODE + SIZEOF_HALF; - break; - } - case IN_GET_LIST_MEM_BKT: { - short field; - read_half( field ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_GET_LIST_MEM_BKT " << field << endl; - } - #endif - - Tree *obj = pop(); - treeDownref( prg, sp, obj ); - - Tree *res = getListMemSplit( prg, (List*)obj, field ); - treeUpref( res ); - push( res ); - break; - } - case IN_SET_LIST_MEM_WC: { - Half field; - read_half( field ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_SET_LIST_MEM_WC " << field << endl; - } - #endif - - Tree *obj = pop(); - treeDownref( prg, sp, obj ); - - Tree *val = pop(); - Tree *existing = setListMem( (List*)obj, field, val ); - treeDownref( prg, sp, existing ); - break; - } - case IN_SET_LIST_MEM_WV: { - Half field; - read_half( field ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_SET_LIST_MEM_WV " << field << endl; - } - #endif - - Tree *obj = pop(); - treeDownref( prg, sp, obj ); - - Tree *val = pop(); - Tree *existing = setListMem( (List*)obj, field, val ); - - /* Set up the reverse instruction. */ - append( exec->reverseCode, IN_SET_LIST_MEM_BKT ); - appendHalf( exec->reverseCode, field ); - appendWord( exec->reverseCode, (Word)existing ); - exec->rcodeUnitLen += SIZEOF_CODE + SIZEOF_HALF + SIZEOF_WORD; - append( exec->reverseCode, exec->rcodeUnitLen ); - /* FLUSH */ - break; - } - case IN_SET_LIST_MEM_BKT: { - Half field; - Tree *val; - read_half( field ); - read_tree( val ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_SET_LIST_MEM_BKT " << field << endl; - } - #endif - - Tree *obj = pop(); - treeDownref( prg, sp, obj ); - - Tree *undid = setListMem( (List*)obj, field, val ); - treeDownref( prg, sp, undid ); - break; - } - case IN_MAP_INSERT_WV: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_MAP_INSERT_WV" << endl; - } - #endif - - Tree *obj = pop(); - Tree *val = pop(); - Tree *key = pop(); - - treeDownref( prg, sp, obj ); - - bool inserted = mapInsert( prg, (Map*)obj, key, val ); - Tree *result = inserted ? prg->trueVal : prg->falseVal; - treeUpref( result ); - push( result ); - - /* Set up the reverse instruction. If the insert fails still need - * to pop the loaded map object. Just use the reverse instruction - * since it's nice to see it in the logs. */ - - /* Need to upref key for storage in reverse code. */ - treeUpref( key ); - append( exec->reverseCode, IN_MAP_INSERT_BKT ); - append( exec->reverseCode, inserted ); - appendWord( exec->reverseCode, (Word)key ); - exec->rcodeUnitLen += SIZEOF_CODE + SIZEOF_CODE + SIZEOF_WORD; - append( exec->reverseCode, exec->rcodeUnitLen ); - - if ( ! inserted ) { - treeDownref( prg, sp, key ); - treeDownref( prg, sp, val ); - } - break; - } - case IN_MAP_INSERT_WC: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_MAP_INSERT_WC" << endl; - } - #endif - - Tree *obj = pop(); - Tree *val = pop(); - Tree *key = pop(); - - treeDownref( prg, sp, obj ); - - bool inserted = mapInsert( prg, (Map*)obj, key, val ); - Tree *result = inserted ? prg->trueVal : prg->falseVal; - treeUpref( result ); - push( result ); - - if ( ! inserted ) { - treeDownref( prg, sp, key ); - treeDownref( prg, sp, val ); - } - break; - } - case IN_MAP_INSERT_BKT: { - uchar inserted; - Tree *key; - read_byte( inserted ); - read_tree( key ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_MAP_INSERT_BKT" << endl; - } - #endif - - Tree *obj = pop(); - if ( inserted ) { - Tree *val = mapUninsert( prg, (Map*)obj, key ); - treeDownref( prg, sp, key ); - treeDownref( prg, sp, val ); - } - - treeDownref( prg, sp, obj ); - treeDownref( prg, sp, key ); - break; - } - case IN_MAP_STORE_WC: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_MAP_STORE_WC" << endl; - } - #endif - - Tree *obj = pop(); - Tree *element = pop(); - Tree *key = pop(); - - Tree *existing = mapStore( prg, (Map*)obj, key, element ); - Tree *result = existing == 0 ? prg->trueVal : prg->falseVal; - treeUpref( result ); - push( result ); - - treeDownref( prg, sp, obj ); - if ( existing != 0 ) { - treeDownref( prg, sp, key ); - treeDownref( prg, sp, existing ); - } - break; - } - case IN_MAP_STORE_WV: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_MAP_STORE_WV" << endl; - } - #endif - - Tree *obj = pop(); - Tree *element = pop(); - Tree *key = pop(); - - Tree *existing = mapStore( prg, (Map*)obj, key, element ); - Tree *result = existing == 0 ? prg->trueVal : prg->falseVal; - treeUpref( result ); - push( result ); - - /* Set up the reverse instruction. */ - treeUpref( key ); - treeUpref( existing ); - append( exec->reverseCode, IN_MAP_STORE_BKT ); - appendWord( exec->reverseCode, (Word)key ); - appendWord( exec->reverseCode, (Word)existing ); - exec->rcodeUnitLen += SIZEOF_CODE + SIZEOF_WORD + SIZEOF_WORD; - append( exec->reverseCode, exec->rcodeUnitLen ); - /* FLUSH */ - - treeDownref( prg, sp, obj ); - if ( existing != 0 ) { - treeDownref( prg, sp, key ); - treeDownref( prg, sp, existing ); - } - break; - } - case IN_MAP_STORE_BKT: { - Tree *key, *val; - read_tree( key ); - read_tree( val ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_MAP_STORE_BKT" << endl; - } - #endif - - Tree *obj = pop(); - Tree *stored = mapUnstore( prg, (Map*)obj, key, val ); - - treeDownref( prg, sp, stored ); - if ( val == 0 ) - treeDownref( prg, sp, key ); - - treeDownref( prg, sp, obj ); - treeDownref( prg, sp, key ); - break; - } - case IN_MAP_REMOVE_WC: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_MAP_REMOVE_WC" << endl; - } - #endif - - Tree *obj = pop(); - Tree *key = pop(); - TreePair pair = mapRemove( prg, (Map*)obj, key ); - - push( pair.val ); - - treeDownref( prg, sp, obj ); - treeDownref( prg, sp, key ); - treeDownref( prg, sp, pair.key ); - break; - } - case IN_MAP_REMOVE_WV: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_MAP_REMOVE_WV" << endl; - } - #endif - - Tree *obj = pop(); - Tree *key = pop(); - TreePair pair = mapRemove( prg, (Map*)obj, key ); - - treeUpref( pair.val ); - push( pair.val ); - - /* Reverse instruction. */ - append( exec->reverseCode, IN_MAP_REMOVE_BKT ); - appendWord( exec->reverseCode, (Word)pair.key ); - appendWord( exec->reverseCode, (Word)pair.val ); - exec->rcodeUnitLen += SIZEOF_CODE + SIZEOF_WORD + SIZEOF_WORD; - append( exec->reverseCode, exec->rcodeUnitLen ); - - treeDownref( prg, sp, obj ); - treeDownref( prg, sp, key ); - break; - } - case IN_MAP_REMOVE_BKT: { - Tree *key, *val; - read_tree( key ); - read_tree( val ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_MAP_REMOVE_BKT" << endl; - } - #endif - - /* Either both or neither. */ - assert( ( key == 0 ) xor ( val != 0 ) ); - - Tree *obj = pop(); - if ( key != 0 ) - mapUnremove( prg, (Map*)obj, key, val ); - - treeDownref( prg, sp, obj ); - break; - } - case IN_MAP_LENGTH: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_MAP_LENGTH" << endl; - } - #endif - - Tree *obj = pop(); - long len = mapLength( (Map*)obj ); - Tree *res = constructInteger( prg, len ); - treeUpref( res ); - push( res ); - - treeDownref( prg, sp, obj ); - break; - } - case IN_MAP_FIND: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_MAP_FIND" << endl; - } - #endif - - Tree *obj = pop(); - Tree *key = pop(); - Tree *result = mapFind( prg, (Map*)obj, key ); - treeUpref( result ); - push( result ); - - treeDownref( prg, sp, obj ); - treeDownref( prg, sp, key ); - break; - } - case IN_INIT_LOCALS: { - Half size; - read_half( size ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_INIT_LOCALS " << size << endl; - } - #endif - - exec->frame = ptop(); - pushn( size ); - memset( ptop(), 0, sizeof(Word) * size ); - break; - } - case IN_POP_LOCALS: { - Half frameId, size; - read_half( frameId ); - read_half( size ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_POP_LOCALS " << frameId << " " << size << endl; - } - #endif - - FrameInfo *fi = &prg->rtd->frameInfo[frameId]; - downrefLocalTrees( prg, sp, exec->frame, fi->trees, fi->treesLen ); - popn( size ); - break; - } - case IN_CALL_WV: { - Half funcId; - read_half( funcId ); - - FunctionInfo *fi = &prg->rtd->functionInfo[funcId]; - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_CALL_WV " << fi->name << endl; - } - #endif - - push( 0 ); /* Return value. */ - push( (SW)instr ); - push( (SW)exec->frame ); - - instr = prg->rtd->frameInfo[fi->frameId].codeWV; - exec->frame = ptop(); - break; - } - case IN_CALL_WC: { - Half funcId; - read_half( funcId ); - - FunctionInfo *fi = &prg->rtd->functionInfo[funcId]; - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_CALL_WC " << fi->name << endl; - } - #endif - - push( 0 ); /* Return value. */ - push( (SW)instr ); - push( (SW)exec->frame ); - - instr = prg->rtd->frameInfo[fi->frameId].codeWC; - exec->frame = ptop(); - break; - } - case IN_YIELD: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_YIELD" << endl; - } - #endif - - Kid *kid = (Kid*)pop(); - Ref *next = (Ref*)pop(); - UserIter *uiter = (UserIter*) plocal_iframe( IFR_AA ); - - if ( kid == 0 || kid->tree == 0 || - kid->tree->id == uiter->searchId || - uiter->searchId == prg->rtd->anyId ) - { - /* Store the yeilded value. */ - uiter->ref.kid = kid; - uiter->ref.next = next; - uiter->stackSize = uiter->stackRoot - ptop(); - uiter->resume = instr; - uiter->frame = exec->frame; - - /* Restore the instruction and frame pointer. */ - instr = (Code*) local_iframe(IFR_RIN); - exec->frame = (Tree**) local_iframe(IFR_RFR); - exec->iframe = (Tree**) local_iframe(IFR_RIF); - - /* Return the yield result on the top of the stack. */ - Tree *result = uiter->ref.kid != 0 ? prg->trueVal : prg->falseVal; - treeUpref( result ); - push( result ); - } - break; - } - case IN_UITER_CREATE_WV: { - short field; - Half funcId, searchId; - read_half( field ); - read_half( funcId ); - read_half( searchId ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_UITER_CREATE_WV " << field << " " << - funcId << " " << searchId << endl; - } - #endif - - FunctionInfo *fi = prg->rtd->functionInfo + funcId; - UserIter *uiter = uiterCreate( sp, prg, fi, searchId ); - local(field) = (SW) uiter; - - /* This is a setup similar to as a call, only the frame structure - * is slightly different for user iterators. We aren't going to do - * the call. We don't need to set up the return ip because the - * uiter advance will set it. The frame we need to do because it - * is set once for the lifetime of the iterator. */ - push( 0 ); /* Return instruction pointer, */ - push( (SW)exec->iframe ); /* Return iframe. */ - push( (SW)exec->frame ); /* Return frame. */ - - uiterInit( prg, sp, uiter, fi, true ); - break; - } - case IN_UITER_CREATE_WC: { - short field; - Half funcId, searchId; - read_half( field ); - read_half( funcId ); - read_half( searchId ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_UITER_CREATE_WC " << field << " " << - funcId << " " << searchId << endl; - } - #endif - - FunctionInfo *fi = prg->rtd->functionInfo + funcId; - UserIter *uiter = uiterCreate( sp, prg, fi, searchId ); - local(field) = (SW) uiter; - - /* This is a setup similar to as a call, only the frame structure - * is slightly different for user iterators. We aren't going to do - * the call. We don't need to set up the return ip because the - * uiter advance will set it. The frame we need to do because it - * is set once for the lifetime of the iterator. */ - push( 0 ); /* Return instruction pointer, */ - push( (SW)exec->iframe ); /* Return iframe. */ - push( (SW)exec->frame ); /* Return frame. */ - - uiterInit( prg, sp, uiter, fi, false ); - break; - } - case IN_UITER_DESTROY: { - short field; - read_half( field ); - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_UITER_DESTROY " << field << endl; - } - #endif - - UserIter *uiter = (UserIter*) local(field); - userIterDestroy( sp, uiter ); - break; - } - case IN_RET: { - Half funcId; - read_half( funcId ); - - FunctionInfo *fui = &prg->rtd->functionInfo[funcId]; - - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_RET " << fui->name << endl; - } - #endif - - FrameInfo *fi = &prg->rtd->frameInfo[fui->frameId]; - downrefLocalTrees( prg, sp, exec->frame, fi->trees, fi->treesLen ); - - popn( fui->frameSize ); - exec->frame = (Tree**) pop(); - instr = (Code*) pop(); - Tree *retVal = pop(); - popn( fui->argSize ); - push( retVal ); - break; - } - case IN_TO_UPPER: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_TO_UPPER" << endl; - } - #endif - Tree *in = pop(); - Head *head = stringToUpper( in->tokdata ); - Tree *upper = constructString( prg, head ); - treeUpref( upper ); - push( upper ); - treeDownref( prg, sp, in ); - break; - } - case IN_TO_LOWER: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_TO_LOWER" << endl; - } - #endif - Tree *in = pop(); - Head *head = stringToLower( in->tokdata ); - Tree *lower = constructString( prg, head ); - treeUpref( lower ); - push( lower ); - treeDownref( prg, sp, in ); - break; - } - case IN_EXIT: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_EXIT" << endl; - } - #endif - - Int *status = (Int*)pop(); - exit( status->value ); - break; - } - case IN_OPEN_FILE: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_OPEN_FILE" << endl; - } - #endif - - Tree *mode = pop(); - Tree *name = pop(); - Tree *res = (Tree*)openFile( prg, name, mode ); - treeUpref( res ); - push( res ); - treeDownref( prg, sp, name ); - treeDownref( prg, sp, mode ); - break; - } - case IN_GET_STDIN: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_GET_STDIN" << endl; - } - #endif - - /* Pop the root object. */ - Tree *obj = pop(); - treeDownref( prg, sp, obj ); - if ( prg->stdinVal == 0 ) { - prg->stdinVal = openStreamFd( prg, 0 ); - treeUpref( (Tree*)prg->stdinVal ); - } - - treeUpref( (Tree*)prg->stdinVal ); - push( (Tree*)prg->stdinVal ); - break; - } - case IN_LOAD_ARGV: { - Half field; - read_half( field ); - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_LOAD_ARGV " << field << endl; - } - #endif - - /* Tree comes back upreffed. */ - Tree *tree = constructArgv( prg, prg->argc, prg->argv ); - setField( prg, prg->global, field, tree ); - break; - } - case IN_STOP: { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "IN_STOP" << endl; - } - #endif - - cout.flush(); - goto out; - } - - /* Halt is a default instruction given by the compiler when it is - * asked to generate and instruction it doesn't have. It is deliberate - * and can represent "not implemented" or "compiler error" because a - * variable holding instructions was not properly initialize. */ - case IN_HALT: { - cerr << "IN_HALT -- compiler did something wrong" << endl; - exit(1); - break; - } - default: { - cerr << "UNKNOWN INSTRUCTION: 0x" << hex << (ulong)instr[-1] << - " -- something is wrong" << endl; - assert(false); - break; - } - } - goto again; - -out: - assert( sp == root ); -} - -void parseError( InputStream *inputStream, FsmRun *fsmRun, PdaRun *pdaRun, int tokId, Tree *tree ) -{ - cerr << "error:" << inputStream->line << ": at token "; - if ( tokId < 128 ) - cerr << "\"" << pdaRun->tables->rtd->lelInfo[tokId].name << "\""; - else - cerr << pdaRun->tables->rtd->lelInfo[tokId].name; - if ( stringLength( tree->tokdata ) > 0 ) { - cerr << " with data \""; - cerr.write( stringData( tree->tokdata ), - stringLength( tree->tokdata ) ); - cerr << "\""; - } - cerr << ": "; -} diff --git a/colm/bytecode.h b/colm/bytecode.h index 41229354..e633cc44 100644 --- a/colm/bytecode.h +++ b/colm/bytecode.h @@ -27,38 +27,11 @@ #include "pool.h" #include "pdarun.h" #include "map.h" - -#include - -using std::cerr; -using std::endl; -using std::ostream; - #include "bytecode2.h" - -typedef struct _Kid Kid; -typedef struct _Tree Tree; -typedef struct _ParseTree ParseTree; -typedef struct _ListEl ListEl; -typedef struct _MapEl MapEl; -typedef struct _List List; -typedef struct _Map Map; -typedef struct _Ref Ref; -typedef struct _Pointer Pointer; -typedef struct _Str Str; -typedef struct _Int Int; -typedef struct _PdaRun PdaRun; - - -void rcodeDownref( Program *prg, Tree **sp, Code *instr ); - #include "tree.h" -Tree **stackAlloc(); - /* * Runtime environment */ - #endif diff --git a/colm/bytecode2.h b/colm/bytecode2.h index 80b6f1f5..c25e90bf 100644 --- a/colm/bytecode2.h +++ b/colm/bytecode2.h @@ -456,6 +456,8 @@ void runProgram( Program *prg ); void allocGlobal( Program *prg ); void executeCode( Execution *exec, Tree **sp, Code *instr ); +void rcodeDownref( Program *prg, Tree **sp, Code *instr ); +Tree **stackAlloc(); #ifdef __cplusplus } diff --git a/colm/ctinput.cpp b/colm/ctinput.cpp index 1fd0284f..52df0ce5 100644 --- a/colm/ctinput.cpp +++ b/colm/ctinput.cpp @@ -24,6 +24,10 @@ #include "input.h" #include "fsmrun.h" +#include +using std::cerr; +using std::endl; + InputFuncs staticFuncs; InputFuncs patternFuncs; InputFuncs replFuncs; diff --git a/colm/debug.c b/colm/debug.c index 047ca518..dd8f7ff2 100644 --- a/colm/debug.c +++ b/colm/debug.c @@ -52,3 +52,11 @@ void fatal( const char *fmt, ... ) va_end( args ); exit(1); } + +void message( const char *fmt, ... ) +{ + va_list args; + va_start( args, fmt ); + vfprintf( stderr, fmt, args ); + va_end( args ); +} diff --git a/colm/debug.h b/colm/debug.h index 15f8a554..7f8519f9 100644 --- a/colm/debug.h +++ b/colm/debug.h @@ -37,6 +37,8 @@ int _debug( long realm, const char *fmt, ... ); int _check_realm( long realm ); extern long colmActiveRealm; +void message( const char *fmt, ... ); + #define REALM_BYTECODE 0x00000001 #define REALM_PARSE 0x00000002 #define REALM_MATCH 0x00000004 diff --git a/colm/fsmrun.c b/colm/fsmrun.c index 8b5463cb..04df873a 100644 --- a/colm/fsmrun.c +++ b/colm/fsmrun.c @@ -473,7 +473,7 @@ void sendQueuedTokens( Tree **sp, PdaRun *pdaRun, FsmRun *fsmRun, InputStream *i incrementConsumed( pdaRun ); - ignore( pdaRun, send->tree ); + ignoreTree( pdaRun, send->tree ); kidFree( fsmRun->prg, send ); } else { @@ -668,7 +668,7 @@ void sendHandleError( Tree **sp, PdaRun *pdaRun, FsmRun *fsmRun, InputStream *in } } -void ignore( PdaRun *pdaRun, Tree *tree ) +void ignoreTree( PdaRun *pdaRun, Tree *tree ) { /* Add the ignore string to the head of the ignore list. */ Kid *ignore = kidAllocate( pdaRun->prg ); @@ -712,7 +712,7 @@ void sendIgnore( InputStream *inputStream, FsmRun *fsmRun, PdaRun *pdaRun, long incrementConsumed( pdaRun ); /* Send it to the pdaRun. */ - ignore( pdaRun, tree ); + ignoreTree( pdaRun, tree ); } Head *extractMatch( Program *prg, FsmRun *fsmRun, InputStream *inputStream ) @@ -1046,7 +1046,7 @@ void sendTreeIgnore( Tree **sp, PdaRun *pdaRun, FsmRun *fsmRun, InputStream *inp incrementConsumed( pdaRun ); - ignore( pdaRun, tree ); + ignoreTree( pdaRun, tree ); } void parseLoop( Tree **sp, PdaRun *pdaRun, FsmRun *fsmRun, InputStream *inputStream ) diff --git a/colm/fsmrun.h b/colm/fsmrun.h index 2efcc607..ed103741 100644 --- a/colm/fsmrun.h +++ b/colm/fsmrun.h @@ -44,9 +44,6 @@ void operator<<( std::ostream &out, exit_object & ); #include "fsmrun2.h" -void execAction( FsmRun *fsmRun, GenAction *genAction ); - -long scan_token( PdaRun *pdaRun, FsmRun *fsmRun, InputStream *inputStream ); #endif diff --git a/colm/main.cpp b/colm/main.cpp index 5b26c026..a8243e9d 100644 --- a/colm/main.cpp +++ b/colm/main.cpp @@ -292,7 +292,7 @@ void compileOutputPath( const char *argv0 ) int length = 1024 + 3*strlen(location) + strlen(outputFileName) + strlen(exec); char command[length]; sprintf( command, - "g++ -Wall -Wwrite-strings" + "gcc -Wall -Wwrite-strings" " -I" PREFIX "/include" " -g" " -o %s" @@ -317,7 +317,7 @@ void compileOutputRelative( const char *argv0 ) int length = 1024 + 3*strlen(location) + strlen(outputFileName) + strlen(exec); char command[length]; sprintf( command, - "g++ -Wall -Wwrite-strings" + "gcc -Wall -Wwrite-strings" " -I%s.." " -I%s../aapl" " -g" diff --git a/colm/parsedata.cpp b/colm/parsedata.cpp index 9fa94c47..ab666350 100644 --- a/colm/parsedata.cpp +++ b/colm/parsedata.cpp @@ -41,6 +41,12 @@ using namespace std; using std::ostringstream; char machineMain[] = "main"; +exit_object endp; +void operator<<( ostream &out, exit_object & ) +{ + out << endl; + exit(1); +} /* Perform minimization after an operation according * to the command line args. */ diff --git a/colm/parsedata.h b/colm/parsedata.h index 41e6f9b4..994dd018 100644 --- a/colm/parsedata.h +++ b/colm/parsedata.h @@ -685,6 +685,7 @@ struct ParseData bool makeFirstSetProd( Definition *prod, PdaState *state ); void makeFirstSets(); + int findIndexOff( PdaTables *pdaTables, PdaGraph *pdaGraph, PdaState *state, int &currLen ); void trySetTime( PdaTrans *trans, long code, long &time ); void addRegion( PdaState *tabState, long pdaKey ); PdaState *followProd( PdaState *tabState, PdaState *prodState ); diff --git a/colm/pdabuild.cpp b/colm/pdabuild.cpp index 630c50b6..a1fa1ae4 100644 --- a/colm/pdabuild.cpp +++ b/colm/pdabuild.cpp @@ -1711,13 +1711,65 @@ void ParseData::fillInPatterns( Program *prg ) } + +int ParseData::findIndexOff( PdaTables *pdaTables, PdaGraph *pdaGraph, PdaState *state, int &curLen ) +{ + for ( int start = 0; start < curLen; ) { + int offset = start; + for ( TransMap::Iter trans = state->transMap; trans.lte(); trans++ ) { + if ( pdaTables->owners[offset] != -1 ) + goto next_start; + + offset++; + if ( ! trans.last() ) { + TransMap::Iter next = trans.next(); + offset += next->key - trans->key - 1; + } + } + + /* Got though the whole list without a conflict. */ + return start; + +next_start: + start++; + } + + return curLen; +} + +struct CmpSpan +{ + static int compare( PdaState *state1, PdaState *state2 ) + { + int dist1 = 0, dist2 = 0; + + if ( state1->transMap.length() > 0 ) { + TransMap::Iter first1 = state1->transMap.first(); + TransMap::Iter last1 = state1->transMap.last(); + dist1 = last1->key - first1->key; + } + + if ( state2->transMap.length() > 0 ) { + TransMap::Iter first2 = state2->transMap.first(); + TransMap::Iter last2 = state2->transMap.last(); + dist2 = last2->key - first2->key; + } + + if ( dist1 < dist2 ) + return 1; + else if ( dist2 < dist1 ) + return -1; + return 0; + } +}; + PdaTables *ParseData::makePdaTables( PdaGraph *pdaGraph ) { - int count, curOffset, pos; + int count, pos; PdaTables *pdaTables = new PdaTables; /* - * Indicies. + * Counting max indices. */ count = 0; for ( PdaStateList::Iter state = pdaGraph->stateList; state.lte(); state++ ) { @@ -1725,27 +1777,64 @@ PdaTables *ParseData::makePdaTables( PdaGraph *pdaGraph ) count++; if ( ! trans.last() ) { TransMap::Iter next = trans.next(); - for ( long key = trans->key+1; key < next->key; key++ ) - count++; + count += next->key - trans->key - 1; } } } - pdaTables->indicies = new int[count]; + + + /* Allocate indicies and owners. */ pdaTables->numIndicies = count; + pdaTables->indicies = new int[count]; + pdaTables->owners = new int[count]; + for ( long i = 0; i < count; i++ ) { + pdaTables->indicies[i] = -1; + pdaTables->owners[i] = -1; + } + + /* Allocate offsets. */ + int numStates = pdaGraph->stateList.length(); + pdaTables->offsets = new unsigned int[numStates]; + pdaTables->numStates = numStates; + + /* Place transitions into indicies/owners */ + PdaState **states = new PdaState*[numStates]; + long ds = 0; + for ( PdaStateList::Iter state = pdaGraph->stateList; state.lte(); state++ ) + states[ds++] = state; + + /* Sorting baseded on span length. Gives an improvement, but incures a + * cost. Off for now. */ + //MergeSort< PdaState*, CmpSpan > mergeSort; + //mergeSort.sort( states, numStates ); + + int indLen = 0; + for ( int s = 0; s < numStates; s++ ) { + PdaState *state = states[s]; + + int indOff = findIndexOff( pdaTables, pdaGraph, state, indLen ); + pdaTables->offsets[state->stateNum] = indOff; - count = 0; - for ( PdaStateList::Iter state = pdaGraph->stateList; state.lte(); state++ ) { for ( TransMap::Iter trans = state->transMap; trans.lte(); trans++ ) { - pdaTables->indicies[count++] = trans->value->actionSetEl->key.id; + pdaTables->indicies[indOff] = trans->value->actionSetEl->key.id; + pdaTables->owners[indOff] = state->stateNum; + indOff++; if ( ! trans.last() ) { TransMap::Iter next = trans.next(); - for ( long key = trans->key+1; key < next->key; key++ ) - pdaTables->indicies[count++] = -1; + indOff += next->key - trans->key - 1; } } + + if ( indOff > indLen ) + indLen = indOff; } + /* We allocated the max, but cmpression gives us less. */ + pdaTables->numIndicies = indLen; + delete[] states; + + /* * Keys */ @@ -1768,26 +1857,6 @@ PdaTables *ParseData::makePdaTables( PdaGraph *pdaGraph ) count += 2; } - /* - * Offsets - */ - count = pdaGraph->stateList.length(); - pdaTables->offsets = new unsigned int[count]; - pdaTables->numStates = count; - - count = 0; - curOffset = 0; - for ( PdaStateList::Iter state = pdaGraph->stateList; state.lte(); state++ ) { - pdaTables->offsets[count++] = curOffset; - - /* Increment the offset. */ - if ( state->transMap.length() > 0 ) { - TransMap::Iter first = state->transMap.first(); - TransMap::Iter last = state->transMap.last(); - curOffset += last->key - first->key + 1; - } - } - /* * Targs */ diff --git a/colm/pdacodegen.cpp b/colm/pdacodegen.cpp index c2567a25..fab5bffc 100644 --- a/colm/pdacodegen.cpp +++ b/colm/pdacodegen.cpp @@ -466,6 +466,18 @@ void PdaCodeGen::writeParserData( long id, PdaTables *tables ) } out << "\n};\n\n"; + out << "int " << prefix << owners() << "[] = {\n\t"; + for ( int i = 0; i < tables->numIndicies; i++ ) { + out << tables->owners[i]; + + if ( i < tables->numIndicies-1 ) { + out << ", "; + if ( (i+1) % 8 == 0 ) + out << "\n\t"; + } + } + out << "\n};\n\n"; + out << "int " << prefix << keys() << "[] = {\n\t"; for ( int i = 0; i < tables->numKeys; i++ ) { out << tables->keys[i]; @@ -566,6 +578,7 @@ void PdaCodeGen::writeParserData( long id, PdaTables *tables ) "PdaTables " << prefix << "pdaTables =\n" "{\n" " " << prefix << indicies() << ",\n" + " " << prefix << owners() << ",\n" " " << prefix << keys() << ",\n" " " << prefix << offsets() << ",\n" " " << prefix << targs() << ",\n" diff --git a/colm/pdacodegen.h b/colm/pdacodegen.h index 7ca32546..fce3d0dd 100644 --- a/colm/pdacodegen.h +++ b/colm/pdacodegen.h @@ -58,6 +58,7 @@ struct PdaCodeGen String startState() { return PARSER() + "startState"; } String indicies() { return PARSER() + "indicies"; } + String owners() { return PARSER() + "owners"; } String keys() { return PARSER() + "keys"; } String offsets() { return PARSER() + "offsets"; } String targs() { return PARSER() + "targs"; } diff --git a/colm/pdarun.c b/colm/pdarun.c index 548efbb3..45dbcf12 100644 --- a/colm/pdarun.c +++ b/colm/pdarun.c @@ -358,7 +358,9 @@ void parseToken( Tree **sp, PdaRun *pdaRun, FsmRun *fsmRun, InputStream *inputSt unsigned int *action; int rhsLen; Kid *lel; + int owner; int induceReject; + int indPos; /* The scanner will send a null token if it can't find a token. */ if ( input == 0 ) @@ -387,8 +389,14 @@ again: lel->tree->id > pdaRun->tables->keys[(pdaRun->cs<<1)+1] ) goto parseError; - pos = pdaRun->tables->indicies[pdaRun->tables->offsets[pdaRun->cs] - + (lel->tree->id - pdaRun->tables->keys[pdaRun->cs<<1])]; + indPos = pdaRun->tables->offsets[pdaRun->cs] + + (lel->tree->id - pdaRun->tables->keys[pdaRun->cs<<1]); + + owner = pdaRun->tables->owners[indPos]; + if ( owner != pdaRun->cs ) + goto parseError; + + pos = pdaRun->tables->indicies[indPos]; if ( pos < 0 ) goto parseError; diff --git a/colm/pdarun.h b/colm/pdarun.h index 1601602f..b5ba0f32 100644 --- a/colm/pdarun.h +++ b/colm/pdarun.h @@ -370,6 +370,7 @@ typedef struct _PdaTables { /* Parser table data. */ int *indicies; + int *owners; int *keys; unsigned int *offsets; unsigned int *targs; @@ -579,7 +580,7 @@ void pdaRunMatch( PdaRun *pdaRun, Kid *tree, Kid *pattern ); int pdaRunGetNextRegion( PdaRun *pdaRun, int offset ); void cleanParser( Tree **root, PdaRun *pdaRun ); -void ignore( PdaRun *pdaRun, Tree *tree ); +void ignoreTree( PdaRun *pdaRun, Tree *tree ); void parseToken( Tree **sp, PdaRun *pdaRun, FsmRun *fsmRun, InputStream *inputStream, Kid *input ); long undoParse( Tree **sp, PdaRun *pdaRun, FsmRun *fsmRun, InputStream *inputStream, Tree *tree ); void xml_print_list( RuntimeData *runtimeData, Kid *lel, int depth ); diff --git a/colm/tree.c b/colm/tree.c new file mode 100644 index 00000000..b5c46526 --- /dev/null +++ b/colm/tree.c @@ -0,0 +1,2033 @@ +/* + * Copyright 2008 Adrian Thurston + */ + +/* This file is part of Colm. + * + * Colm is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Colm is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Colm; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "pdarun.h" +#include "tree.h" +#include "pool.h" +#include "bytecode2.h" +#include "debug.h" +#include "map.h" +#include +#include +#include + +#define true 1 +#define false 0 + +#define BUFFER_INITIAL_SIZE 4096 + +void initUserIter( UserIter *userIter, Tree **stackRoot, long argSize, long searchId ) +{ + userIter->stackRoot = stackRoot; + userIter->argSize = argSize; + userIter->stackSize = 0; + userIter->resume = 0; + userIter->frame = 0; + userIter->searchId = searchId; + + userIter->ref.kid = 0; + userIter->ref.next = 0; +} + +Kid *allocAttrs( Program *prg, long length ) +{ + Kid *cur = 0; + long i; + for ( i = 0; i < length; i++ ) { + Kid *next = cur; + cur = kidAllocate( prg ); + cur->next = next; + } + return cur; +} + +void freeAttrs( Program *prg, Kid *attrs ) +{ + Kid *cur = attrs; + while ( cur != 0 ) { + Kid *next = cur->next; + kidFree( prg, cur ); + cur = next; + } +} + +void setAttr( Tree *tree, long pos, Tree *val ) +{ + long i; + Kid *kid = tree->child; + + if ( tree->flags & AF_LEFT_IGNORE ) + kid = kid->next; + if ( tree->flags & AF_RIGHT_IGNORE ) + kid = kid->next; + + for ( i = 0; i < pos; i++ ) + kid = kid->next; + kid->tree = val; +} + +Tree *getAttr( Tree *tree, long pos ) +{ + long i; + Kid *kid = tree->child; + + if ( tree->flags & AF_LEFT_IGNORE ) + kid = kid->next; + if ( tree->flags & AF_RIGHT_IGNORE ) + kid = kid->next; + + for ( i = 0; i < pos; i++ ) + kid = kid->next; + return kid->tree; +} + +Kid *getAttrKid( Tree *tree, long pos ) +{ + long i; + Kid *kid = tree->child; + + if ( tree->flags & AF_LEFT_IGNORE ) + kid = kid->next; + if ( tree->flags & AF_RIGHT_IGNORE ) + kid = kid->next; + + for ( i = 0; i < pos; i++ ) + kid = kid->next; + return kid; +} + +Kid *kidListConcat( Kid *list1, Kid *list2 ) +{ + if ( list1 == 0 ) + return list2; + else if ( list2 == 0 ) + return list1; + + Kid *dest = list1; + while ( dest->next != 0 ) + dest = dest->next; + dest->next = list2; + return list1; +} + + +Stream *openStreamFile( Program *prg, FILE *file ) +{ + Stream *res = (Stream*)mapElAllocate( prg ); + res->id = LEL_ID_STREAM; + res->file = file; + res->in = newInputStreamFile( file ); + initInputStream( res->in ); + return res; +} + +Stream *openStreamFd( Program *prg, long fd ) +{ + Stream *res = (Stream*)mapElAllocate( prg ); + res->id = LEL_ID_STREAM; + res->in = newInputStreamFd( fd ); + initInputStream( res->in ); + return res; +} + +Stream *openFile( Program *prg, Tree *name, Tree *mode ) +{ + Head *headName = ((Str*)name)->value; + Head *headMode = ((Str*)mode)->value; + + const char *givenMode = stringData(headMode); + const char *fopenMode = 0; + if ( memcmp( givenMode, "r", stringLength(headMode) ) == 0 ) + fopenMode = "rb"; + else if ( memcmp( givenMode, "w", stringLength(headMode) ) == 0 ) + fopenMode = "wb"; + else { + fatal( "unknown file open mode: %s\n", givenMode ); + } + + /* Need to make a C-string (null terminated). */ + char *fileName = (char*)malloc(stringLength(headName)+1); + memcpy( fileName, stringData(headName), stringLength(headName) ); + fileName[stringLength(headName)] = 0; + FILE *file = fopen( fileName, fopenMode ); + free(fileName); + return openStreamFile( prg, file ); +} + +Tree *constructInteger( Program *prg, long i ) +{ + Int *integer = (Int*) treeAllocate( prg ); + integer->id = LEL_ID_INT; + integer->value = i; + + return (Tree*)integer; +} + +Tree *constructString( Program *prg, Head *s ) +{ + Str *str = (Str*) treeAllocate( prg ); + str->id = LEL_ID_STR; + str->value = s; + + return (Tree*)str; +} + +Tree *constructPointer( Program *prg, Tree *tree ) +{ + Kid *kid = kidAllocate( prg ); + kid->tree = tree; + kid->next = prg->heap; + prg->heap = kid; + + Pointer *pointer = (Pointer*) treeAllocate( prg ); + pointer->id = LEL_ID_PTR; + pointer->value = kid; + + return (Tree*)pointer; +} + +Tree *constructTerm( Program *prg, Word id, Head *tokdata ) +{ + LangElInfo *lelInfo = prg->rtd->lelInfo; + + Tree *tree = treeAllocate( prg ); + tree->id = id; + tree->refs = 0; + tree->tokdata = tokdata; + + int objectLength = lelInfo[tree->id].objectLength; + tree->child = allocAttrs( prg, objectLength ); + + return tree; +} + +Kid *constructReplacementKid( Tree **bindings, Program *prg, Kid *prev, long pat ); + +Kid *constructIgnoreList( Program *prg, long pat ) +{ + PatReplNode *nodes = prg->rtd->patReplNodes; + long ignore = nodes[pat].ignore; + + Kid *first = 0, *last = 0; + while ( ignore >= 0 ) { + Head *ignoreData = stringAllocPointer( prg, nodes[ignore].data, nodes[ignore].length ); + + Tree *ignTree = treeAllocate( prg ); + ignTree->refs = 1; + ignTree->id = nodes[ignore].id; + ignTree->tokdata = ignoreData; + + Kid *ignKid = kidAllocate( prg ); + ignKid->tree = ignTree; + ignKid->next = 0; + + if ( last == 0 ) + first = ignKid; + else + last->next = ignKid; + + ignore = nodes[ignore].next; + last = ignKid; + } + + return first; +} + +/* Returns an uprefed tree. Saves us having to downref and bindings to zero to + * return a zero-ref tree. */ +Tree *constructReplacementTree( Tree **bindings, Program *prg, long pat ) +{ + PatReplNode *nodes = prg->rtd->patReplNodes; + LangElInfo *lelInfo = prg->rtd->lelInfo; + Tree *tree = 0; + + if ( nodes[pat].bindId > 0 ) { + /* All bindings have been uprefed. */ + tree = bindings[nodes[pat].bindId]; + + long ignore = nodes[pat].ignore; + if ( ignore >= 0 ) { + Kid *ignore = constructIgnoreList( prg, pat ); + + tree = splitTree( prg, tree ); + + Kid *ignoreHead = kidAllocate( prg ); + ignoreHead->next = tree->child; + tree->child = ignoreHead; + + ignoreHead->tree = (Tree*) ignore; + tree->flags |= AF_LEFT_IGNORE; + } + } + else { + tree = treeAllocate( prg ); + tree->id = nodes[pat].id; + tree->refs = 1; + tree->tokdata = nodes[pat].length == 0 ? 0 : + stringAllocPointer( prg, + nodes[pat].data, nodes[pat].length ); + + int objectLength = lelInfo[tree->id].objectLength; + + Kid *attrs = allocAttrs( prg, objectLength ); + Kid *ignore = constructIgnoreList( prg, pat ); + Kid *child = constructReplacementKid( bindings, prg, + 0, nodes[pat].child ); + + tree->child = kidListConcat( attrs, child ); + if ( ignore != 0 ) { + Kid *ignoreHead = kidAllocate( prg ); + ignoreHead->next = tree->child; + tree->child = ignoreHead; + + ignoreHead->tree = (Tree*) ignore; + tree->flags |= AF_LEFT_IGNORE; + } + + int i; + for ( i = 0; i < lelInfo[tree->id].numCaptureAttr; i++ ) { + long ci = pat+1+i; + CaptureAttr *ca = prg->rtd->captureAttr + lelInfo[tree->id].captureAttr + i; + Tree *attr = treeAllocate( prg ); + attr->id = nodes[ci].id; + attr->refs = 1; + attr->tokdata = nodes[ci].length == 0 ? 0 : + stringAllocPointer( prg, + nodes[ci].data, nodes[ci].length ); + + setAttr( tree, ca->offset, attr ); + } + } + + return tree; +} + +Kid *constructReplacementKid( Tree **bindings, Program *prg, Kid *prev, long pat ) +{ + PatReplNode *nodes = prg->rtd->patReplNodes; + Kid *kid = 0; + + if ( pat != -1 ) { + kid = kidAllocate( prg ); + kid->tree = constructReplacementTree( bindings, prg, pat ); + + /* Recurse down next. */ + Kid *next = constructReplacementKid( bindings, prg, + kid, nodes[pat].next ); + + kid->next = next; + } + + return kid; +} + +Tree *makeToken2( Tree **root, Program *prg, long nargs ) +{ + Tree **const sp = root; + Tree **base = vm_ptop() + nargs; + + Int *idInt = (Int*)base[-1]; + Str *textStr = (Str*)base[-2]; + + long id = idInt->value; + Head *tokdata = stringCopy( prg, textStr->value ); + + LangElInfo *lelInfo = prg->rtd->lelInfo; + Tree *tree; + + if ( lelInfo[id].ignore ) { + tree = treeAllocate( prg ); + tree->refs = 1; + tree->id = id; + tree->tokdata = tokdata; + } + else { + long objectLength = lelInfo[id].objectLength; + Kid *attrs = allocAttrs( prg, objectLength ); + + tree = treeAllocate( prg ); + tree->id = id; + tree->refs = 1; + tree->tokdata = tokdata; + + tree->child = attrs; + + assert( nargs-2 <= objectLength ); + long id; + for ( id = 0; id < nargs-2; id++ ) { + setAttr( tree, id, base[-3-id] ); + treeUpref( getAttr( tree, id) ); + } + } + return tree; +} + +Tree *makeTree( Tree **root, Program *prg, long nargs ) +{ + Tree **const sp = root; + Tree **base = vm_ptop() + nargs; + + Int *idInt = (Int*)base[-1]; + + long id = idInt->value; + LangElInfo *lelInfo = prg->rtd->lelInfo; + + Tree *tree = treeAllocate( prg ); + tree->id = id; + tree->refs = 1; + + long objectLength = lelInfo[id].objectLength; + Kid *attrs = allocAttrs( prg, objectLength ); + + Kid *last = 0, *child = 0; + for ( id = 0; id < nargs-1; id++ ) { + Kid *kid = kidAllocate( prg ); + kid->tree = base[-2-id]; + treeUpref( kid->tree ); + + if ( last == 0 ) + child = kid; + else + last->next = kid; + + last = kid; + } + + tree->child = kidListConcat( attrs, child ); + + return tree; +} + +int testFalse( Program *prg, Tree *tree ) +{ + int flse = ( + tree == 0 || + tree == prg->falseVal || + ( tree->id == LEL_ID_INT && ((Int*)tree)->value == 0 ) ); + return flse; +} + +void printStr2( FILE *out, Head *str ) +{ + fwrite( (char*)(str->data), str->length, 1, out ); +} + +/* Note that this function causes recursion, thought it is not a big + * deal since the recursion it is only caused by nonterminals that are ignored. */ +void printIgnoreList2( FILE *out, Tree **sp, Program *prg, Tree *tree ) +{ + Kid *ignore = treeIgnore( prg, tree ); + + /* Record the root of the stack and push everything. */ + Tree **root = vm_ptop(); + while ( ignore != 0 ) { + vm_push( (SW)ignore ); + ignore = ignore->next; + } + + /* Pop them off and print. */ + while ( vm_ptop() != root ) { + ignore = (Kid*) vm_pop(); + printTree2( out, sp, prg, ignore->tree ); + } +} + + +void printKid2( FILE *out, Tree **sp, Program *prg, Kid *kid, int printIgnore ) +{ + Tree **root = vm_ptop(); + Kid *child; + +rec_call: + /* If not currently skipping ignore data, then print it. Ignore data can + * be associated with terminals and nonterminals. */ + if ( printIgnore && treeIgnore( prg, kid->tree ) != 0 ) { + /* Ignorelists are reversed. */ + printIgnoreList2( out, sp, prg, kid->tree ); + printIgnore = false; + } + + if ( kid->tree->id < prg->rtd->firstNonTermId ) { + /* Always turn on ignore printing when we get to a token. */ + printIgnore = true; + + if ( kid->tree->id == LEL_ID_INT ) + fprintf( out, "%ld", ((Int*)kid->tree)->value ); + else if ( kid->tree->id == LEL_ID_BOOL ) { + if ( ((Int*)kid->tree)->value ) + fprintf( out, "true" ); + else + fprintf( out, "false" ); + } + else if ( kid->tree->id == LEL_ID_PTR ) + fprintf( out, "#%p", (void*) ((Pointer*)kid->tree)->value ); + else if ( kid->tree->id == LEL_ID_STR ) + printStr2( out, ((Str*)kid->tree)->value ); + else if ( kid->tree->id == LEL_ID_STREAM ) + fprintf( out, "#%p", ((Stream*)kid->tree)->file ); + else if ( kid->tree->tokdata != 0 && + stringLength( kid->tree->tokdata ) > 0 ) + { + fwrite( stringData( kid->tree->tokdata ), + stringLength( kid->tree->tokdata ), 1, out ); + } + } + else { + /* Non-terminal. */ + child = treeChild( prg, kid->tree ); + if ( child != 0 ) { + vm_push( (SW)kid ); + kid = child; + while ( kid != 0 ) { + goto rec_call; + rec_return: + kid = kid->next; + } + kid = (Kid*)vm_pop(); + } + } + + if ( vm_ptop() != root ) + goto rec_return; +} + +void printTree2( FILE *out, Tree **sp, Program *prg, Tree *tree ) +{ + if ( tree == 0 ) + fprintf( out, "NIL" ); + else { + Kid kid; + kid.tree = tree; + kid.next = 0; + printKid2( out, sp, prg, &kid, false ); + } +} + +void streamFree( Program *prg, Stream *s ) +{ + free( s->in ); + if ( s->file != 0 ) + fclose( s->file ); + mapElFree( prg, (MapEl*)s ); +} + +Kid *copyIgnoreList( Program *prg, Kid *ignoreHeader ) +{ + Kid *newHeader = kidAllocate( prg ); + Kid *last = 0, *ic = (Kid*)ignoreHeader->tree; + while ( ic != 0 ) { + Kid *newIc = kidAllocate( prg ); + + newIc->tree = ic->tree; + newIc->tree->refs += 1; + + /* List pointers. */ + if ( last == 0 ) + newHeader->tree = (Tree*)newIc; + else + last->next = newIc; + + ic = ic->next; + last = newIc; + } + return newHeader; +} + +/* New tree has zero ref. */ +Tree *copyRealTree( Program *prg, Tree *tree, Kid *oldNextDown, + Kid **newNextDown, int parseTree ) +{ + /* Need to keep a lookout for next down. If + * copying it, return the copy. */ + Tree *newTree; + if ( parseTree ) { + newTree = (Tree*) parseTreeAllocate( prg ); + newTree->flags |= AF_PARSE_TREE; + } + else { + newTree = treeAllocate( prg ); + } + + newTree->id = tree->id; + newTree->tokdata = stringCopy( prg, tree->tokdata ); + + /* Copy the child list. Start with ignores, then the list. */ + Kid *child = tree->child, *last = 0; + + /* Left ignores. */ + if ( tree->flags & AF_LEFT_IGNORE ) { + newTree->flags |= AF_LEFT_IGNORE; + Kid *newHeader = copyIgnoreList( prg, child ); + + /* Always the head. */ + newTree->child = newHeader; + + child = child->next; + last = newHeader; + } + + /* Right ignores. */ + if ( tree->flags & AF_RIGHT_IGNORE ) { + newTree->flags |= AF_RIGHT_IGNORE; + Kid *newHeader = copyIgnoreList( prg, child ); + if ( last == 0 ) + newTree->child = newHeader; + else + last->next = newHeader; + child = child->next; + last = newHeader; + } + + /* Attributes and children. */ + while ( child != 0 ) { + Kid *newKid = kidAllocate( prg ); + + /* Watch out for next down. */ + if ( child == oldNextDown ) + *newNextDown = newKid; + + newKid->tree = child->tree; + newKid->next = 0; + + /* May be an attribute. */ + if ( newKid->tree != 0 ) + newKid->tree->refs += 1; + + /* Store the first child. */ + if ( last == 0 ) + newTree->child = newKid; + else + last->next = newKid; + + child = child->next; + last = newKid; + } + + return newTree; +} + +List *copyList( Program *prg, List *list, Kid *oldNextDown, Kid **newNextDown ) +{ + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "splitting list: " << list << " refs: " << + list->refs << endl; + } + #endif + + /* Not a need copy. */ + List *newList = (List*)mapElAllocate( prg ); + newList->id = list->genericInfo->langElId; + newList->genericInfo = list->genericInfo; + + ListEl *src = list->head; + while( src != 0 ) { + ListEl *newEl = listElAllocate( prg ); + newEl->value = src->value; + treeUpref( newEl->value ); + + listAppend( newList, newEl ); + + /* Watch out for next down. */ + if ( (Kid*)src == oldNextDown ) + *newNextDown = (Kid*)newEl; + + src = src->next; + } + + return newList; +} + +Map *copyMap( Program *prg, Map *map, Kid *oldNextDown, Kid **newNextDown ) +{ + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "splitting map: " << map << " refs: " << + map->refs << endl; + } + #endif + + Map *newMap = (Map*)mapElAllocate( prg ); + newMap->id = map->genericInfo->langElId; + newMap->genericInfo = map->genericInfo; + newMap->treeSize = map->treeSize; + newMap->root = 0; + + /* If there is a root, copy the tree. */ + if ( map->root != 0 ) { + newMap->root = mapCopyBranch( prg, newMap, map->root, + oldNextDown, newNextDown ); + } + MapEl *el; + for ( el = newMap->head; el != 0; el = el->next ) { + assert( map->genericInfo->typeArg == TYPE_TREE ); + treeUpref( el->tree ); + } + + return newMap; +} + +Tree *copyTree( Program *prg, Tree *tree, Kid *oldNextDown, Kid **newNextDown ) +{ + LangElInfo *lelInfo = prg->rtd->lelInfo; + long genericId = lelInfo[tree->id].genericId; + if ( genericId > 0 ) { + GenericInfo *generic = &prg->rtd->genericInfo[genericId]; + if ( generic->type == GEN_LIST ) + tree = (Tree*) copyList( prg, (List*) tree, oldNextDown, newNextDown ); + else if ( generic->type == GEN_MAP ) + tree = (Tree*) copyMap( prg, (Map*) tree, oldNextDown, newNextDown ); + else if ( generic->type == GEN_PARSER ) { + /* Need to figure out the semantics here. */ + fatal( "ATTEMPT TO COPY PARSER\n" ); + assert(false); + } + } + else if ( tree->id == LEL_ID_PTR ) + assert(false); + else if ( tree->id == LEL_ID_BOOL ) + assert(false); + else if ( tree->id == LEL_ID_INT ) + assert(false); + else if ( tree->id == LEL_ID_STR ) + assert(false); + else if ( tree->id == LEL_ID_STREAM ) + assert(false); + else { + tree = copyRealTree( prg, tree, oldNextDown, newNextDown, false ); + } + + assert( tree->refs == 0 ); + return tree; +} + +Tree *splitTree( Program *prg, Tree *tree ) +{ + if ( tree != 0 ) { + assert( tree->refs >= 1 ); + + if ( tree->refs > 1 ) { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "splitting tree: " << tree << " refs: " << + tree->refs << endl; + } + #endif + + Kid *oldNextDown = 0, *newNextDown = 0; + Tree *newTree = copyTree( prg, tree, oldNextDown, &newNextDown ); + treeUpref( newTree ); + + /* Downref the original. Don't need to consider freeing because + * refs were > 1. */ + tree->refs -= 1; + + tree = newTree; + } + + assert( tree->refs == 1 ); + } + return tree; +} + +Tree *createGeneric( Program *prg, long genericId ) +{ + GenericInfo *genericInfo = &prg->rtd->genericInfo[genericId]; + Tree *newGeneric = 0; + switch ( genericInfo->type ) { + case GEN_MAP: { + Map *map = (Map*)mapElAllocate( prg ); + map->id = genericInfo->langElId; + map->genericInfo = genericInfo; + newGeneric = (Tree*) map; + break; + } + case GEN_LIST: { + List *list = (List*)mapElAllocate( prg ); + list->id = genericInfo->langElId; + list->genericInfo = genericInfo; + newGeneric = (Tree*) list; + break; + } + case GEN_PARSER: { + Accum *accum = (Accum*)mapElAllocate( prg ); + accum->id = genericInfo->langElId; + accum->genericInfo = genericInfo; + accum->fsmRun = malloc( sizeof(FsmRun) ); + accum->pdaRun = malloc( sizeof(PdaRun) ); + + /* Start off the parsing process. */ + initPdaRun( accum->pdaRun, prg, prg->rtd->pdaTables, + accum->fsmRun, genericInfo->parserId, false, false, 0 ); + initFsmRun( accum->fsmRun, prg ); + newToken( accum->pdaRun, accum->fsmRun ); + + newGeneric = (Tree*) accum; + break; + } + default: + assert(false); + return 0; + } + + return newGeneric; +} + + +/* We can't make recursive calls here since the tree we are freeing may be + * very large. Need the VM stack. */ +void treeFreeRec( Program *prg, Tree **sp, Tree *tree ) +{ + Tree **top = sp; + LangElInfo *lelInfo; + long genericId; + +free_tree: + lelInfo = prg->rtd->lelInfo; + genericId = lelInfo[tree->id].genericId; + if ( genericId > 0 ) { + GenericInfo *generic = &prg->rtd->genericInfo[genericId]; + if ( generic->type == GEN_LIST ) { + List *list = (List*) tree; + ListEl *el = list->head; + while ( el != 0 ) { + ListEl *next = el->next; + vm_push( el->value ); + listElFree( prg, el ); + el = next; + } + mapElFree( prg, (MapEl*)list ); + } + else if ( generic->type == GEN_MAP ) { + Map *map = (Map*)tree; + MapEl *el = map->head; + while ( el != 0 ) { + MapEl *next = el->next; + vm_push( el->key ); + vm_push( el->tree ); + mapElFree( prg, el ); + el = next; + } + mapElFree( prg, (MapEl*)map ); + } + else if ( generic->type == GEN_PARSER ) { + Accum *accum = (Accum*)tree; + free( accum->fsmRun ); + cleanParser( sp, accum->pdaRun ); + clearContext( accum->pdaRun, sp ); + rcodeDownrefAll( prg, sp, accum->pdaRun->allReverseCode ); + free( accum->pdaRun ); + treeDownref( prg, sp, (Tree*)accum->stream ); + mapElFree( prg, (MapEl*)accum ); + } + else + assert(false); + } + else { + if ( tree->id == LEL_ID_STR ) { + Str *str = (Str*) tree; + stringFree( prg, str->value ); + treeFree( prg, tree ); + } + else if ( tree->id == LEL_ID_BOOL || tree->id == LEL_ID_INT ) + treeFree( prg, tree ); + else if ( tree->id == LEL_ID_PTR ) { + //Pointer *ptr = (Pointer*)tree; + //vm_push( ptr->value->tree ); + //kidFree( prg, ptr->value ); + treeFree( prg, tree ); + } + else if ( tree->id == LEL_ID_STREAM ) + streamFree( prg, (Stream*) tree ); + else { + stringFree( prg, tree->tokdata ); + Kid *child = tree->child; + + /* Left ignore trees. */ + if ( tree->flags & AF_LEFT_IGNORE ) { + Kid *ic = (Kid*)child->tree; + while ( ic != 0 ) { + Kid *next = ic->next; + vm_push( ic->tree ); + kidFree( prg, ic ); + ic = next; + } + + Kid *next = child->next; + kidFree( prg, child ); + child = next; + } + + /* Right ignore trees. */ + if ( tree->flags & AF_RIGHT_IGNORE ) { + Kid *ic = (Kid*)child->tree; + while ( ic != 0 ) { + Kid *next = ic->next; + vm_push( ic->tree ); + kidFree( prg, ic ); + ic = next; + } + + Kid *next = child->next; + kidFree( prg, child ); + child = next; + } + + /* Attributes and grammar-based children. */ + while ( child != 0 ) { + Kid *next = child->next; + vm_push( child->tree ); + kidFree( prg, child ); + child = next; + } + + if ( tree->flags & AF_PARSE_TREE ) + parseTreeFree( prg, (ParseTree*)tree ); + else + treeFree( prg, tree ); + } + } + + /* Any trees to downref? */ + while ( sp != top ) { + tree = vm_pop(); + if ( tree != 0 ) { + assert( tree->refs > 0 ); + tree->refs -= 1; + if ( tree->refs == 0 ) + goto free_tree; + } + } +} + +void treeUpref( Tree *tree ) +{ + if ( tree != 0 ) + tree->refs += 1; +} + +void treeDownref( Program *prg, Tree **sp, Tree *tree ) +{ + if ( tree != 0 ) { + assert( tree->refs > 0 ); + tree->refs -= 1; + if ( tree->refs == 0 ) + treeFreeRec( prg, sp, tree ); + } +} + +/* Find the first child of a tree. */ +Kid *treeChild( Program *prg, const Tree *tree ) +{ + LangElInfo *lelInfo = prg->rtd->lelInfo; + Kid *kid = tree->child; + + if ( tree->flags & AF_LEFT_IGNORE ) + kid = kid->next; + if ( tree->flags & AF_RIGHT_IGNORE ) + kid = kid->next; + + /* Skip over attributes. */ + long objectLength = lelInfo[tree->id].objectLength; + long a; + for ( a = 0; a < objectLength; a++ ) + kid = kid->next; + + return kid; +} + +/* Find the first child of a tree. */ +Kid *treeExtractChild( Program *prg, Tree *tree ) +{ + LangElInfo *lelInfo = prg->rtd->lelInfo; + Kid *kid = tree->child, *last = 0; + + if ( tree->flags & AF_LEFT_IGNORE ) + kid = kid->next; + if ( tree->flags & AF_RIGHT_IGNORE ) + kid = kid->next; + + /* Skip over attributes. */ + long objectLength = lelInfo[tree->id].objectLength; + long a; + for ( a = 0; a < objectLength; a++ ) { + last = kid; + kid = kid->next; + } + + if ( last == 0 ) + tree->child = 0; + else + last->next = 0; + + return kid; +} + + +Kid *treeIgnore( Program *prg, Tree *tree ) +{ + if ( tree->flags & AF_LEFT_IGNORE ) + return (Kid*)tree->child->tree; + return 0; +} + +Tree *treeIterDerefCur( TreeIter *iter ) +{ + return iter->ref.kid == 0 ? 0 : iter->ref.kid->tree; +} + +void refSetValue( Ref *ref, Tree *v ) +{ + Kid *firstKid = ref->kid; + while ( ref != 0 && ref->kid == firstKid ) { + ref->kid->tree = v; + ref = ref->next; + } +} + +Tree *getRhsEl( Program *prg, Tree *lhs, long position ) +{ + Kid *pos = treeChild( prg, lhs ); + while ( position > 0 ) { + pos = pos->next; + position -= 1; + } + return pos->tree; +} + +void setField( Program *prg, Tree *tree, long field, Tree *value ) +{ + assert( tree->refs == 1 ); + if ( value != 0 ) + assert( value->refs >= 1 ); + setAttr( tree, field, value ); +} + +Tree *getField( Tree *tree, Word field ) +{ + return getAttr( tree, field ); +} + +Kid *getFieldKid( Tree *tree, Word field ) +{ + return getAttrKid( tree, field ); +} + +Tree *getFieldSplit( Program *prg, Tree *tree, Word field ) +{ + Tree *val = getAttr( tree, field ); + Tree *split = splitTree( prg, val ); + setAttr( tree, field, split ); + return split; +} + +void setTriterCur( TreeIter *iter, Tree *tree ) +{ + iter->ref.kid->tree = tree; +} + +Tree *getPtrVal( Pointer *ptr ) +{ + return ptr->value->tree; +} + +Tree *getPtrValSplit( Program *prg, Pointer *ptr ) +{ + Tree *val = ptr->value->tree; + Tree *split = splitTree( prg, val ); + ptr->value->tree = split; + return split; +} + +/* This must traverse in the same order that the bindId assignments are done + * in. */ +int matchPattern( Tree **bindings, Program *prg, long pat, Kid *kid, int checkNext ) +{ + PatReplNode *nodes = prg->rtd->patReplNodes; + + #ifdef COLM_LOG_MATCH + if ( colm_log_match ) { + LangElInfo *lelInfo = prg->rtd->lelInfo; + cerr << "match pattern " << ( pat == -1 ? "NULL" : lelInfo[nodes[pat].id].name ) << + " vs " << ( kid == 0 ? "NULL" : lelInfo[kid->tree->id].name ) << endl; + } + #endif + + /* match node, recurse on children. */ + if ( pat != -1 && kid != 0 ) { + if ( nodes[pat].id == kid->tree->id ) { + /* If the pattern node has data, then this means we need to match + * the data against the token data. */ + if ( nodes[pat].data != 0 ) { + /* Check the length of token text. */ + if ( nodes[pat].length != stringLength( kid->tree->tokdata ) ) + return false; + + /* Check the token text data. */ + if ( nodes[pat].length > 0 && memcmp( nodes[pat].data, + stringData( kid->tree->tokdata ), nodes[pat].length ) != 0 ) + return false; + } + + /* No failure, all okay. */ + if ( nodes[pat].bindId > 0 ) { + #ifdef COLM_LOG_MATCH + if ( colm_log_match ) { + cerr << "bindId: " << nodes[pat].bindId << endl; + } + #endif + bindings[nodes[pat].bindId] = kid->tree; + } + + /* If we didn't match a terminal duplicate of a nonterm then check + * down the children. */ + if ( !nodes[pat].stop ) { + /* Check for failure down child branch. */ + int childCheck = matchPattern( bindings, prg, + nodes[pat].child, treeChild( prg, kid->tree ), true ); + if ( ! childCheck ) + return false; + } + + /* If checking next, then look for failure there. */ + if ( checkNext ) { + int nextCheck = matchPattern( bindings, prg, + nodes[pat].next, kid->next, true ); + if ( ! nextCheck ) + return false; + } + + return true; + } + } + else if ( pat == -1 && kid == 0 ) { + /* Both null is a match. */ + return 1; + } + + return false; +} + + +long cmpTree( Program *prg, const Tree *tree1, const Tree *tree2 ) +{ + long cmpres = 0; + if ( tree1 == 0 ) { + if ( tree2 == 0 ) + return 0; + else + return -1; + } + else if ( tree2 == 0 ) + return 1; + else if ( tree1->id < tree2->id ) + return -1; + else if ( tree1->id > tree2->id ) + return 1; + else if ( tree1->id == LEL_ID_PTR ) { + if ( ((Pointer*)tree1)->value < ((Pointer*)tree2)->value ) + return -1; + else if ( ((Pointer*)tree1)->value > ((Pointer*)tree2)->value ) + return 1; + } + else if ( tree1->id == LEL_ID_INT ) { + if ( ((Int*)tree1)->value < ((Int*)tree2)->value ) + return -1; + else if ( ((Int*)tree1)->value > ((Int*)tree2)->value ) + return 1; + } + else if ( tree1->id == LEL_ID_STR ) { + cmpres = cmpString( ((Str*)tree1)->value, ((Str*)tree2)->value ); + if ( cmpres != 0 ) + return cmpres; + } + else { + if ( tree1->tokdata == 0 && tree2->tokdata != 0 ) + return -1; + else if ( tree1->tokdata != 0 && tree2->tokdata == 0 ) + return 1; + else if ( tree1->tokdata != 0 && tree2->tokdata != 0 ) { + cmpres = cmpString( tree1->tokdata, tree2->tokdata ); + if ( cmpres != 0 ) + return cmpres; + } + } + + Kid *kid1 = treeChild( prg, tree1 ); + Kid *kid2 = treeChild( prg, tree2 ); + + while ( true ) { + if ( kid1 == 0 && kid2 == 0 ) + return 0; + else if ( kid1 == 0 && kid2 != 0 ) + return -1; + else if ( kid1 != 0 && kid2 == 0 ) + return 1; + else { + cmpres = cmpTree( prg, kid1->tree, kid2->tree ); + if ( cmpres != 0 ) + return cmpres; + } + kid1 = kid1->next; + kid2 = kid2->next; + } +} + + +void splitRef( Tree ***psp, Program *prg, Ref *fromRef ) +{ + /* Go up the chain of kids, turing the pointers down. */ + Ref *last = 0, *ref = fromRef, *next = 0; + while ( ref->next != 0 ) { + next = ref->next; + ref->next = last; + last = ref; + ref = next; + } + ref->next = last; + + /* Now traverse the list, which goes down. */ + while ( ref != 0 ) { + if ( ref->kid->tree->refs > 1 ) { + #ifdef COLM_LOG_BYTECODE + if ( colm_log_bytecode ) { + cerr << "splitting tree: " << ref->kid << " refs: " << + ref->kid->tree->refs << endl; + } + #endif + + Ref *nextDown = ref->next; + while ( nextDown != 0 && nextDown->kid == ref->kid ) + nextDown = nextDown->next; + + Kid *oldNextKidDown = nextDown != 0 ? nextDown->kid : 0; + Kid *newNextKidDown = 0; + + Tree *newTree = copyTree( prg, ref->kid->tree, + oldNextKidDown, &newNextKidDown ); + treeUpref( newTree ); + + /* Downref the original. Don't need to consider freeing because + * refs were > 1. */ + ref->kid->tree->refs -= 1; + + while ( ref != 0 && ref != nextDown ) { + next = ref->next; + ref->next = 0; + + ref->kid->tree = newTree; + ref = next; + } + + /* Correct kid pointers down from ref. */ + while ( nextDown != 0 && nextDown->kid == oldNextKidDown ) { + nextDown->kid = newNextKidDown; + nextDown = nextDown->next; + } + } + else { + /* Reset the list as we go down. */ + next = ref->next; + ref->next = 0; + ref = next; + } + } +} + +void splitIterCur( Tree ***psp, Program *prg, TreeIter *iter ) +{ + if ( iter->ref.kid == 0 ) + return; + + splitRef( psp, prg, &iter->ref ); +} + +Tree *setListMem( List *list, Half field, Tree *value ) +{ + assert( list->refs == 1 ); + if ( value != 0 ) + assert( value->refs >= 1 ); + + Tree *existing = 0; + switch ( field ) { + case 0: + existing = list->head->value; + list->head->value = value; + break; + case 1: + existing = list->tail->value; + list->tail->value = value; + break; + default: + assert( false ); + break; + } + return existing; +} + +TreePair mapRemove( Program *prg, Map *map, Tree *key ) +{ + MapEl *mapEl = mapImplFind( prg, map, key ); + TreePair result; + if ( mapEl != 0 ) { + mapDetach( prg, map, mapEl ); + result.key = mapEl->key; + result.val = mapEl->tree; + mapElFree( prg, mapEl ); + } + + return result; +} + +Tree *mapUnstore( Program *prg, Map *map, Tree *key, Tree *existing ) +{ + Tree *stored = 0; + if ( existing == 0 ) { + MapEl *mapEl = mapDetachByKey( prg, map, key ); + stored = mapEl->tree; + mapElFree( prg, mapEl ); + } + else { + MapEl *mapEl = mapImplFind( prg, map, key ); + stored = mapEl->tree; + mapEl->tree = existing; + } + return stored; +} + +Tree *mapFind( Program *prg, Map *map, Tree *key ) +{ + MapEl *mapEl = mapImplFind( prg, map, key ); + return mapEl == 0 ? 0 : mapEl->tree; +} + +long mapLength( Map *map ) +{ + return map->treeSize; +} + +void listAppend2( Program *prg, List *list, Tree *val ) +{ + assert( list->refs == 1 ); + if ( val != 0 ) + assert( val->refs >= 1 ); + ListEl *listEl = listElAllocate( prg ); + listEl->value = val; + listAppend( list, listEl ); +} + +Tree *listRemoveEnd( Program *prg, List *list ) +{ + Tree *tree = list->tail->value; + listElFree( prg, listDetachLast( list ) ); + return tree; +} + +Tree *getListMem( List *list, Word field ) +{ + Tree *result = 0; + switch ( field ) { + case 0: + result = list->head->value; + break; + case 1: + result = list->tail->value; + break; + default: + assert( false ); + break; + } + return result; +} + +Tree *getListMemSplit( Program *prg, List *list, Word field ) +{ + Tree *sv = 0; + switch ( field ) { + case 0: + sv = splitTree( prg, list->head->value ); + list->head->value = sv; + break; + case 1: + sv = splitTree( prg, list->tail->value ); + list->tail->value = sv; + break; + default: + assert( false ); + break; + } + return sv; +} + + +int mapInsert( Program *prg, Map *map, Tree *key, Tree *element ) +{ + MapEl *mapEl = mapInsertKey( prg, map, key, 0 ); + + if ( mapEl != 0 ) { + mapEl->tree = element; + return true; + } + + return false; +} + +void mapUnremove( Program *prg, Map *map, Tree *key, Tree *element ) +{ + MapEl *mapEl = mapInsertKey( prg, map, key, 0 ); + assert( mapEl != 0 ); + mapEl->tree = element; +} + +Tree *mapUninsert( Program *prg, Map *map, Tree *key ) +{ + MapEl *el = mapDetachByKey( prg, map, key ); + Tree *val = el->tree; + mapElFree( prg, el ); + return val; +} + +Tree *mapStore( Program *prg, Map *map, Tree *key, Tree *element ) +{ + Tree *oldTree = 0; + MapEl *elInTree = 0; + MapEl *mapEl = mapInsertKey( prg, map, key, &elInTree ); + + if ( mapEl != 0 ) + mapEl->tree = element; + else { + /* Element with key exists. Overwriting the value. */ + oldTree = elInTree->tree; + elInTree->tree = element; + } + + return oldTree; +} + +void iterFind( Program *prg, Tree ***psp, TreeIter *iter, int tryFirst ) +{ + int anyTree = iter->searchId == prg->rtd->anyId; + Tree **top = iter->stackRoot; + Kid *child; + Tree **sp = *psp; + +rec_call: + if ( tryFirst && ( iter->ref.kid->tree->id == iter->searchId || anyTree ) ) { + *psp = sp; + return; + } + else { + child = treeChild( prg, iter->ref.kid->tree ); + if ( child != 0 ) { + vm_push( (SW) iter->ref.next ); + vm_push( (SW) iter->ref.kid ); + iter->ref.kid = child; + iter->ref.next = (Ref*)vm_ptop(); + while ( iter->ref.kid != 0 ) { + tryFirst = true; + goto rec_call; + rec_return: + iter->ref.kid = iter->ref.kid->next; + } + iter->ref.kid = (Kid*)vm_pop(); + iter->ref.next = (Ref*)vm_pop(); + } + } + + if ( top != vm_ptop() ) + goto rec_return; + + iter->ref.kid = 0; + *psp = sp; +} + +Tree *treeIterAdvance( Program *prg, Tree ***psp, TreeIter *iter ) +{ + assert( iter->stackSize == iter->stackRoot - *psp ); + + if ( iter->ref.kid == 0 ) { + /* Kid is zero, start from the root. */ + iter->ref = iter->rootRef; + iterFind( prg, psp, iter, true ); + } + else { + /* Have a previous item, continue searching from there. */ + iterFind( prg, psp, iter, false ); + } + + iter->stackSize = iter->stackRoot - *psp; + + return (iter->ref.kid ? prg->trueVal : prg->falseVal ); +} + +Tree *treeIterNextChild( Program *prg, Tree ***psp, TreeIter *iter ) +{ + Tree **sp = *psp; + assert( iter->stackSize == iter->stackRoot - vm_ptop() ); + Kid *kid = 0; + + if ( iter->ref.kid == 0 ) { + /* Kid is zero, start from the first child. */ + Kid *child = treeChild( prg, iter->rootRef.kid->tree ); + + if ( child == 0 ) + iter->ref.next = 0; + else { + /* Make a reference to the root. */ + vm_push( (SW) iter->rootRef.next ); + vm_push( (SW) iter->rootRef.kid ); + iter->ref.next = (Ref*)vm_ptop(); + + kid = child; + } + } + else { + /* Start at next. */ + kid = iter->ref.kid->next; + } + + if ( iter->searchId != prg->rtd->anyId ) { + /* Have a previous item, go to the next sibling. */ + while ( kid != 0 && kid->tree->id != iter->searchId ) + kid = kid->next; + } + + iter->ref.kid = kid; + iter->stackSize = iter->stackRoot - vm_ptop(); + *psp = sp; + return ( iter->ref.kid ? prg->trueVal : prg->falseVal ); +} + +Tree *treeRevIterPrevChild( Program *prg, Tree ***psp, RevTreeIter *iter ) +{ + Tree **sp = *psp; + + assert( iter->stackSize == iter->stackRoot - vm_ptop() ); + + if ( iter->kidAtYield != iter->ref.kid ) { + /* Need to reload the kids. */ + Kid *kid = treeChild( prg, iter->rootRef.kid->tree ); + Kid **dst = (Kid**)iter->stackRoot - 1; + while ( kid != 0 ) { + *dst-- = kid; + kid = kid->next; + } + } + + if ( iter->ref.kid == 0 ) + iter->cur = (Kid**)iter->stackRoot - iter->children; + else + iter->cur += 1; + + if ( iter->searchId != prg->rtd->anyId ) { + /* Have a previous item, go to the next sibling. */ + while ( iter->cur != (Kid**)iter->stackRoot && (*iter->cur)->tree->id != iter->searchId ) + iter->cur += 1; + } + + if ( iter->cur == (Kid**)iter->stackRoot ) { + iter->ref.next = 0; + iter->ref.kid = 0; + } + else { + iter->ref.next = &iter->rootRef; + iter->ref.kid = *iter->cur; + } + + /* We will use this to detect a split above the iterated tree. */ + iter->kidAtYield = iter->ref.kid; + + iter->stackSize = iter->stackRoot - vm_ptop(); + + *psp = sp; + + return (iter->ref.kid ? prg->trueVal : prg->falseVal ); +} + +void iterFindRepeat( Program *prg, Tree ***psp, TreeIter *iter, int tryFirst ) +{ + Tree **sp = *psp; + int anyTree = iter->searchId == prg->rtd->anyId; + Tree **top = iter->stackRoot; + Kid *child; + +rec_call: + if ( tryFirst && ( iter->ref.kid->tree->id == iter->searchId || anyTree ) ) { + *psp = sp; + return; + } + else { + /* The repeat iterator is just like the normal top-down-left-right, + * execept it only goes into the children of a node if the node is the + * root of the iteration, or if does not have any neighbours to the + * right. */ + if ( top == vm_ptop() || iter->ref.kid->next == 0 ) { + child = treeChild( prg, iter->ref.kid->tree ); + if ( child != 0 ) { + vm_push( (SW) iter->ref.next ); + vm_push( (SW) iter->ref.kid ); + iter->ref.kid = child; + iter->ref.next = (Ref*)vm_ptop(); + while ( iter->ref.kid != 0 ) { + tryFirst = true; + goto rec_call; + rec_return: + iter->ref.kid = iter->ref.kid->next; + } + iter->ref.kid = (Kid*)vm_pop(); + iter->ref.next = (Ref*)vm_pop(); + } + } + } + + if ( top != vm_ptop() ) + goto rec_return; + + iter->ref.kid = 0; + *psp = sp; +} + +Tree *treeIterNextRepeat( Program *prg, Tree ***psp, TreeIter *iter ) +{ + assert( iter->stackSize == iter->stackRoot - *psp ); + + if ( iter->ref.kid == 0 ) { + /* Kid is zero, start from the root. */ + iter->ref = iter->rootRef; + iterFindRepeat( prg, psp, iter, true ); + } + else { + /* Have a previous item, continue searching from there. */ + iterFindRepeat( prg, psp, iter, false ); + } + + iter->stackSize = iter->stackRoot - *psp; + + return (iter->ref.kid ? prg->trueVal : prg->falseVal ); +} + +void iterFindRevRepeat( Program *prg, Tree ***psp, TreeIter *iter, int tryFirst ) +{ + Tree **sp = *psp; + int anyTree = iter->searchId == prg->rtd->anyId; + Tree **top = iter->stackRoot; + Kid *child; + + if ( tryFirst ) { + while ( true ) { + if ( top == vm_ptop() || iter->ref.kid->next == 0 ) { + child = treeChild( prg, iter->ref.kid->tree ); + + if ( child == 0 ) + break; + vm_push( (SW) iter->ref.next ); + vm_push( (SW) iter->ref.kid ); + iter->ref.kid = child; + iter->ref.next = (Ref*)vm_ptop(); + } + else { + /* Not the top and not there is a next, go over to it. */ + iter->ref.kid = iter->ref.kid->next; + } + } + + goto first; + } + + while ( true ) { + if ( top == vm_ptop() ) { + iter->ref.kid = 0; + return; + } + + if ( iter->ref.kid->next == 0 ) { + /* Go up one and then down. Remember we can't use iter->ref.next + * because the chain may have been split, setting it null (to + * prevent repeated walks up). */ + Ref *ref = (Ref*)vm_ptop(); + iter->ref.kid = ref->kid->tree->child; + } + else { + iter->ref.kid = (Kid*)vm_pop(); + iter->ref.next = (Ref*)vm_pop(); + } +first: + if ( iter->ref.kid->tree->id == iter->searchId || anyTree ) { + *psp = sp; + return; + } + } + *psp = sp; + return; +} + + +Tree *treeIterPrevRepeat( Program *prg, Tree ***psp, TreeIter *iter ) +{ + assert( iter->stackSize == iter->stackRoot - *psp ); + + if ( iter->ref.kid == 0 ) { + /* Kid is zero, start from the root. */ + iter->ref = iter->rootRef; + iterFindRevRepeat( prg, psp, iter, true ); + } + else { + /* Have a previous item, continue searching from there. */ + iterFindRevRepeat( prg, psp, iter, false ); + } + + iter->stackSize = iter->stackRoot - *psp; + + return (iter->ref.kid ? prg->trueVal : prg->falseVal ); +} + +Tree *treeSearch( Program *prg, Kid *kid, long id ) +{ + /* This node the one? */ + if ( kid->tree->id == id ) + return kid->tree; + + Tree *res = 0; + + /* Search children. */ + Kid *child = treeChild( prg, kid->tree ); + if ( child != 0 ) + res = treeSearch( prg, child, id ); + + /* Search siblings. */ + if ( res == 0 && kid->next != 0 ) + res = treeSearch( prg, kid->next, id ); + + return res; +} + +Tree *treeSearch2( Program *prg, Tree *tree, long id ) +{ + Tree *res = 0; + if ( tree->id == id ) + res = tree; + else { + Kid *child = treeChild( prg, tree ); + if ( child != 0 ) + res = treeSearch( prg, child, id ); + } + return res; +} + +void xmlEscapeData( FILE *out, const char *data, long len ) +{ + int i; + for ( i = 0; i < len; i++ ) { + if ( data[i] == '<' ) + fprintf( out, "<" ); + else if ( data[i] == '>' ) + fprintf( out, ">" ); + else if ( data[i] == '&' ) + fprintf( out, "&" ); + else if ( 32 <= data[i] && data[i] <= 126 ) + fprintf( out, "%c", data[i] ); + else + fprintf( out, "&#%u;", ((unsigned)data[i]) ); + } +} + +void printXmlKid( FILE *out, Tree **sp, Program *prg, Kid *kid, int commAttr, int depth ); + +/* Might be a good idea to include this in the printXmlKid function since + * it is recursive and can eat up stac, however it's probably not a big deal + * since the additional stack depth is only caused for nonterminals that are + * ignored. */ +void printXmlIgnoreList( FILE *out, Tree **sp, Program *prg, Tree *tree, long depth ) +{ + Kid *ignore = treeIgnore( prg, tree ); + while ( ignore != 0 ) { + printXmlKid( out, sp, prg, ignore, true, depth ); + ignore = ignore->next; + } +} + +void printXmlKid( FILE *out, Tree **sp, Program *prg, Kid *kid, int commAttr, int depth ) +{ + Kid *child; + Tree **root = vm_ptop(); + long i, objectLength; + LangElInfo *lelInfo = prg->rtd->lelInfo; + + long kidNum = 0;; + +rec_call: + + if ( kid->tree == 0 ) { + for ( i = 0; i < depth; i++ ) + fprintf( out, " " ); + + fprintf( out, "NIL\n" ); + } + else { + /* First print the ignore tokens. */ + if ( commAttr ) + printXmlIgnoreList( out, sp, prg, kid->tree, depth ); + + for ( i = 0; i < depth; i++ ) + fprintf( out, " " ); + + /* Open the tag. Afterwards we will either print data underneath it or + * we will close it off immediately. */ + fprintf( out, "<%s", lelInfo[kid->tree->id].name ); + + /* If this is an attribute then give the node an attribute number. */ + if ( vm_ptop() != root ) { + objectLength = lelInfo[((Kid*)vm_top())->tree->id].objectLength; + if ( kidNum < objectLength ) + fprintf( out, " an=\"%ld\"", kidNum ); + } + + objectLength = lelInfo[kid->tree->id].objectLength; + child = treeChild( prg, kid->tree ); + if ( (commAttr && objectLength > 0) || child != 0 ) { + fprintf( out, ">\n" ); + vm_push( (SW) kidNum ); + vm_push( (SW) kid ); + + kidNum = 0; + kid = kid->tree->child; + + /* Skip over attributes if not printing comments and attributes. */ + if ( ! commAttr ) + kid = child; + + while ( kid != 0 ) { + /* FIXME: I don't think we need this check for ignore any more. */ + if ( kid->tree == 0 || !lelInfo[kid->tree->id].ignore ) { + depth++; + goto rec_call; + rec_return: + depth--; + } + + kid = kid->next; + kidNum += 1; + + /* If the parent kid is a repeat then skip this node and go + * right to the first child (repeated item). */ + if ( lelInfo[((Kid*)vm_top())->tree->id].repeat ) + kid = kid->tree->child; + + /* If we have a kid and the parent is a list (recursive prod of + * list) then go right to the first child. */ + if ( kid != 0 && lelInfo[((Kid*)vm_top())->tree->id].list ) + kid = kid->tree->child; + } + + kid = (Kid*) vm_pop(); + kidNum = (long) vm_pop(); + + for ( i = 0; i < depth; i++ ) + fprintf( out, " " ); + fprintf( out, "\n", lelInfo[kid->tree->id].name ); + } + else if ( kid->tree->id == LEL_ID_PTR ) { + fprintf( out, ">%p\n", (void*)((Pointer*)kid->tree)->value, + lelInfo[kid->tree->id].name ); + } + else if ( kid->tree->id == LEL_ID_BOOL ) { + if ( ((Int*)kid->tree)->value ) + fprintf( out, ">truefalse\n", lelInfo[kid->tree->id].name ); + } + else if ( kid->tree->id == LEL_ID_INT ) { + fprintf( out, ">%ld\n", ((Int*)kid->tree)->value, + lelInfo[kid->tree->id].name ); + } + else if ( kid->tree->id == LEL_ID_STR ) { + Head *head = (Head*) ((Str*)kid->tree)->value; + + fprintf( out, ">" ); + xmlEscapeData( out, (char*)(head->data), head->length ); + fprintf( out, "\n", lelInfo[kid->tree->id].name ); + } + else if ( 0 < kid->tree->id && kid->tree->id < prg->rtd->firstNonTermId && + kid->tree->tokdata != 0 && + stringLength( kid->tree->tokdata ) > 0 && + !lelInfo[kid->tree->id].literal ) + { + fprintf( out, ">" ); + xmlEscapeData( out, stringData( kid->tree->tokdata ), + stringLength( kid->tree->tokdata ) ); + fprintf( out, "\n", lelInfo[kid->tree->id].name ); + } + else { + fprintf( out, "/>\n" ); + } + } + + if ( vm_ptop() != root ) + goto rec_return; +} + +void printXmlTree( Tree **sp, Program *prg, Tree *tree, int commAttr ) +{ + Kid kid; + kid.tree = tree; + kid.next = 0; + printXmlKid( stdout, sp, prg, &kid, commAttr, 0 ); +} + +void initStrCollect( StrCollect *collect ) +{ + collect->data = (char*) malloc( BUFFER_INITIAL_SIZE ); + collect->allocated = BUFFER_INITIAL_SIZE; + collect->length = 0; +} + +void strCollectDestroy( StrCollect *collect ) +{ + free( collect->data ); +} + +void strCollectAppend( StrCollect *collect, const char *data, long len ) +{ + long newLen = collect->length + len; + if ( newLen > collect->allocated ) { + collect->allocated *= newLen * 2; + collect->data = (char*) realloc( collect->data, collect->allocated ); + } + memcpy( collect->data + collect->length, data, len ); + collect->length += len; +} + +void strCollectClear( StrCollect *collect ) +{ + collect->length = 0; +} + +#define INT_SZ 32 + +void printStr( StrCollect *collect, Head *str ) +{ + strCollectAppend( collect, (char*)(str->data), str->length ); +} + +/* Note that this function causes recursion, thought it is not a big + * deal since the recursion it is only caused by nonterminals that are ignored. */ +void printIgnoreList( StrCollect *collect, Tree **sp, Program *prg, Tree *tree ) +{ + Kid *ignore = treeIgnore( prg, tree ); + + /* Record the root of the stack and push everything. */ + Tree **root = vm_ptop(); + while ( ignore != 0 ) { + vm_push( (SW)ignore ); + ignore = ignore->next; + } + + /* Pop them off and print. */ + while ( vm_ptop() != root ) { + ignore = (Kid*) vm_pop(); + printTree( collect, sp, prg, ignore->tree ); + } +} + +void printKid( StrCollect *collect, Tree **sp, Program *prg, Kid *kid, int printIgnore ) +{ + Tree **root = vm_ptop(); + Kid *child; + +rec_call: + /* If not currently skipping ignore data, then print it. Ignore data can + * be associated with terminals and nonterminals. */ + if ( printIgnore && treeIgnore( prg, kid->tree ) != 0 ) { + /* Ignorelists are reversed. */ + printIgnoreList( collect, sp, prg, kid->tree ); + printIgnore = false; + } + + if ( kid->tree->id < prg->rtd->firstNonTermId ) { + /* Always turn on ignore printing when we get to a token. */ + printIgnore = true; + + if ( kid->tree->id == LEL_ID_INT ) { + char buf[INT_SZ]; + sprintf( buf, "%ld", ((Int*)kid->tree)->value ); + strCollectAppend( collect, buf, strlen(buf) ); + } + else if ( kid->tree->id == LEL_ID_BOOL ) { + if ( ((Int*)kid->tree)->value ) + strCollectAppend( collect, "true", 4 ); + else + strCollectAppend( collect, "false", 5 ); + } + else if ( kid->tree->id == LEL_ID_PTR ) { + char buf[INT_SZ]; + strCollectAppend( collect, "#", 1 ); + sprintf( buf, "%p", (void*) ((Pointer*)kid->tree)->value ); + strCollectAppend( collect, buf, strlen(buf) ); + } + else if ( kid->tree->id == LEL_ID_STR ) { + printStr( collect, ((Str*)kid->tree)->value ); + } + else if ( kid->tree->id == LEL_ID_STREAM ) { + char buf[INT_SZ]; + strCollectAppend( collect, "#", 1 ); + sprintf( buf, "%p", (void*) ((Stream*)kid->tree)->file ); + strCollectAppend( collect, buf, strlen(buf) ); + } + else if ( kid->tree->tokdata != 0 && + stringLength( kid->tree->tokdata ) > 0 ) + { + strCollectAppend( collect, stringData( kid->tree->tokdata ), + stringLength( kid->tree->tokdata ) ); + } + } + else { + /* Non-terminal. */ + child = treeChild( prg, kid->tree ); + if ( child != 0 ) { + vm_push( (SW)kid ); + kid = child; + while ( kid != 0 ) { + goto rec_call; + rec_return: + kid = kid->next; + } + kid = (Kid*)vm_pop(); + } + } + + if ( vm_ptop() != root ) + goto rec_return; +} + +void printTree( StrCollect *collect, Tree **sp, Program *prg, Tree *tree ) +{ + if ( tree == 0 ) + strCollectAppend( collect, "NIL", 3 ); + else { + Kid kid; + kid.tree = tree; + kid.next = 0; + printKid( collect, sp, prg, &kid, false ); + } +} + + diff --git a/colm/tree.h b/colm/tree.h index 29029ddb..e4c49dfd 100644 --- a/colm/tree.h +++ b/colm/tree.h @@ -28,8 +28,6 @@ extern "C" { typedef struct _TreePair { -// TreePair() : key(0), val(0) {} - Tree *key; Tree *val; } TreePair; diff --git a/colm/tree2.c b/colm/tree2.c deleted file mode 100644 index b5c46526..00000000 --- a/colm/tree2.c +++ /dev/null @@ -1,2033 +0,0 @@ -/* - * Copyright 2008 Adrian Thurston - */ - -/* This file is part of Colm. - * - * Colm is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * Colm is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Colm; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "pdarun.h" -#include "tree.h" -#include "pool.h" -#include "bytecode2.h" -#include "debug.h" -#include "map.h" -#include -#include -#include - -#define true 1 -#define false 0 - -#define BUFFER_INITIAL_SIZE 4096 - -void initUserIter( UserIter *userIter, Tree **stackRoot, long argSize, long searchId ) -{ - userIter->stackRoot = stackRoot; - userIter->argSize = argSize; - userIter->stackSize = 0; - userIter->resume = 0; - userIter->frame = 0; - userIter->searchId = searchId; - - userIter->ref.kid = 0; - userIter->ref.next = 0; -} - -Kid *allocAttrs( Program *prg, long length ) -{ - Kid *cur = 0; - long i; - for ( i = 0; i < length; i++ ) { - Kid *next = cur; - cur = kidAllocate( prg ); - cur->next = next; - } - return cur; -} - -void freeAttrs( Program *prg, Kid *attrs ) -{ - Kid *cur = attrs; - while ( cur != 0 ) { - Kid *next = cur->next; - kidFree( prg, cur ); - cur = next; - } -} - -void setAttr( Tree *tree, long pos, Tree *val ) -{ - long i; - Kid *kid = tree->child; - - if ( tree->flags & AF_LEFT_IGNORE ) - kid = kid->next; - if ( tree->flags & AF_RIGHT_IGNORE ) - kid = kid->next; - - for ( i = 0; i < pos; i++ ) - kid = kid->next; - kid->tree = val; -} - -Tree *getAttr( Tree *tree, long pos ) -{ - long i; - Kid *kid = tree->child; - - if ( tree->flags & AF_LEFT_IGNORE ) - kid = kid->next; - if ( tree->flags & AF_RIGHT_IGNORE ) - kid = kid->next; - - for ( i = 0; i < pos; i++ ) - kid = kid->next; - return kid->tree; -} - -Kid *getAttrKid( Tree *tree, long pos ) -{ - long i; - Kid *kid = tree->child; - - if ( tree->flags & AF_LEFT_IGNORE ) - kid = kid->next; - if ( tree->flags & AF_RIGHT_IGNORE ) - kid = kid->next; - - for ( i = 0; i < pos; i++ ) - kid = kid->next; - return kid; -} - -Kid *kidListConcat( Kid *list1, Kid *list2 ) -{ - if ( list1 == 0 ) - return list2; - else if ( list2 == 0 ) - return list1; - - Kid *dest = list1; - while ( dest->next != 0 ) - dest = dest->next; - dest->next = list2; - return list1; -} - - -Stream *openStreamFile( Program *prg, FILE *file ) -{ - Stream *res = (Stream*)mapElAllocate( prg ); - res->id = LEL_ID_STREAM; - res->file = file; - res->in = newInputStreamFile( file ); - initInputStream( res->in ); - return res; -} - -Stream *openStreamFd( Program *prg, long fd ) -{ - Stream *res = (Stream*)mapElAllocate( prg ); - res->id = LEL_ID_STREAM; - res->in = newInputStreamFd( fd ); - initInputStream( res->in ); - return res; -} - -Stream *openFile( Program *prg, Tree *name, Tree *mode ) -{ - Head *headName = ((Str*)name)->value; - Head *headMode = ((Str*)mode)->value; - - const char *givenMode = stringData(headMode); - const char *fopenMode = 0; - if ( memcmp( givenMode, "r", stringLength(headMode) ) == 0 ) - fopenMode = "rb"; - else if ( memcmp( givenMode, "w", stringLength(headMode) ) == 0 ) - fopenMode = "wb"; - else { - fatal( "unknown file open mode: %s\n", givenMode ); - } - - /* Need to make a C-string (null terminated). */ - char *fileName = (char*)malloc(stringLength(headName)+1); - memcpy( fileName, stringData(headName), stringLength(headName) ); - fileName[stringLength(headName)] = 0; - FILE *file = fopen( fileName, fopenMode ); - free(fileName); - return openStreamFile( prg, file ); -} - -Tree *constructInteger( Program *prg, long i ) -{ - Int *integer = (Int*) treeAllocate( prg ); - integer->id = LEL_ID_INT; - integer->value = i; - - return (Tree*)integer; -} - -Tree *constructString( Program *prg, Head *s ) -{ - Str *str = (Str*) treeAllocate( prg ); - str->id = LEL_ID_STR; - str->value = s; - - return (Tree*)str; -} - -Tree *constructPointer( Program *prg, Tree *tree ) -{ - Kid *kid = kidAllocate( prg ); - kid->tree = tree; - kid->next = prg->heap; - prg->heap = kid; - - Pointer *pointer = (Pointer*) treeAllocate( prg ); - pointer->id = LEL_ID_PTR; - pointer->value = kid; - - return (Tree*)pointer; -} - -Tree *constructTerm( Program *prg, Word id, Head *tokdata ) -{ - LangElInfo *lelInfo = prg->rtd->lelInfo; - - Tree *tree = treeAllocate( prg ); - tree->id = id; - tree->refs = 0; - tree->tokdata = tokdata; - - int objectLength = lelInfo[tree->id].objectLength; - tree->child = allocAttrs( prg, objectLength ); - - return tree; -} - -Kid *constructReplacementKid( Tree **bindings, Program *prg, Kid *prev, long pat ); - -Kid *constructIgnoreList( Program *prg, long pat ) -{ - PatReplNode *nodes = prg->rtd->patReplNodes; - long ignore = nodes[pat].ignore; - - Kid *first = 0, *last = 0; - while ( ignore >= 0 ) { - Head *ignoreData = stringAllocPointer( prg, nodes[ignore].data, nodes[ignore].length ); - - Tree *ignTree = treeAllocate( prg ); - ignTree->refs = 1; - ignTree->id = nodes[ignore].id; - ignTree->tokdata = ignoreData; - - Kid *ignKid = kidAllocate( prg ); - ignKid->tree = ignTree; - ignKid->next = 0; - - if ( last == 0 ) - first = ignKid; - else - last->next = ignKid; - - ignore = nodes[ignore].next; - last = ignKid; - } - - return first; -} - -/* Returns an uprefed tree. Saves us having to downref and bindings to zero to - * return a zero-ref tree. */ -Tree *constructReplacementTree( Tree **bindings, Program *prg, long pat ) -{ - PatReplNode *nodes = prg->rtd->patReplNodes; - LangElInfo *lelInfo = prg->rtd->lelInfo; - Tree *tree = 0; - - if ( nodes[pat].bindId > 0 ) { - /* All bindings have been uprefed. */ - tree = bindings[nodes[pat].bindId]; - - long ignore = nodes[pat].ignore; - if ( ignore >= 0 ) { - Kid *ignore = constructIgnoreList( prg, pat ); - - tree = splitTree( prg, tree ); - - Kid *ignoreHead = kidAllocate( prg ); - ignoreHead->next = tree->child; - tree->child = ignoreHead; - - ignoreHead->tree = (Tree*) ignore; - tree->flags |= AF_LEFT_IGNORE; - } - } - else { - tree = treeAllocate( prg ); - tree->id = nodes[pat].id; - tree->refs = 1; - tree->tokdata = nodes[pat].length == 0 ? 0 : - stringAllocPointer( prg, - nodes[pat].data, nodes[pat].length ); - - int objectLength = lelInfo[tree->id].objectLength; - - Kid *attrs = allocAttrs( prg, objectLength ); - Kid *ignore = constructIgnoreList( prg, pat ); - Kid *child = constructReplacementKid( bindings, prg, - 0, nodes[pat].child ); - - tree->child = kidListConcat( attrs, child ); - if ( ignore != 0 ) { - Kid *ignoreHead = kidAllocate( prg ); - ignoreHead->next = tree->child; - tree->child = ignoreHead; - - ignoreHead->tree = (Tree*) ignore; - tree->flags |= AF_LEFT_IGNORE; - } - - int i; - for ( i = 0; i < lelInfo[tree->id].numCaptureAttr; i++ ) { - long ci = pat+1+i; - CaptureAttr *ca = prg->rtd->captureAttr + lelInfo[tree->id].captureAttr + i; - Tree *attr = treeAllocate( prg ); - attr->id = nodes[ci].id; - attr->refs = 1; - attr->tokdata = nodes[ci].length == 0 ? 0 : - stringAllocPointer( prg, - nodes[ci].data, nodes[ci].length ); - - setAttr( tree, ca->offset, attr ); - } - } - - return tree; -} - -Kid *constructReplacementKid( Tree **bindings, Program *prg, Kid *prev, long pat ) -{ - PatReplNode *nodes = prg->rtd->patReplNodes; - Kid *kid = 0; - - if ( pat != -1 ) { - kid = kidAllocate( prg ); - kid->tree = constructReplacementTree( bindings, prg, pat ); - - /* Recurse down next. */ - Kid *next = constructReplacementKid( bindings, prg, - kid, nodes[pat].next ); - - kid->next = next; - } - - return kid; -} - -Tree *makeToken2( Tree **root, Program *prg, long nargs ) -{ - Tree **const sp = root; - Tree **base = vm_ptop() + nargs; - - Int *idInt = (Int*)base[-1]; - Str *textStr = (Str*)base[-2]; - - long id = idInt->value; - Head *tokdata = stringCopy( prg, textStr->value ); - - LangElInfo *lelInfo = prg->rtd->lelInfo; - Tree *tree; - - if ( lelInfo[id].ignore ) { - tree = treeAllocate( prg ); - tree->refs = 1; - tree->id = id; - tree->tokdata = tokdata; - } - else { - long objectLength = lelInfo[id].objectLength; - Kid *attrs = allocAttrs( prg, objectLength ); - - tree = treeAllocate( prg ); - tree->id = id; - tree->refs = 1; - tree->tokdata = tokdata; - - tree->child = attrs; - - assert( nargs-2 <= objectLength ); - long id; - for ( id = 0; id < nargs-2; id++ ) { - setAttr( tree, id, base[-3-id] ); - treeUpref( getAttr( tree, id) ); - } - } - return tree; -} - -Tree *makeTree( Tree **root, Program *prg, long nargs ) -{ - Tree **const sp = root; - Tree **base = vm_ptop() + nargs; - - Int *idInt = (Int*)base[-1]; - - long id = idInt->value; - LangElInfo *lelInfo = prg->rtd->lelInfo; - - Tree *tree = treeAllocate( prg ); - tree->id = id; - tree->refs = 1; - - long objectLength = lelInfo[id].objectLength; - Kid *attrs = allocAttrs( prg, objectLength ); - - Kid *last = 0, *child = 0; - for ( id = 0; id < nargs-1; id++ ) { - Kid *kid = kidAllocate( prg ); - kid->tree = base[-2-id]; - treeUpref( kid->tree ); - - if ( last == 0 ) - child = kid; - else - last->next = kid; - - last = kid; - } - - tree->child = kidListConcat( attrs, child ); - - return tree; -} - -int testFalse( Program *prg, Tree *tree ) -{ - int flse = ( - tree == 0 || - tree == prg->falseVal || - ( tree->id == LEL_ID_INT && ((Int*)tree)->value == 0 ) ); - return flse; -} - -void printStr2( FILE *out, Head *str ) -{ - fwrite( (char*)(str->data), str->length, 1, out ); -} - -/* Note that this function causes recursion, thought it is not a big - * deal since the recursion it is only caused by nonterminals that are ignored. */ -void printIgnoreList2( FILE *out, Tree **sp, Program *prg, Tree *tree ) -{ - Kid *ignore = treeIgnore( prg, tree ); - - /* Record the root of the stack and push everything. */ - Tree **root = vm_ptop(); - while ( ignore != 0 ) { - vm_push( (SW)ignore ); - ignore = ignore->next; - } - - /* Pop them off and print. */ - while ( vm_ptop() != root ) { - ignore = (Kid*) vm_pop(); - printTree2( out, sp, prg, ignore->tree ); - } -} - - -void printKid2( FILE *out, Tree **sp, Program *prg, Kid *kid, int printIgnore ) -{ - Tree **root = vm_ptop(); - Kid *child; - -rec_call: - /* If not currently skipping ignore data, then print it. Ignore data can - * be associated with terminals and nonterminals. */ - if ( printIgnore && treeIgnore( prg, kid->tree ) != 0 ) { - /* Ignorelists are reversed. */ - printIgnoreList2( out, sp, prg, kid->tree ); - printIgnore = false; - } - - if ( kid->tree->id < prg->rtd->firstNonTermId ) { - /* Always turn on ignore printing when we get to a token. */ - printIgnore = true; - - if ( kid->tree->id == LEL_ID_INT ) - fprintf( out, "%ld", ((Int*)kid->tree)->value ); - else if ( kid->tree->id == LEL_ID_BOOL ) { - if ( ((Int*)kid->tree)->value ) - fprintf( out, "true" ); - else - fprintf( out, "false" ); - } - else if ( kid->tree->id == LEL_ID_PTR ) - fprintf( out, "#%p", (void*) ((Pointer*)kid->tree)->value ); - else if ( kid->tree->id == LEL_ID_STR ) - printStr2( out, ((Str*)kid->tree)->value ); - else if ( kid->tree->id == LEL_ID_STREAM ) - fprintf( out, "#%p", ((Stream*)kid->tree)->file ); - else if ( kid->tree->tokdata != 0 && - stringLength( kid->tree->tokdata ) > 0 ) - { - fwrite( stringData( kid->tree->tokdata ), - stringLength( kid->tree->tokdata ), 1, out ); - } - } - else { - /* Non-terminal. */ - child = treeChild( prg, kid->tree ); - if ( child != 0 ) { - vm_push( (SW)kid ); - kid = child; - while ( kid != 0 ) { - goto rec_call; - rec_return: - kid = kid->next; - } - kid = (Kid*)vm_pop(); - } - } - - if ( vm_ptop() != root ) - goto rec_return; -} - -void printTree2( FILE *out, Tree **sp, Program *prg, Tree *tree ) -{ - if ( tree == 0 ) - fprintf( out, "NIL" ); - else { - Kid kid; - kid.tree = tree; - kid.next = 0; - printKid2( out, sp, prg, &kid, false ); - } -} - -void streamFree( Program *prg, Stream *s ) -{ - free( s->in ); - if ( s->file != 0 ) - fclose( s->file ); - mapElFree( prg, (MapEl*)s ); -} - -Kid *copyIgnoreList( Program *prg, Kid *ignoreHeader ) -{ - Kid *newHeader = kidAllocate( prg ); - Kid *last = 0, *ic = (Kid*)ignoreHeader->tree; - while ( ic != 0 ) { - Kid *newIc = kidAllocate( prg ); - - newIc->tree = ic->tree; - newIc->tree->refs += 1; - - /* List pointers. */ - if ( last == 0 ) - newHeader->tree = (Tree*)newIc; - else - last->next = newIc; - - ic = ic->next; - last = newIc; - } - return newHeader; -} - -/* New tree has zero ref. */ -Tree *copyRealTree( Program *prg, Tree *tree, Kid *oldNextDown, - Kid **newNextDown, int parseTree ) -{ - /* Need to keep a lookout for next down. If - * copying it, return the copy. */ - Tree *newTree; - if ( parseTree ) { - newTree = (Tree*) parseTreeAllocate( prg ); - newTree->flags |= AF_PARSE_TREE; - } - else { - newTree = treeAllocate( prg ); - } - - newTree->id = tree->id; - newTree->tokdata = stringCopy( prg, tree->tokdata ); - - /* Copy the child list. Start with ignores, then the list. */ - Kid *child = tree->child, *last = 0; - - /* Left ignores. */ - if ( tree->flags & AF_LEFT_IGNORE ) { - newTree->flags |= AF_LEFT_IGNORE; - Kid *newHeader = copyIgnoreList( prg, child ); - - /* Always the head. */ - newTree->child = newHeader; - - child = child->next; - last = newHeader; - } - - /* Right ignores. */ - if ( tree->flags & AF_RIGHT_IGNORE ) { - newTree->flags |= AF_RIGHT_IGNORE; - Kid *newHeader = copyIgnoreList( prg, child ); - if ( last == 0 ) - newTree->child = newHeader; - else - last->next = newHeader; - child = child->next; - last = newHeader; - } - - /* Attributes and children. */ - while ( child != 0 ) { - Kid *newKid = kidAllocate( prg ); - - /* Watch out for next down. */ - if ( child == oldNextDown ) - *newNextDown = newKid; - - newKid->tree = child->tree; - newKid->next = 0; - - /* May be an attribute. */ - if ( newKid->tree != 0 ) - newKid->tree->refs += 1; - - /* Store the first child. */ - if ( last == 0 ) - newTree->child = newKid; - else - last->next = newKid; - - child = child->next; - last = newKid; - } - - return newTree; -} - -List *copyList( Program *prg, List *list, Kid *oldNextDown, Kid **newNextDown ) -{ - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "splitting list: " << list << " refs: " << - list->refs << endl; - } - #endif - - /* Not a need copy. */ - List *newList = (List*)mapElAllocate( prg ); - newList->id = list->genericInfo->langElId; - newList->genericInfo = list->genericInfo; - - ListEl *src = list->head; - while( src != 0 ) { - ListEl *newEl = listElAllocate( prg ); - newEl->value = src->value; - treeUpref( newEl->value ); - - listAppend( newList, newEl ); - - /* Watch out for next down. */ - if ( (Kid*)src == oldNextDown ) - *newNextDown = (Kid*)newEl; - - src = src->next; - } - - return newList; -} - -Map *copyMap( Program *prg, Map *map, Kid *oldNextDown, Kid **newNextDown ) -{ - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "splitting map: " << map << " refs: " << - map->refs << endl; - } - #endif - - Map *newMap = (Map*)mapElAllocate( prg ); - newMap->id = map->genericInfo->langElId; - newMap->genericInfo = map->genericInfo; - newMap->treeSize = map->treeSize; - newMap->root = 0; - - /* If there is a root, copy the tree. */ - if ( map->root != 0 ) { - newMap->root = mapCopyBranch( prg, newMap, map->root, - oldNextDown, newNextDown ); - } - MapEl *el; - for ( el = newMap->head; el != 0; el = el->next ) { - assert( map->genericInfo->typeArg == TYPE_TREE ); - treeUpref( el->tree ); - } - - return newMap; -} - -Tree *copyTree( Program *prg, Tree *tree, Kid *oldNextDown, Kid **newNextDown ) -{ - LangElInfo *lelInfo = prg->rtd->lelInfo; - long genericId = lelInfo[tree->id].genericId; - if ( genericId > 0 ) { - GenericInfo *generic = &prg->rtd->genericInfo[genericId]; - if ( generic->type == GEN_LIST ) - tree = (Tree*) copyList( prg, (List*) tree, oldNextDown, newNextDown ); - else if ( generic->type == GEN_MAP ) - tree = (Tree*) copyMap( prg, (Map*) tree, oldNextDown, newNextDown ); - else if ( generic->type == GEN_PARSER ) { - /* Need to figure out the semantics here. */ - fatal( "ATTEMPT TO COPY PARSER\n" ); - assert(false); - } - } - else if ( tree->id == LEL_ID_PTR ) - assert(false); - else if ( tree->id == LEL_ID_BOOL ) - assert(false); - else if ( tree->id == LEL_ID_INT ) - assert(false); - else if ( tree->id == LEL_ID_STR ) - assert(false); - else if ( tree->id == LEL_ID_STREAM ) - assert(false); - else { - tree = copyRealTree( prg, tree, oldNextDown, newNextDown, false ); - } - - assert( tree->refs == 0 ); - return tree; -} - -Tree *splitTree( Program *prg, Tree *tree ) -{ - if ( tree != 0 ) { - assert( tree->refs >= 1 ); - - if ( tree->refs > 1 ) { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "splitting tree: " << tree << " refs: " << - tree->refs << endl; - } - #endif - - Kid *oldNextDown = 0, *newNextDown = 0; - Tree *newTree = copyTree( prg, tree, oldNextDown, &newNextDown ); - treeUpref( newTree ); - - /* Downref the original. Don't need to consider freeing because - * refs were > 1. */ - tree->refs -= 1; - - tree = newTree; - } - - assert( tree->refs == 1 ); - } - return tree; -} - -Tree *createGeneric( Program *prg, long genericId ) -{ - GenericInfo *genericInfo = &prg->rtd->genericInfo[genericId]; - Tree *newGeneric = 0; - switch ( genericInfo->type ) { - case GEN_MAP: { - Map *map = (Map*)mapElAllocate( prg ); - map->id = genericInfo->langElId; - map->genericInfo = genericInfo; - newGeneric = (Tree*) map; - break; - } - case GEN_LIST: { - List *list = (List*)mapElAllocate( prg ); - list->id = genericInfo->langElId; - list->genericInfo = genericInfo; - newGeneric = (Tree*) list; - break; - } - case GEN_PARSER: { - Accum *accum = (Accum*)mapElAllocate( prg ); - accum->id = genericInfo->langElId; - accum->genericInfo = genericInfo; - accum->fsmRun = malloc( sizeof(FsmRun) ); - accum->pdaRun = malloc( sizeof(PdaRun) ); - - /* Start off the parsing process. */ - initPdaRun( accum->pdaRun, prg, prg->rtd->pdaTables, - accum->fsmRun, genericInfo->parserId, false, false, 0 ); - initFsmRun( accum->fsmRun, prg ); - newToken( accum->pdaRun, accum->fsmRun ); - - newGeneric = (Tree*) accum; - break; - } - default: - assert(false); - return 0; - } - - return newGeneric; -} - - -/* We can't make recursive calls here since the tree we are freeing may be - * very large. Need the VM stack. */ -void treeFreeRec( Program *prg, Tree **sp, Tree *tree ) -{ - Tree **top = sp; - LangElInfo *lelInfo; - long genericId; - -free_tree: - lelInfo = prg->rtd->lelInfo; - genericId = lelInfo[tree->id].genericId; - if ( genericId > 0 ) { - GenericInfo *generic = &prg->rtd->genericInfo[genericId]; - if ( generic->type == GEN_LIST ) { - List *list = (List*) tree; - ListEl *el = list->head; - while ( el != 0 ) { - ListEl *next = el->next; - vm_push( el->value ); - listElFree( prg, el ); - el = next; - } - mapElFree( prg, (MapEl*)list ); - } - else if ( generic->type == GEN_MAP ) { - Map *map = (Map*)tree; - MapEl *el = map->head; - while ( el != 0 ) { - MapEl *next = el->next; - vm_push( el->key ); - vm_push( el->tree ); - mapElFree( prg, el ); - el = next; - } - mapElFree( prg, (MapEl*)map ); - } - else if ( generic->type == GEN_PARSER ) { - Accum *accum = (Accum*)tree; - free( accum->fsmRun ); - cleanParser( sp, accum->pdaRun ); - clearContext( accum->pdaRun, sp ); - rcodeDownrefAll( prg, sp, accum->pdaRun->allReverseCode ); - free( accum->pdaRun ); - treeDownref( prg, sp, (Tree*)accum->stream ); - mapElFree( prg, (MapEl*)accum ); - } - else - assert(false); - } - else { - if ( tree->id == LEL_ID_STR ) { - Str *str = (Str*) tree; - stringFree( prg, str->value ); - treeFree( prg, tree ); - } - else if ( tree->id == LEL_ID_BOOL || tree->id == LEL_ID_INT ) - treeFree( prg, tree ); - else if ( tree->id == LEL_ID_PTR ) { - //Pointer *ptr = (Pointer*)tree; - //vm_push( ptr->value->tree ); - //kidFree( prg, ptr->value ); - treeFree( prg, tree ); - } - else if ( tree->id == LEL_ID_STREAM ) - streamFree( prg, (Stream*) tree ); - else { - stringFree( prg, tree->tokdata ); - Kid *child = tree->child; - - /* Left ignore trees. */ - if ( tree->flags & AF_LEFT_IGNORE ) { - Kid *ic = (Kid*)child->tree; - while ( ic != 0 ) { - Kid *next = ic->next; - vm_push( ic->tree ); - kidFree( prg, ic ); - ic = next; - } - - Kid *next = child->next; - kidFree( prg, child ); - child = next; - } - - /* Right ignore trees. */ - if ( tree->flags & AF_RIGHT_IGNORE ) { - Kid *ic = (Kid*)child->tree; - while ( ic != 0 ) { - Kid *next = ic->next; - vm_push( ic->tree ); - kidFree( prg, ic ); - ic = next; - } - - Kid *next = child->next; - kidFree( prg, child ); - child = next; - } - - /* Attributes and grammar-based children. */ - while ( child != 0 ) { - Kid *next = child->next; - vm_push( child->tree ); - kidFree( prg, child ); - child = next; - } - - if ( tree->flags & AF_PARSE_TREE ) - parseTreeFree( prg, (ParseTree*)tree ); - else - treeFree( prg, tree ); - } - } - - /* Any trees to downref? */ - while ( sp != top ) { - tree = vm_pop(); - if ( tree != 0 ) { - assert( tree->refs > 0 ); - tree->refs -= 1; - if ( tree->refs == 0 ) - goto free_tree; - } - } -} - -void treeUpref( Tree *tree ) -{ - if ( tree != 0 ) - tree->refs += 1; -} - -void treeDownref( Program *prg, Tree **sp, Tree *tree ) -{ - if ( tree != 0 ) { - assert( tree->refs > 0 ); - tree->refs -= 1; - if ( tree->refs == 0 ) - treeFreeRec( prg, sp, tree ); - } -} - -/* Find the first child of a tree. */ -Kid *treeChild( Program *prg, const Tree *tree ) -{ - LangElInfo *lelInfo = prg->rtd->lelInfo; - Kid *kid = tree->child; - - if ( tree->flags & AF_LEFT_IGNORE ) - kid = kid->next; - if ( tree->flags & AF_RIGHT_IGNORE ) - kid = kid->next; - - /* Skip over attributes. */ - long objectLength = lelInfo[tree->id].objectLength; - long a; - for ( a = 0; a < objectLength; a++ ) - kid = kid->next; - - return kid; -} - -/* Find the first child of a tree. */ -Kid *treeExtractChild( Program *prg, Tree *tree ) -{ - LangElInfo *lelInfo = prg->rtd->lelInfo; - Kid *kid = tree->child, *last = 0; - - if ( tree->flags & AF_LEFT_IGNORE ) - kid = kid->next; - if ( tree->flags & AF_RIGHT_IGNORE ) - kid = kid->next; - - /* Skip over attributes. */ - long objectLength = lelInfo[tree->id].objectLength; - long a; - for ( a = 0; a < objectLength; a++ ) { - last = kid; - kid = kid->next; - } - - if ( last == 0 ) - tree->child = 0; - else - last->next = 0; - - return kid; -} - - -Kid *treeIgnore( Program *prg, Tree *tree ) -{ - if ( tree->flags & AF_LEFT_IGNORE ) - return (Kid*)tree->child->tree; - return 0; -} - -Tree *treeIterDerefCur( TreeIter *iter ) -{ - return iter->ref.kid == 0 ? 0 : iter->ref.kid->tree; -} - -void refSetValue( Ref *ref, Tree *v ) -{ - Kid *firstKid = ref->kid; - while ( ref != 0 && ref->kid == firstKid ) { - ref->kid->tree = v; - ref = ref->next; - } -} - -Tree *getRhsEl( Program *prg, Tree *lhs, long position ) -{ - Kid *pos = treeChild( prg, lhs ); - while ( position > 0 ) { - pos = pos->next; - position -= 1; - } - return pos->tree; -} - -void setField( Program *prg, Tree *tree, long field, Tree *value ) -{ - assert( tree->refs == 1 ); - if ( value != 0 ) - assert( value->refs >= 1 ); - setAttr( tree, field, value ); -} - -Tree *getField( Tree *tree, Word field ) -{ - return getAttr( tree, field ); -} - -Kid *getFieldKid( Tree *tree, Word field ) -{ - return getAttrKid( tree, field ); -} - -Tree *getFieldSplit( Program *prg, Tree *tree, Word field ) -{ - Tree *val = getAttr( tree, field ); - Tree *split = splitTree( prg, val ); - setAttr( tree, field, split ); - return split; -} - -void setTriterCur( TreeIter *iter, Tree *tree ) -{ - iter->ref.kid->tree = tree; -} - -Tree *getPtrVal( Pointer *ptr ) -{ - return ptr->value->tree; -} - -Tree *getPtrValSplit( Program *prg, Pointer *ptr ) -{ - Tree *val = ptr->value->tree; - Tree *split = splitTree( prg, val ); - ptr->value->tree = split; - return split; -} - -/* This must traverse in the same order that the bindId assignments are done - * in. */ -int matchPattern( Tree **bindings, Program *prg, long pat, Kid *kid, int checkNext ) -{ - PatReplNode *nodes = prg->rtd->patReplNodes; - - #ifdef COLM_LOG_MATCH - if ( colm_log_match ) { - LangElInfo *lelInfo = prg->rtd->lelInfo; - cerr << "match pattern " << ( pat == -1 ? "NULL" : lelInfo[nodes[pat].id].name ) << - " vs " << ( kid == 0 ? "NULL" : lelInfo[kid->tree->id].name ) << endl; - } - #endif - - /* match node, recurse on children. */ - if ( pat != -1 && kid != 0 ) { - if ( nodes[pat].id == kid->tree->id ) { - /* If the pattern node has data, then this means we need to match - * the data against the token data. */ - if ( nodes[pat].data != 0 ) { - /* Check the length of token text. */ - if ( nodes[pat].length != stringLength( kid->tree->tokdata ) ) - return false; - - /* Check the token text data. */ - if ( nodes[pat].length > 0 && memcmp( nodes[pat].data, - stringData( kid->tree->tokdata ), nodes[pat].length ) != 0 ) - return false; - } - - /* No failure, all okay. */ - if ( nodes[pat].bindId > 0 ) { - #ifdef COLM_LOG_MATCH - if ( colm_log_match ) { - cerr << "bindId: " << nodes[pat].bindId << endl; - } - #endif - bindings[nodes[pat].bindId] = kid->tree; - } - - /* If we didn't match a terminal duplicate of a nonterm then check - * down the children. */ - if ( !nodes[pat].stop ) { - /* Check for failure down child branch. */ - int childCheck = matchPattern( bindings, prg, - nodes[pat].child, treeChild( prg, kid->tree ), true ); - if ( ! childCheck ) - return false; - } - - /* If checking next, then look for failure there. */ - if ( checkNext ) { - int nextCheck = matchPattern( bindings, prg, - nodes[pat].next, kid->next, true ); - if ( ! nextCheck ) - return false; - } - - return true; - } - } - else if ( pat == -1 && kid == 0 ) { - /* Both null is a match. */ - return 1; - } - - return false; -} - - -long cmpTree( Program *prg, const Tree *tree1, const Tree *tree2 ) -{ - long cmpres = 0; - if ( tree1 == 0 ) { - if ( tree2 == 0 ) - return 0; - else - return -1; - } - else if ( tree2 == 0 ) - return 1; - else if ( tree1->id < tree2->id ) - return -1; - else if ( tree1->id > tree2->id ) - return 1; - else if ( tree1->id == LEL_ID_PTR ) { - if ( ((Pointer*)tree1)->value < ((Pointer*)tree2)->value ) - return -1; - else if ( ((Pointer*)tree1)->value > ((Pointer*)tree2)->value ) - return 1; - } - else if ( tree1->id == LEL_ID_INT ) { - if ( ((Int*)tree1)->value < ((Int*)tree2)->value ) - return -1; - else if ( ((Int*)tree1)->value > ((Int*)tree2)->value ) - return 1; - } - else if ( tree1->id == LEL_ID_STR ) { - cmpres = cmpString( ((Str*)tree1)->value, ((Str*)tree2)->value ); - if ( cmpres != 0 ) - return cmpres; - } - else { - if ( tree1->tokdata == 0 && tree2->tokdata != 0 ) - return -1; - else if ( tree1->tokdata != 0 && tree2->tokdata == 0 ) - return 1; - else if ( tree1->tokdata != 0 && tree2->tokdata != 0 ) { - cmpres = cmpString( tree1->tokdata, tree2->tokdata ); - if ( cmpres != 0 ) - return cmpres; - } - } - - Kid *kid1 = treeChild( prg, tree1 ); - Kid *kid2 = treeChild( prg, tree2 ); - - while ( true ) { - if ( kid1 == 0 && kid2 == 0 ) - return 0; - else if ( kid1 == 0 && kid2 != 0 ) - return -1; - else if ( kid1 != 0 && kid2 == 0 ) - return 1; - else { - cmpres = cmpTree( prg, kid1->tree, kid2->tree ); - if ( cmpres != 0 ) - return cmpres; - } - kid1 = kid1->next; - kid2 = kid2->next; - } -} - - -void splitRef( Tree ***psp, Program *prg, Ref *fromRef ) -{ - /* Go up the chain of kids, turing the pointers down. */ - Ref *last = 0, *ref = fromRef, *next = 0; - while ( ref->next != 0 ) { - next = ref->next; - ref->next = last; - last = ref; - ref = next; - } - ref->next = last; - - /* Now traverse the list, which goes down. */ - while ( ref != 0 ) { - if ( ref->kid->tree->refs > 1 ) { - #ifdef COLM_LOG_BYTECODE - if ( colm_log_bytecode ) { - cerr << "splitting tree: " << ref->kid << " refs: " << - ref->kid->tree->refs << endl; - } - #endif - - Ref *nextDown = ref->next; - while ( nextDown != 0 && nextDown->kid == ref->kid ) - nextDown = nextDown->next; - - Kid *oldNextKidDown = nextDown != 0 ? nextDown->kid : 0; - Kid *newNextKidDown = 0; - - Tree *newTree = copyTree( prg, ref->kid->tree, - oldNextKidDown, &newNextKidDown ); - treeUpref( newTree ); - - /* Downref the original. Don't need to consider freeing because - * refs were > 1. */ - ref->kid->tree->refs -= 1; - - while ( ref != 0 && ref != nextDown ) { - next = ref->next; - ref->next = 0; - - ref->kid->tree = newTree; - ref = next; - } - - /* Correct kid pointers down from ref. */ - while ( nextDown != 0 && nextDown->kid == oldNextKidDown ) { - nextDown->kid = newNextKidDown; - nextDown = nextDown->next; - } - } - else { - /* Reset the list as we go down. */ - next = ref->next; - ref->next = 0; - ref = next; - } - } -} - -void splitIterCur( Tree ***psp, Program *prg, TreeIter *iter ) -{ - if ( iter->ref.kid == 0 ) - return; - - splitRef( psp, prg, &iter->ref ); -} - -Tree *setListMem( List *list, Half field, Tree *value ) -{ - assert( list->refs == 1 ); - if ( value != 0 ) - assert( value->refs >= 1 ); - - Tree *existing = 0; - switch ( field ) { - case 0: - existing = list->head->value; - list->head->value = value; - break; - case 1: - existing = list->tail->value; - list->tail->value = value; - break; - default: - assert( false ); - break; - } - return existing; -} - -TreePair mapRemove( Program *prg, Map *map, Tree *key ) -{ - MapEl *mapEl = mapImplFind( prg, map, key ); - TreePair result; - if ( mapEl != 0 ) { - mapDetach( prg, map, mapEl ); - result.key = mapEl->key; - result.val = mapEl->tree; - mapElFree( prg, mapEl ); - } - - return result; -} - -Tree *mapUnstore( Program *prg, Map *map, Tree *key, Tree *existing ) -{ - Tree *stored = 0; - if ( existing == 0 ) { - MapEl *mapEl = mapDetachByKey( prg, map, key ); - stored = mapEl->tree; - mapElFree( prg, mapEl ); - } - else { - MapEl *mapEl = mapImplFind( prg, map, key ); - stored = mapEl->tree; - mapEl->tree = existing; - } - return stored; -} - -Tree *mapFind( Program *prg, Map *map, Tree *key ) -{ - MapEl *mapEl = mapImplFind( prg, map, key ); - return mapEl == 0 ? 0 : mapEl->tree; -} - -long mapLength( Map *map ) -{ - return map->treeSize; -} - -void listAppend2( Program *prg, List *list, Tree *val ) -{ - assert( list->refs == 1 ); - if ( val != 0 ) - assert( val->refs >= 1 ); - ListEl *listEl = listElAllocate( prg ); - listEl->value = val; - listAppend( list, listEl ); -} - -Tree *listRemoveEnd( Program *prg, List *list ) -{ - Tree *tree = list->tail->value; - listElFree( prg, listDetachLast( list ) ); - return tree; -} - -Tree *getListMem( List *list, Word field ) -{ - Tree *result = 0; - switch ( field ) { - case 0: - result = list->head->value; - break; - case 1: - result = list->tail->value; - break; - default: - assert( false ); - break; - } - return result; -} - -Tree *getListMemSplit( Program *prg, List *list, Word field ) -{ - Tree *sv = 0; - switch ( field ) { - case 0: - sv = splitTree( prg, list->head->value ); - list->head->value = sv; - break; - case 1: - sv = splitTree( prg, list->tail->value ); - list->tail->value = sv; - break; - default: - assert( false ); - break; - } - return sv; -} - - -int mapInsert( Program *prg, Map *map, Tree *key, Tree *element ) -{ - MapEl *mapEl = mapInsertKey( prg, map, key, 0 ); - - if ( mapEl != 0 ) { - mapEl->tree = element; - return true; - } - - return false; -} - -void mapUnremove( Program *prg, Map *map, Tree *key, Tree *element ) -{ - MapEl *mapEl = mapInsertKey( prg, map, key, 0 ); - assert( mapEl != 0 ); - mapEl->tree = element; -} - -Tree *mapUninsert( Program *prg, Map *map, Tree *key ) -{ - MapEl *el = mapDetachByKey( prg, map, key ); - Tree *val = el->tree; - mapElFree( prg, el ); - return val; -} - -Tree *mapStore( Program *prg, Map *map, Tree *key, Tree *element ) -{ - Tree *oldTree = 0; - MapEl *elInTree = 0; - MapEl *mapEl = mapInsertKey( prg, map, key, &elInTree ); - - if ( mapEl != 0 ) - mapEl->tree = element; - else { - /* Element with key exists. Overwriting the value. */ - oldTree = elInTree->tree; - elInTree->tree = element; - } - - return oldTree; -} - -void iterFind( Program *prg, Tree ***psp, TreeIter *iter, int tryFirst ) -{ - int anyTree = iter->searchId == prg->rtd->anyId; - Tree **top = iter->stackRoot; - Kid *child; - Tree **sp = *psp; - -rec_call: - if ( tryFirst && ( iter->ref.kid->tree->id == iter->searchId || anyTree ) ) { - *psp = sp; - return; - } - else { - child = treeChild( prg, iter->ref.kid->tree ); - if ( child != 0 ) { - vm_push( (SW) iter->ref.next ); - vm_push( (SW) iter->ref.kid ); - iter->ref.kid = child; - iter->ref.next = (Ref*)vm_ptop(); - while ( iter->ref.kid != 0 ) { - tryFirst = true; - goto rec_call; - rec_return: - iter->ref.kid = iter->ref.kid->next; - } - iter->ref.kid = (Kid*)vm_pop(); - iter->ref.next = (Ref*)vm_pop(); - } - } - - if ( top != vm_ptop() ) - goto rec_return; - - iter->ref.kid = 0; - *psp = sp; -} - -Tree *treeIterAdvance( Program *prg, Tree ***psp, TreeIter *iter ) -{ - assert( iter->stackSize == iter->stackRoot - *psp ); - - if ( iter->ref.kid == 0 ) { - /* Kid is zero, start from the root. */ - iter->ref = iter->rootRef; - iterFind( prg, psp, iter, true ); - } - else { - /* Have a previous item, continue searching from there. */ - iterFind( prg, psp, iter, false ); - } - - iter->stackSize = iter->stackRoot - *psp; - - return (iter->ref.kid ? prg->trueVal : prg->falseVal ); -} - -Tree *treeIterNextChild( Program *prg, Tree ***psp, TreeIter *iter ) -{ - Tree **sp = *psp; - assert( iter->stackSize == iter->stackRoot - vm_ptop() ); - Kid *kid = 0; - - if ( iter->ref.kid == 0 ) { - /* Kid is zero, start from the first child. */ - Kid *child = treeChild( prg, iter->rootRef.kid->tree ); - - if ( child == 0 ) - iter->ref.next = 0; - else { - /* Make a reference to the root. */ - vm_push( (SW) iter->rootRef.next ); - vm_push( (SW) iter->rootRef.kid ); - iter->ref.next = (Ref*)vm_ptop(); - - kid = child; - } - } - else { - /* Start at next. */ - kid = iter->ref.kid->next; - } - - if ( iter->searchId != prg->rtd->anyId ) { - /* Have a previous item, go to the next sibling. */ - while ( kid != 0 && kid->tree->id != iter->searchId ) - kid = kid->next; - } - - iter->ref.kid = kid; - iter->stackSize = iter->stackRoot - vm_ptop(); - *psp = sp; - return ( iter->ref.kid ? prg->trueVal : prg->falseVal ); -} - -Tree *treeRevIterPrevChild( Program *prg, Tree ***psp, RevTreeIter *iter ) -{ - Tree **sp = *psp; - - assert( iter->stackSize == iter->stackRoot - vm_ptop() ); - - if ( iter->kidAtYield != iter->ref.kid ) { - /* Need to reload the kids. */ - Kid *kid = treeChild( prg, iter->rootRef.kid->tree ); - Kid **dst = (Kid**)iter->stackRoot - 1; - while ( kid != 0 ) { - *dst-- = kid; - kid = kid->next; - } - } - - if ( iter->ref.kid == 0 ) - iter->cur = (Kid**)iter->stackRoot - iter->children; - else - iter->cur += 1; - - if ( iter->searchId != prg->rtd->anyId ) { - /* Have a previous item, go to the next sibling. */ - while ( iter->cur != (Kid**)iter->stackRoot && (*iter->cur)->tree->id != iter->searchId ) - iter->cur += 1; - } - - if ( iter->cur == (Kid**)iter->stackRoot ) { - iter->ref.next = 0; - iter->ref.kid = 0; - } - else { - iter->ref.next = &iter->rootRef; - iter->ref.kid = *iter->cur; - } - - /* We will use this to detect a split above the iterated tree. */ - iter->kidAtYield = iter->ref.kid; - - iter->stackSize = iter->stackRoot - vm_ptop(); - - *psp = sp; - - return (iter->ref.kid ? prg->trueVal : prg->falseVal ); -} - -void iterFindRepeat( Program *prg, Tree ***psp, TreeIter *iter, int tryFirst ) -{ - Tree **sp = *psp; - int anyTree = iter->searchId == prg->rtd->anyId; - Tree **top = iter->stackRoot; - Kid *child; - -rec_call: - if ( tryFirst && ( iter->ref.kid->tree->id == iter->searchId || anyTree ) ) { - *psp = sp; - return; - } - else { - /* The repeat iterator is just like the normal top-down-left-right, - * execept it only goes into the children of a node if the node is the - * root of the iteration, or if does not have any neighbours to the - * right. */ - if ( top == vm_ptop() || iter->ref.kid->next == 0 ) { - child = treeChild( prg, iter->ref.kid->tree ); - if ( child != 0 ) { - vm_push( (SW) iter->ref.next ); - vm_push( (SW) iter->ref.kid ); - iter->ref.kid = child; - iter->ref.next = (Ref*)vm_ptop(); - while ( iter->ref.kid != 0 ) { - tryFirst = true; - goto rec_call; - rec_return: - iter->ref.kid = iter->ref.kid->next; - } - iter->ref.kid = (Kid*)vm_pop(); - iter->ref.next = (Ref*)vm_pop(); - } - } - } - - if ( top != vm_ptop() ) - goto rec_return; - - iter->ref.kid = 0; - *psp = sp; -} - -Tree *treeIterNextRepeat( Program *prg, Tree ***psp, TreeIter *iter ) -{ - assert( iter->stackSize == iter->stackRoot - *psp ); - - if ( iter->ref.kid == 0 ) { - /* Kid is zero, start from the root. */ - iter->ref = iter->rootRef; - iterFindRepeat( prg, psp, iter, true ); - } - else { - /* Have a previous item, continue searching from there. */ - iterFindRepeat( prg, psp, iter, false ); - } - - iter->stackSize = iter->stackRoot - *psp; - - return (iter->ref.kid ? prg->trueVal : prg->falseVal ); -} - -void iterFindRevRepeat( Program *prg, Tree ***psp, TreeIter *iter, int tryFirst ) -{ - Tree **sp = *psp; - int anyTree = iter->searchId == prg->rtd->anyId; - Tree **top = iter->stackRoot; - Kid *child; - - if ( tryFirst ) { - while ( true ) { - if ( top == vm_ptop() || iter->ref.kid->next == 0 ) { - child = treeChild( prg, iter->ref.kid->tree ); - - if ( child == 0 ) - break; - vm_push( (SW) iter->ref.next ); - vm_push( (SW) iter->ref.kid ); - iter->ref.kid = child; - iter->ref.next = (Ref*)vm_ptop(); - } - else { - /* Not the top and not there is a next, go over to it. */ - iter->ref.kid = iter->ref.kid->next; - } - } - - goto first; - } - - while ( true ) { - if ( top == vm_ptop() ) { - iter->ref.kid = 0; - return; - } - - if ( iter->ref.kid->next == 0 ) { - /* Go up one and then down. Remember we can't use iter->ref.next - * because the chain may have been split, setting it null (to - * prevent repeated walks up). */ - Ref *ref = (Ref*)vm_ptop(); - iter->ref.kid = ref->kid->tree->child; - } - else { - iter->ref.kid = (Kid*)vm_pop(); - iter->ref.next = (Ref*)vm_pop(); - } -first: - if ( iter->ref.kid->tree->id == iter->searchId || anyTree ) { - *psp = sp; - return; - } - } - *psp = sp; - return; -} - - -Tree *treeIterPrevRepeat( Program *prg, Tree ***psp, TreeIter *iter ) -{ - assert( iter->stackSize == iter->stackRoot - *psp ); - - if ( iter->ref.kid == 0 ) { - /* Kid is zero, start from the root. */ - iter->ref = iter->rootRef; - iterFindRevRepeat( prg, psp, iter, true ); - } - else { - /* Have a previous item, continue searching from there. */ - iterFindRevRepeat( prg, psp, iter, false ); - } - - iter->stackSize = iter->stackRoot - *psp; - - return (iter->ref.kid ? prg->trueVal : prg->falseVal ); -} - -Tree *treeSearch( Program *prg, Kid *kid, long id ) -{ - /* This node the one? */ - if ( kid->tree->id == id ) - return kid->tree; - - Tree *res = 0; - - /* Search children. */ - Kid *child = treeChild( prg, kid->tree ); - if ( child != 0 ) - res = treeSearch( prg, child, id ); - - /* Search siblings. */ - if ( res == 0 && kid->next != 0 ) - res = treeSearch( prg, kid->next, id ); - - return res; -} - -Tree *treeSearch2( Program *prg, Tree *tree, long id ) -{ - Tree *res = 0; - if ( tree->id == id ) - res = tree; - else { - Kid *child = treeChild( prg, tree ); - if ( child != 0 ) - res = treeSearch( prg, child, id ); - } - return res; -} - -void xmlEscapeData( FILE *out, const char *data, long len ) -{ - int i; - for ( i = 0; i < len; i++ ) { - if ( data[i] == '<' ) - fprintf( out, "<" ); - else if ( data[i] == '>' ) - fprintf( out, ">" ); - else if ( data[i] == '&' ) - fprintf( out, "&" ); - else if ( 32 <= data[i] && data[i] <= 126 ) - fprintf( out, "%c", data[i] ); - else - fprintf( out, "&#%u;", ((unsigned)data[i]) ); - } -} - -void printXmlKid( FILE *out, Tree **sp, Program *prg, Kid *kid, int commAttr, int depth ); - -/* Might be a good idea to include this in the printXmlKid function since - * it is recursive and can eat up stac, however it's probably not a big deal - * since the additional stack depth is only caused for nonterminals that are - * ignored. */ -void printXmlIgnoreList( FILE *out, Tree **sp, Program *prg, Tree *tree, long depth ) -{ - Kid *ignore = treeIgnore( prg, tree ); - while ( ignore != 0 ) { - printXmlKid( out, sp, prg, ignore, true, depth ); - ignore = ignore->next; - } -} - -void printXmlKid( FILE *out, Tree **sp, Program *prg, Kid *kid, int commAttr, int depth ) -{ - Kid *child; - Tree **root = vm_ptop(); - long i, objectLength; - LangElInfo *lelInfo = prg->rtd->lelInfo; - - long kidNum = 0;; - -rec_call: - - if ( kid->tree == 0 ) { - for ( i = 0; i < depth; i++ ) - fprintf( out, " " ); - - fprintf( out, "NIL\n" ); - } - else { - /* First print the ignore tokens. */ - if ( commAttr ) - printXmlIgnoreList( out, sp, prg, kid->tree, depth ); - - for ( i = 0; i < depth; i++ ) - fprintf( out, " " ); - - /* Open the tag. Afterwards we will either print data underneath it or - * we will close it off immediately. */ - fprintf( out, "<%s", lelInfo[kid->tree->id].name ); - - /* If this is an attribute then give the node an attribute number. */ - if ( vm_ptop() != root ) { - objectLength = lelInfo[((Kid*)vm_top())->tree->id].objectLength; - if ( kidNum < objectLength ) - fprintf( out, " an=\"%ld\"", kidNum ); - } - - objectLength = lelInfo[kid->tree->id].objectLength; - child = treeChild( prg, kid->tree ); - if ( (commAttr && objectLength > 0) || child != 0 ) { - fprintf( out, ">\n" ); - vm_push( (SW) kidNum ); - vm_push( (SW) kid ); - - kidNum = 0; - kid = kid->tree->child; - - /* Skip over attributes if not printing comments and attributes. */ - if ( ! commAttr ) - kid = child; - - while ( kid != 0 ) { - /* FIXME: I don't think we need this check for ignore any more. */ - if ( kid->tree == 0 || !lelInfo[kid->tree->id].ignore ) { - depth++; - goto rec_call; - rec_return: - depth--; - } - - kid = kid->next; - kidNum += 1; - - /* If the parent kid is a repeat then skip this node and go - * right to the first child (repeated item). */ - if ( lelInfo[((Kid*)vm_top())->tree->id].repeat ) - kid = kid->tree->child; - - /* If we have a kid and the parent is a list (recursive prod of - * list) then go right to the first child. */ - if ( kid != 0 && lelInfo[((Kid*)vm_top())->tree->id].list ) - kid = kid->tree->child; - } - - kid = (Kid*) vm_pop(); - kidNum = (long) vm_pop(); - - for ( i = 0; i < depth; i++ ) - fprintf( out, " " ); - fprintf( out, "\n", lelInfo[kid->tree->id].name ); - } - else if ( kid->tree->id == LEL_ID_PTR ) { - fprintf( out, ">%p\n", (void*)((Pointer*)kid->tree)->value, - lelInfo[kid->tree->id].name ); - } - else if ( kid->tree->id == LEL_ID_BOOL ) { - if ( ((Int*)kid->tree)->value ) - fprintf( out, ">truefalse\n", lelInfo[kid->tree->id].name ); - } - else if ( kid->tree->id == LEL_ID_INT ) { - fprintf( out, ">%ld\n", ((Int*)kid->tree)->value, - lelInfo[kid->tree->id].name ); - } - else if ( kid->tree->id == LEL_ID_STR ) { - Head *head = (Head*) ((Str*)kid->tree)->value; - - fprintf( out, ">" ); - xmlEscapeData( out, (char*)(head->data), head->length ); - fprintf( out, "\n", lelInfo[kid->tree->id].name ); - } - else if ( 0 < kid->tree->id && kid->tree->id < prg->rtd->firstNonTermId && - kid->tree->tokdata != 0 && - stringLength( kid->tree->tokdata ) > 0 && - !lelInfo[kid->tree->id].literal ) - { - fprintf( out, ">" ); - xmlEscapeData( out, stringData( kid->tree->tokdata ), - stringLength( kid->tree->tokdata ) ); - fprintf( out, "\n", lelInfo[kid->tree->id].name ); - } - else { - fprintf( out, "/>\n" ); - } - } - - if ( vm_ptop() != root ) - goto rec_return; -} - -void printXmlTree( Tree **sp, Program *prg, Tree *tree, int commAttr ) -{ - Kid kid; - kid.tree = tree; - kid.next = 0; - printXmlKid( stdout, sp, prg, &kid, commAttr, 0 ); -} - -void initStrCollect( StrCollect *collect ) -{ - collect->data = (char*) malloc( BUFFER_INITIAL_SIZE ); - collect->allocated = BUFFER_INITIAL_SIZE; - collect->length = 0; -} - -void strCollectDestroy( StrCollect *collect ) -{ - free( collect->data ); -} - -void strCollectAppend( StrCollect *collect, const char *data, long len ) -{ - long newLen = collect->length + len; - if ( newLen > collect->allocated ) { - collect->allocated *= newLen * 2; - collect->data = (char*) realloc( collect->data, collect->allocated ); - } - memcpy( collect->data + collect->length, data, len ); - collect->length += len; -} - -void strCollectClear( StrCollect *collect ) -{ - collect->length = 0; -} - -#define INT_SZ 32 - -void printStr( StrCollect *collect, Head *str ) -{ - strCollectAppend( collect, (char*)(str->data), str->length ); -} - -/* Note that this function causes recursion, thought it is not a big - * deal since the recursion it is only caused by nonterminals that are ignored. */ -void printIgnoreList( StrCollect *collect, Tree **sp, Program *prg, Tree *tree ) -{ - Kid *ignore = treeIgnore( prg, tree ); - - /* Record the root of the stack and push everything. */ - Tree **root = vm_ptop(); - while ( ignore != 0 ) { - vm_push( (SW)ignore ); - ignore = ignore->next; - } - - /* Pop them off and print. */ - while ( vm_ptop() != root ) { - ignore = (Kid*) vm_pop(); - printTree( collect, sp, prg, ignore->tree ); - } -} - -void printKid( StrCollect *collect, Tree **sp, Program *prg, Kid *kid, int printIgnore ) -{ - Tree **root = vm_ptop(); - Kid *child; - -rec_call: - /* If not currently skipping ignore data, then print it. Ignore data can - * be associated with terminals and nonterminals. */ - if ( printIgnore && treeIgnore( prg, kid->tree ) != 0 ) { - /* Ignorelists are reversed. */ - printIgnoreList( collect, sp, prg, kid->tree ); - printIgnore = false; - } - - if ( kid->tree->id < prg->rtd->firstNonTermId ) { - /* Always turn on ignore printing when we get to a token. */ - printIgnore = true; - - if ( kid->tree->id == LEL_ID_INT ) { - char buf[INT_SZ]; - sprintf( buf, "%ld", ((Int*)kid->tree)->value ); - strCollectAppend( collect, buf, strlen(buf) ); - } - else if ( kid->tree->id == LEL_ID_BOOL ) { - if ( ((Int*)kid->tree)->value ) - strCollectAppend( collect, "true", 4 ); - else - strCollectAppend( collect, "false", 5 ); - } - else if ( kid->tree->id == LEL_ID_PTR ) { - char buf[INT_SZ]; - strCollectAppend( collect, "#", 1 ); - sprintf( buf, "%p", (void*) ((Pointer*)kid->tree)->value ); - strCollectAppend( collect, buf, strlen(buf) ); - } - else if ( kid->tree->id == LEL_ID_STR ) { - printStr( collect, ((Str*)kid->tree)->value ); - } - else if ( kid->tree->id == LEL_ID_STREAM ) { - char buf[INT_SZ]; - strCollectAppend( collect, "#", 1 ); - sprintf( buf, "%p", (void*) ((Stream*)kid->tree)->file ); - strCollectAppend( collect, buf, strlen(buf) ); - } - else if ( kid->tree->tokdata != 0 && - stringLength( kid->tree->tokdata ) > 0 ) - { - strCollectAppend( collect, stringData( kid->tree->tokdata ), - stringLength( kid->tree->tokdata ) ); - } - } - else { - /* Non-terminal. */ - child = treeChild( prg, kid->tree ); - if ( child != 0 ) { - vm_push( (SW)kid ); - kid = child; - while ( kid != 0 ) { - goto rec_call; - rec_return: - kid = kid->next; - } - kid = (Kid*)vm_pop(); - } - } - - if ( vm_ptop() != root ) - goto rec_return; -} - -void printTree( StrCollect *collect, Tree **sp, Program *prg, Tree *tree ) -{ - if ( tree == 0 ) - strCollectAppend( collect, "NIL", 3 ); - else { - Kid kid; - kid.tree = tree; - kid.next = 0; - printKid( collect, sp, prg, &kid, false ); - } -} - - -- cgit v1.2.1