summaryrefslogtreecommitdiff
path: root/src/bytecode.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/bytecode.c')
-rw-r--r--src/bytecode.c3702
1 files changed, 3702 insertions, 0 deletions
diff --git a/src/bytecode.c b/src/bytecode.c
new file mode 100644
index 0000000..4aa5b10
--- /dev/null
+++ b/src/bytecode.c
@@ -0,0 +1,3702 @@
+/*
+ * Copyright 2006-2012 Adrian Thurston <thurston@complang.org>
+ */
+
+/* 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 <colm/pdarun.h>
+#include <colm/tree.h>
+#include <colm/bytecode.h>
+#include <colm/pool.h>
+#include <colm/debug.h>
+#include <colm/config.h>
+
+#include <alloca.h>
+#include <sys/mman.h>
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#if SIZEOF_LONG != 4 && SIZEOF_LONG != 8
+ #error "SIZEOF_LONG contained an unexpected value"
+#endif
+
+#define true 1
+#define false 0
+
+#define read_byte( i ) do { \
+ i = ((uchar) *instr++); \
+} while(0)
+
+#define consume_byte( ) do { \
+ instr += 1; \
+} 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)
+
+ #define read_word_type( Type, i ) do { \
+ Word w; \
+ w = ((Word) *instr++); \
+ w |= ((Word) *instr++) << 8; \
+ w |= ((Word) *instr++) << 16; \
+ w |= ((Word) *instr++) << 24; \
+ i = (Type) w; \
+ } while(0)
+
+ #define consume_word( ) do { \
+ instr += 4; \
+ } 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)
+
+ #define read_word_type( Type, 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 = (Type) w; \
+ } while(0)
+
+ #define consume_word( ) do { \
+ instr += 8; \
+ } while(0)
+#endif
+
+#define read_half( i ) do { \
+ i = ((Word) *instr++); \
+ i |= ((Word) *instr++) << 8; \
+} while(0)
+
+void parserSetContext( Program *prg, Tree **sp, Parser *parser, Tree *val )
+{
+ parser->pdaRun->context = splitTree( prg, val );
+}
+
+static Head *treeToStr( Program *prg, Tree **sp, Tree *tree, int trim )
+{
+ /* Collect the tree data. */
+ StrCollect collect;
+ initStrCollect( &collect );
+
+ printTreeCollect( prg, sp, &collect, tree, trim );
+
+ /* Set up the input stream. */
+ Head *ret = stringAllocFull( prg, collect.data, collect.length );
+
+ strCollectDestroy( &collect );
+
+ return ret;
+}
+
+Word streamAppend( Program *prg, Tree **sp, Tree *input, StreamImpl *is )
+{
+ long length = 0;
+
+ if ( input->id == LEL_ID_STR ) {
+ /* Collect the tree data. */
+ StrCollect collect;
+ initStrCollect( &collect );
+ printTreeCollect( prg, sp, &collect, input, false );
+
+ /* Load it into the input. */
+ is->funcs->appendData( is, collect.data, collect.length );
+ length = collect.length;
+ strCollectDestroy( &collect );
+ }
+ else if ( input->id == LEL_ID_STREAM ) {
+ treeUpref( input );
+ is->funcs->appendStream( is, input );
+ }
+ else {
+ treeUpref( input );
+ is->funcs->appendTree( is, input );
+ }
+
+ return length;
+}
+
+long parseFrag( Program *prg, Tree **sp, Parser *parser, long stopId, long entry )
+{
+switch ( entry ) {
+case PcrStart:
+
+ if ( ! parser->pdaRun->parseError ) {
+ parser->pdaRun->stopTarget = stopId;
+
+ long pcr = parseLoop( prg, sp, parser->pdaRun, parser->input->in, entry );
+
+ while ( pcr != PcrDone ) {
+
+return pcr;
+case PcrReduction:
+case PcrGeneration:
+case PcrPreEof:
+case PcrReverse:
+
+ pcr = parseLoop( prg, sp, parser->pdaRun, parser->input->in, entry );
+ }
+ }
+
+case PcrDone:
+break; }
+
+ return PcrDone;
+}
+
+long parseFinish( Tree **result, Program *prg, Tree **sp,
+ Parser *parser, int revertOn, long entry )
+{
+switch ( entry ) {
+case PcrStart:
+
+ if ( parser->pdaRun->stopTarget <= 0 ) {
+ parser->input->in->funcs->setEof( parser->input->in );
+
+ if ( ! parser->pdaRun->parseError ) {
+ long pcr = parseLoop( prg, sp, parser->pdaRun, parser->input->in, entry );
+
+ while ( pcr != PcrDone ) {
+
+return pcr;
+case PcrReduction:
+case PcrGeneration:
+case PcrPreEof:
+case PcrReverse:
+
+ pcr = parseLoop( prg, sp, parser->pdaRun, parser->input->in, entry );
+ }
+ }
+ }
+
+ /* FIXME: need something here to check that we are not stopped waiting for
+ * more data when we are actually expected to finish. This check doesn't
+ * work (at time of writing). */
+ //assert( (parser->pdaRun->stopTarget > 0 && parser->pdaRun->stopParsing) || parser->input->in->eofSent );
+
+ if ( !revertOn )
+ commitFull( prg, sp, parser->pdaRun, 0 );
+
+ Tree *tree = getParsedRoot( parser->pdaRun, parser->pdaRun->stopTarget > 0 );
+ treeUpref( tree );
+
+ *result = tree;
+
+case PcrDone:
+break; }
+
+ return PcrDone;
+}
+
+long undoParseFrag( Program *prg, Tree **sp, Parser *parser, long steps, long entry )
+{
+ StreamImpl *is = parser->input->in;
+ PdaRun *pdaRun = parser->pdaRun;
+
+ debug( prg, REALM_PARSE, "undo parse frag, target steps: %ld, pdarun steps: %ld\n", steps, pdaRun->steps );
+
+ resetToken( pdaRun );
+
+switch ( entry ) {
+case PcrStart:
+
+ if ( steps < pdaRun->steps ) {
+ /* Setup environment for going backwards until we reduced steps to
+ * what we want. */
+ pdaRun->numRetry += 1;
+ pdaRun->targetSteps = steps;
+ pdaRun->triggerUndo = 1;
+
+ /* The parse loop will recognise the situation. */
+ long pcr = parseLoop( prg, sp, pdaRun, is, entry );
+ while ( pcr != PcrDone ) {
+
+return pcr;
+case PcrReduction:
+case PcrGeneration:
+case PcrPreEof:
+case PcrReverse:
+
+ pcr = parseLoop( prg, sp, pdaRun, is, entry );
+ }
+
+ /* Reset environment. */
+ pdaRun->triggerUndo = 0;
+ pdaRun->targetSteps = -1;
+ pdaRun->numRetry -= 1;
+ }
+
+case PcrDone:
+break; }
+
+ return PcrDone;
+}
+
+Tree *streamPullBc( Program *prg, PdaRun *pdaRun, StreamImpl *in, Tree *length )
+{
+ long len = ((Int*)length)->value;
+ Head *tokdata = streamPull( prg, pdaRun, in, len );
+ return constructString( prg, tokdata );
+}
+
+void undoPull( Program *prg, StreamImpl *in, Tree *str )
+{
+ const char *data = stringData( ( (Str*)str )->value );
+ long length = stringLength( ( (Str*)str )->value );
+ undoStreamPull( in, data, length );
+}
+
+static long streamPush( Program *prg, Tree **sp, StreamImpl *in, 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 );
+ printTreeCollect( prg, sp, &collect, tree, false );
+
+ streamPushText( in, collect.data, collect.length );
+ long length = collect.length;
+ strCollectDestroy( &collect );
+
+ return length;
+ }
+ else if ( tree->id == LEL_ID_STREAM ) {
+ treeUpref( tree );
+ streamPushStream( in, tree );
+ return -1;
+ }
+ else {
+ treeUpref( tree );
+ streamPushTree( in, tree, ignore );
+ return -1;
+ }
+}
+
+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;
+}
+
+static void downrefLocalTrees( Program *prg, Tree **sp, Tree **frame, LocalInfo *locals, long localsLen )
+{
+ long i;
+ for ( i = localsLen-1; i >= 0; i-- ) {
+ if ( locals[i].type == LI_Tree ) {
+ debug( prg, REALM_BYTECODE, "local tree downref: %ld\n", (long)locals[i].offset );
+
+ Tree *tree = (Tree*) frame[(long)locals[i].offset];
+ treeDownref( prg, sp, tree );
+ }
+ }
+}
+
+static void downrefLocals( Program *prg, Tree ***psp, Tree **frame, LocalInfo *locals, long localsLen )
+{
+ long i;
+ for ( i = localsLen-1; i >= 0; i-- ) {
+ switch ( locals[i].type ) {
+ case LI_Tree: {
+ debug( prg, REALM_BYTECODE, "local tree downref: %ld\n", (long)locals[i].offset );
+ Tree *tree = (Tree*) frame[(long)locals[i].offset];
+ treeDownref( prg, *psp, tree );
+ break;
+ }
+ case LI_Iter: {
+ debug( prg, REALM_BYTECODE, "local iter downref: %ld\n", (long)locals[i].offset );
+ TreeIter *iter = (TreeIter*) &frame[(long)locals[i].offset];
+ treeIterDestroy( prg, psp, iter );
+ break;
+ }
+ case LI_RevIter: {
+ debug( prg, REALM_BYTECODE, "local rev iter downref: %ld\n", (long)locals[i].offset );
+ RevTreeIter *riter = (RevTreeIter*) &frame[(long)locals[i].offset];
+ revTreeIterDestroy( prg, psp, riter );
+ break;
+ }
+ case LI_UserIter: {
+ debug( prg, REALM_BYTECODE, "local user iter downref: %ld\n", (long)locals[i].offset );
+ UserIter *uiter = (UserIter*) frame[locals[i].offset];
+ userIterDestroy2( prg, psp, uiter );
+ break;
+ }
+ }
+ }
+}
+
+Tree *constructArgv( Program *prg, int argc, const char **argv )
+{
+ Tree *list = createGeneric( prg, prg->rtd->argvGenericId );
+ 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 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_PARSE_SAVE_STEPS: {
+ debug( prg, REALM_BYTECODE, "IN_PARSE_SAVE_STEPS\n" );
+ break;
+ }
+ case IN_PARSE_INIT_BKT: {
+ Tree *parser;
+ Word pcr;
+ Word steps;
+
+ debug( prg, REALM_BYTECODE, "IN_PARSE_INIT_BKT\n" );
+
+ read_tree( parser );
+ read_word( pcr );
+ read_word( steps );
+
+ treeDownref( prg, sp, (Tree*)parser );
+ break;
+ }
+
+ case IN_LOAD_TREE: {
+ Word w;
+ read_word( w );
+ debug( prg, REALM_BYTECODE, "IN_LOAD_TREE %p\n", (Tree*)w );
+ treeDownref( prg, sp, (Tree*)w );
+ break;
+ }
+ case IN_LOAD_WORD: {
+ Word w;
+ read_word( w );
+ debug( prg, REALM_BYTECODE, "IN_LOAD_WORD\n" );
+ break;
+ }
+ case IN_RESTORE_LHS: {
+ Tree *restore;
+ read_tree( restore );
+ debug( prg, REALM_BYTECODE, "IN_RESTORE_LHS\n" );
+ treeDownref( prg, sp, restore );
+ break;
+ }
+
+ case IN_PARSE_FRAG_BKT: {
+ Half stopId;
+ read_half( stopId );
+ debug( prg, REALM_BYTECODE, "IN_PARSE_FRAG_BKT\n" );
+ break;
+ }
+ case IN_PARSE_FRAG_EXIT_BKT: {
+ debug( prg, REALM_BYTECODE, "IN_PARSE_FRAG_EXIT_BKT\n" );
+ break;
+ }
+ case IN_PARSE_FINISH_BKT: {
+ Half stopId;
+ read_half( stopId );
+ debug( prg, REALM_BYTECODE, "IN_PARSE_FINISH_BKT\n" );
+ break;
+ }
+ case IN_PARSE_FINISH_EXIT_BKT: {
+ debug( prg, REALM_BYTECODE, "IN_PARSE_FINISH_EXIT_BKT\n" );
+ break;
+ }
+ case IN_PCR_CALL: {
+ debug( prg, REALM_BYTECODE, "IN_PCR_CALL\n" );
+ break;
+ }
+ case IN_PCR_RET: {
+ debug( prg, REALM_BYTECODE, "IN_PCR_RET\n" );
+ return;
+ }
+ case IN_PCR_END_DECK: {
+ debug( prg, REALM_BYTECODE, "IN_PCR_END_DECK\n" );
+ return;
+ }
+ case IN_INPUT_APPEND_BKT: {
+ Tree *parser;
+ Tree *input;
+ Word len;
+ read_tree( parser );
+ read_tree( input );
+ read_word( len );
+
+ debug( prg, REALM_BYTECODE, "IN_INPUT_APPEND_BKT\n" );
+
+ treeDownref( prg, sp, parser );
+ treeDownref( prg, sp, input );
+ break;
+ }
+ case IN_INPUT_PULL_BKT: {
+ Tree *string;
+ read_tree( string );
+
+ debug( prg, REALM_BYTECODE, "IN_INPUT_PULL_BKT\n" );
+
+ treeDownref( prg, sp, string );
+ break;
+ }
+ case IN_INPUT_PUSH_BKT: {
+ Word len;
+ read_word( len );
+
+ debug( prg, REALM_BYTECODE, "IN_INPUT_PUSH_BKT\n" );
+ break;
+ }
+ case IN_LOAD_GLOBAL_BKT: {
+ debug( prg, REALM_BYTECODE, "IN_LOAD_GLOBAL_BKT\n" );
+ break;
+ }
+ case IN_LOAD_CONTEXT_BKT: {
+ debug( prg, REALM_BYTECODE, "IN_LOAD_CONTEXT_BKT\n" );
+ break;
+ }
+ case IN_LOAD_PARSER_BKT: {
+ /* Tree *parser; */
+ consume_word();
+ debug( prg, REALM_BYTECODE, "IN_LOAD_PARSER_BKT\n" );
+ break;
+ }
+ case IN_LOAD_INPUT_BKT: {
+ /* Tree *input; */
+ consume_word();
+ debug( prg, REALM_BYTECODE, "IN_LOAD_INPUT_BKT\n" );
+ break;
+ }
+ case IN_GET_FIELD_BKT: {
+ short field;
+ read_half( field );
+
+ debug( prg, REALM_BYTECODE, "IN_GET_FIELD_BKT %hd\n", field );
+ break;
+ }
+ case IN_SET_FIELD_BKT: {
+ short field;
+ Tree *val;
+ read_half( field );
+ read_tree( val );
+
+ debug( prg, REALM_BYTECODE, "IN_SET_FIELD_BKT %hd\n", field );
+
+ treeDownref( prg, sp, val );
+ break;
+ }
+ case IN_PTR_DEREF_BKT: {
+ Tree *ptr;
+ read_tree( ptr );
+
+ debug( prg, REALM_BYTECODE, "IN_PTR_DEREF_BKT\n" );
+
+ treeDownref( prg, sp, ptr );
+ break;
+ }
+ case IN_SET_TOKEN_DATA_BKT: {
+ Word oldval;
+ read_word( oldval );
+
+ debug( prg, REALM_BYTECODE, "IN_SET_TOKEN_DATA_BKT\n" );
+
+ Head *head = (Head*)oldval;
+ stringFree( prg, head );
+ break;
+ }
+ case IN_LIST_APPEND_BKT: {
+ debug( prg, REALM_BYTECODE, "IN_LIST_APPEND_BKT\n" );
+ break;
+ }
+ case IN_LIST_REMOVE_END_BKT: {
+ Tree *val;
+ read_tree( val );
+
+ debug( prg, REALM_BYTECODE, "IN_LIST_REMOVE_END_BKT\n" );
+
+ treeDownref( prg, sp, val );
+ break;
+ }
+ case IN_GET_LIST_MEM_BKT: {
+ short field;
+ read_half( field );
+
+ debug( prg, REALM_BYTECODE, "IN_GET_LIST_MEM_BKT %hd\n", field );
+ break;
+ }
+ case IN_SET_LIST_MEM_BKT: {
+ Half field;
+ Tree *val;
+ read_half( field );
+ read_tree( val );
+
+ debug( prg, REALM_BYTECODE, "IN_SET_LIST_MEM_BKT %hd\n", field );
+
+ treeDownref( prg, sp, val );
+ break;
+ }
+ case IN_MAP_INSERT_BKT: {
+ /* uchar inserted; */
+ Tree *key;
+ consume_byte();
+ read_tree( key );
+
+ debug( prg, REALM_BYTECODE, "IN_MAP_INSERT_BKT\n" );
+
+ treeDownref( prg, sp, key );
+ break;
+ }
+ case IN_MAP_STORE_BKT: {
+ Tree *key, *val;
+ read_tree( key );
+ read_tree( val );
+
+ debug( prg, REALM_BYTECODE,"IN_MAP_STORE_BKT\n" );
+
+ treeDownref( prg, sp, key );
+ treeDownref( prg, sp, val );
+ break;
+ }
+ case IN_MAP_REMOVE_BKT: {
+ Tree *key, *val;
+ read_tree( key );
+ read_tree( val );
+
+ debug( prg, REALM_BYTECODE, "IN_MAP_REMOVE_BKT\n" );
+
+ treeDownref( prg, sp, key );
+ treeDownref( prg, sp, val );
+ break;
+ }
+ case IN_STOP: {
+ return;
+ }
+ default: {
+ fatal( "UNKNOWN INSTRUCTION 0x%2x: -- reverse code downref\n", *(instr-1));
+ assert(false);
+ break;
+ }
+ }
+ goto again;
+}
+
+void mainExecution( Program *prg, Execution *exec, Code *code )
+{
+ Tree **sp = prg->stackRoot;
+
+ FrameInfo *fi = &prg->rtd->frameInfo[prg->rtd->rootFrameId];
+ long stretch = fi->argSize + 4 + fi->frameSize;
+ vm_contiguous( stretch );
+
+ /* Set up the stack as if we have called. We allow a return value. */
+ vm_push( 0 );
+ vm_push( 0 );
+ vm_push( 0 );
+ vm_push( 0 );
+
+ /* Execution loop. */
+ executeCode( prg, exec, sp, code );
+
+ vm_pop_ignore();
+ vm_pop_ignore();
+ treeDownref( prg, sp, prg->returnVal );
+ prg->returnVal = vm_pop();
+ vm_pop_ignore();
+
+ prg->stackRoot = sp;
+}
+
+int makeReverseCode( PdaRun *pdaRun )
+{
+ RtCodeVect *reverseCode = &pdaRun->reverseCode;
+ RtCodeVect *rcodeCollect = &pdaRun->rcodeCollect;
+
+ /* Do we need to revert the left hand side? */
+
+ /* Check if there was anything generated. */
+ if ( rcodeCollect->tabLen == 0 )
+ return false;
+
+ if ( pdaRun->rcBlockCount == 0 ) {
+ /* One reverse code run for the DECK terminator. */
+ appendCode( reverseCode, IN_PCR_END_DECK );
+ appendCode( reverseCode, IN_PCR_RET );
+ appendWord( reverseCode, 2 );
+ pdaRun->rcBlockCount += 1;
+ incrementSteps( pdaRun );
+ }
+
+ long startLength = reverseCode->tabLen;
+
+ /* Go backwards, group by group, through the reverse code. Push each group
+ * to the global reverse code stack. */
+ Code *p = rcodeCollect->data + rcodeCollect->tabLen;
+ while ( p != rcodeCollect->data ) {
+ p--;
+ long len = *p;
+ p = p - len;
+ appendCode2( reverseCode, p, len );
+ }
+
+ /* Stop, then place a total length in the global stack. */
+ appendCode( reverseCode, IN_PCR_RET );
+ long length = reverseCode->tabLen - startLength;
+ appendWord( reverseCode, length );
+
+ /* Clear the revere code buffer. */
+ rcodeCollect->tabLen = 0;
+
+ pdaRun->rcBlockCount += 1;
+ incrementSteps( pdaRun );
+
+ return true;
+}
+
+void transferReverseCode( PdaRun *pdaRun, ParseTree *parseTree )
+{
+ if ( pdaRun->rcBlockCount > 0 ) {
+ //debug( REALM_PARSE, "attaching reverse code to token\n" );
+ parseTree->flags |= PF_HAS_RCODE;
+ pdaRun->rcBlockCount = 0;
+ }
+}
+
+void rcodeUnitTerm( Execution *exec )
+{
+ appendCode( &exec->parser->pdaRun->rcodeCollect, exec->rcodeUnitLen );
+ exec->rcodeUnitLen = 0;
+}
+
+void rcodeUnitStart( Execution *exec )
+{
+ exec->rcodeUnitLen = 0;
+}
+
+void rcodeCode( Execution *exec, const Code code )
+{
+ appendCode( &exec->parser->pdaRun->rcodeCollect, code );
+ exec->rcodeUnitLen += SIZEOF_CODE;
+}
+
+void rcodeHalf( Execution *exec, const Half half )
+{
+ appendHalf( &exec->parser->pdaRun->rcodeCollect, half );
+ exec->rcodeUnitLen += SIZEOF_HALF;
+}
+
+void rcodeWord( Execution *exec, const Word word )
+{
+ appendWord( &exec->parser->pdaRun->rcodeCollect, word );
+ exec->rcodeUnitLen += SIZEOF_WORD;
+}
+
+Code *popReverseCode( 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;
+
+ /* Backup over it. */
+ allRev->tabLen -= len + SIZEOF_WORD;
+ return prcode;
+}
+
+Tree **executeCode( Program *prg, 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;
+ Code c;
+
+again:
+ c = *instr++;
+ //debug( REALM_BYTECODE, "--in 0x%x\n", c );
+
+ switch ( c ) {
+ case IN_RESTORE_LHS: {
+ Tree *restore;
+ read_tree( restore );
+
+ debug( prg, REALM_BYTECODE, "IN_RESTORE_LHS\n" );
+ treeDownref( prg, sp, exec->parser->pdaRun->parseInput->shadow->tree );
+ exec->parser->pdaRun->parseInput->shadow->tree = restore;
+ break;
+ }
+ case IN_LOAD_NIL: {
+ debug( prg, REALM_BYTECODE, "IN_LOAD_NIL\n" );
+ vm_push( 0 );
+ break;
+ }
+ case IN_LOAD_TREE: {
+ Tree *tree;
+ read_tree( tree );
+ vm_push( tree );
+ debug( prg, REALM_BYTECODE, "IN_LOAD_TREE %p id: %d refs: %d\n", tree, tree->id, tree->refs );
+ break;
+ }
+ case IN_LOAD_WORD: {
+ debug( prg, REALM_BYTECODE, "IN_LOAD_WORD\n" );
+ Word w;
+ read_word( w );
+ vm_push( (SW)w );
+ break;
+ }
+ case IN_LOAD_TRUE: {
+ debug( prg, REALM_BYTECODE, "IN_LOAD_TRUE\n" );
+ treeUpref( prg->trueVal );
+ vm_push( prg->trueVal );
+ break;
+ }
+ case IN_LOAD_FALSE: {
+ debug( prg, REALM_BYTECODE, "IN_LOAD_FALSE\n" );
+ treeUpref( prg->falseVal );
+ vm_push( prg->falseVal );
+ break;
+ }
+ case IN_LOAD_INT: {
+ Word i;
+ read_word( i );
+
+ debug( prg, REALM_BYTECODE, "IN_LOAD_INT %d\n", i );
+
+ Tree *tree = constructInteger( prg, i );
+ treeUpref( tree );
+ vm_push( tree );
+ break;
+ }
+ case IN_LOAD_STR: {
+ Word offset;
+ read_word( offset );
+
+ debug( prg, REALM_BYTECODE, "IN_LOAD_STR %d\n", offset );
+
+ Head *lit = makeLiteral( prg, offset );
+ Tree *tree = constructString( prg, lit );
+ treeUpref( tree );
+ vm_push( tree );
+ break;
+ }
+ case IN_PRINT: {
+ int n, i;
+ read_byte( n );
+ debug( prg, REALM_BYTECODE, "IN_PRINT %d\n", n );
+
+ Tree *arg[n];
+ for ( i = n-1; i >= 0; i-- )
+ arg[i] = vm_pop();
+
+ for ( i = 0; i < n; i++ )
+ printTreeFile( prg, sp, stdout, arg[i], false );
+
+ for ( i = 0; i < n; i++ )
+ treeDownref( prg, sp, arg[i] );
+ break;
+ }
+ case IN_PRINT_STREAM: {
+ int n, i;
+ read_byte( n );
+ debug( prg, REALM_BYTECODE, "IN_PRINT_STREAM\n" );
+
+ Tree *arg[n];
+ for ( i = n-1; i >= 0; i-- )
+ arg[i] = vm_pop();
+ Stream *stream = (Stream*)vm_pop();
+
+ for ( i = 0; i < n; i++ ) {
+ if ( stream->in->file != 0 )
+ printTreeFile( prg, sp, stream->in->file, arg[i], false );
+ else
+ printTreeFd( prg, sp, stream->in->fd, arg[i], false );
+ }
+
+ for ( i = 0; i < n; i++ )
+ treeDownref( prg, sp, arg[i] );
+ treeDownref( prg, sp, (Tree*)stream );
+ break;
+ }
+ case IN_PRINT_XML_AC: {
+ int n, i;
+ read_byte( n );
+
+ debug( prg, REALM_BYTECODE, "IN_PRINT_XML_AC %d\n", n );
+
+ Tree *arg[n];
+ for ( i = n-1; i >= 0; i-- )
+ arg[i] = vm_pop();
+
+ for ( i = 0; i < n; i++ )
+ printXmlStdout( prg, sp, arg[i], true, true );
+
+ for ( i = 0; i < n; i++ )
+ treeDownref( prg, sp, arg[i] );
+ break;
+ }
+ case IN_PRINT_XML: {
+ int n, i;
+ read_byte( n );
+ debug( prg, REALM_BYTECODE, "IN_PRINT_XML %d", n );
+
+ Tree *arg[n];
+ for ( i = n-1; i >= 0; i-- )
+ arg[i] = vm_pop();
+
+ for ( i = 0; i < n; i++ )
+ printXmlStdout( prg, sp, arg[i], false, true );
+
+ for ( i = 0; i < n; i++ )
+ treeDownref( prg, sp, arg[i] );
+ break;
+ }
+ case IN_LOAD_CONTEXT_R: {
+ debug( prg, REALM_BYTECODE, "IN_LOAD_CONTEXT_R\n" );
+
+ treeUpref( exec->parser->pdaRun->context );
+ vm_push( exec->parser->pdaRun->context );
+ break;
+ }
+ case IN_LOAD_CONTEXT_WV: {
+ debug( prg, REALM_BYTECODE, "IN_LOAD_CONTEXT_WV\n" );
+
+ treeUpref( exec->parser->pdaRun->context );
+ vm_push( exec->parser->pdaRun->context );
+
+ /* Set up the reverse instruction. */
+ rcodeUnitStart( exec );
+ rcodeCode( exec, IN_LOAD_CONTEXT_BKT );
+ break;
+ }
+ case IN_LOAD_CONTEXT_WC: {
+ debug( prg, REALM_BYTECODE, "IN_LOAD_CONTEXT_WC\n" );
+
+ /* This is identical to the _R version, but using it for writing
+ * would be confusing. */
+ treeUpref( exec->parser->pdaRun->context );
+ vm_push( exec->parser->pdaRun->context );
+ break;
+ }
+ case IN_LOAD_CONTEXT_BKT: {
+ debug( prg, REALM_BYTECODE, "IN_LOAD_CONTEXT_BKT\n" );
+
+ treeUpref( exec->parser->pdaRun->context );
+ vm_push( exec->parser->pdaRun->context );
+ break;
+ }
+ case IN_LOAD_GLOBAL_R: {
+ debug( prg, REALM_BYTECODE, "IN_LOAD_GLOBAL_R\n" );
+
+ treeUpref( prg->global );
+ vm_push( prg->global );
+ break;
+ }
+ case IN_LOAD_GLOBAL_WV: {
+ debug( prg, REALM_BYTECODE, "IN_LOAD_GLOBAL_WV\n" );
+
+ treeUpref( prg->global );
+ vm_push( prg->global );
+
+ /* Set up the reverse instruction. */
+ rcodeUnitStart( exec );
+ rcodeCode( exec, IN_LOAD_GLOBAL_BKT );
+ break;
+ }
+ case IN_LOAD_GLOBAL_WC: {
+ debug( prg, REALM_BYTECODE, "IN_LOAD_GLOBAL_WC\n" );
+
+ /* This is identical to the _R version, but using it for writing
+ * would be confusing. */
+ treeUpref( prg->global );
+ vm_push( prg->global );
+ break;
+ }
+ case IN_LOAD_GLOBAL_BKT: {
+ debug( prg, REALM_BYTECODE, "IN_LOAD_GLOBAL_BKT\n" );
+
+ treeUpref( prg->global );
+ vm_push( prg->global );
+ break;
+ }
+ case IN_LOAD_PARSER_R: {
+ debug( prg, REALM_BYTECODE, "IN_LOAD_PARSER_R\n" );
+
+ treeUpref( (Tree*)exec->parser );
+ vm_push( (Tree*)exec->parser );
+ assert( exec->parser != 0 );
+ break;
+ }
+ case IN_LOAD_PARSER_WV: {
+ debug( prg, REALM_BYTECODE, "IN_LOAD_PARSER_WV\n" );
+
+ treeUpref( (Tree*)exec->parser );
+ vm_push( (Tree*)exec->parser );
+ assert( exec->parser != 0 );
+
+ /* Set up the reverse instruction. */
+ rcodeUnitStart( exec );
+ rcodeCode( exec, IN_LOAD_PARSER_BKT );
+ rcodeWord( exec, (Word)exec->parser );
+ break;
+ }
+ case IN_LOAD_PARSER_WC: {
+ debug( prg, REALM_BYTECODE, "IN_LOAD_PARSER_WC\n" );
+
+ /* This is identical to the _R version, but using it for writing
+ * would be confusing. */
+ treeUpref( (Tree*)exec->parser );
+ vm_push( (Tree*)exec->parser );
+ assert( exec->parser != 0 );
+ break;
+ }
+ case IN_LOAD_PARSER_BKT: {
+ Tree *parser;
+ read_tree( parser );
+
+ debug( prg, REALM_BYTECODE, "IN_LOAD_PARSER_BKT\n" );
+
+ treeUpref( parser );
+ vm_push( parser );
+ break;
+ }
+ case IN_LOAD_INPUT_R: {
+ debug( prg, REALM_BYTECODE, "IN_LOAD_INPUT_R\n" );
+
+ assert( exec->parser != 0 );
+ treeUpref( (Tree*)exec->parser->input );
+ vm_push( (Tree*)exec->parser->input );
+ break;
+ }
+ case IN_LOAD_INPUT_WV: {
+ debug( prg, REALM_BYTECODE, "IN_LOAD_INPUT_WV\n" );
+
+ assert( exec->parser != 0 );
+ treeUpref( (Tree*)exec->parser->input );
+ vm_push( (Tree*)exec->parser->input );
+
+ /* Set up the reverse instruction. */
+ rcodeUnitStart( exec );
+ rcodeCode( exec, IN_LOAD_INPUT_BKT );
+ rcodeWord( exec, (Word)exec->parser->input );
+ break;
+ }
+ case IN_LOAD_INPUT_WC: {
+ debug( prg, REALM_BYTECODE, "IN_LOAD_INPUT_WC\n" );
+
+ /* This is identical to the _R version, but using it for writing
+ * would be confusing. */
+ assert( exec->parser != 0 );
+ treeUpref( (Tree*)exec->parser->input );
+ vm_push( (Tree*)exec->parser->input );
+ break;
+ }
+ case IN_LOAD_INPUT_BKT: {
+ Tree *accumStream;
+ read_tree( accumStream );
+
+ debug( prg, REALM_BYTECODE, "IN_LOAD_INPUT_BKT\n" );
+
+ treeUpref( accumStream );
+ vm_push( accumStream );
+ break;
+ }
+ case IN_LOAD_CTX_R: {
+ debug( prg, REALM_BYTECODE, "IN_LOAD_CTX_R\n" );
+
+ treeUpref( exec->parser->pdaRun->context );
+ vm_push( exec->parser->pdaRun->context );
+ break;
+ }
+ case IN_LOAD_CTX_WV: {
+ debug( prg, REALM_BYTECODE, "IN_LOAD_CTX_WV\n" );
+
+ treeUpref( exec->parser->pdaRun->context );
+ vm_push( exec->parser->pdaRun->context );
+
+ /* Set up the reverse instruction. */
+ rcodeUnitStart( exec );
+ rcodeCode( exec, IN_LOAD_PARSER_BKT );
+ rcodeWord( exec, (Word)exec->parser );
+ break;
+ }
+ case IN_LOAD_CTX_WC: {
+ debug( prg, REALM_BYTECODE, "IN_LOAD_CTX_WC\n" );
+
+ /* This is identical to the _R version, but using it for writing
+ * would be confusing. */
+ treeUpref( exec->parser->pdaRun->context );
+ vm_push( exec->parser->pdaRun->context );
+ break;
+ }
+ case IN_LOAD_CTX_BKT: {
+ debug( prg, REALM_BYTECODE, "IN_LOAD_CTX_BKT\n" );
+
+ treeUpref( exec->parser->pdaRun->context );
+ vm_push( exec->parser->pdaRun->context );
+ break;
+ }
+ case IN_INIT_CAPTURES: {
+ /* uchar ncaps; */
+ consume_byte();
+
+ debug( prg, REALM_BYTECODE, "IN_INIT_CAPTURES\n" );
+
+ /* 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->parser->pdaRun->fsmRun->mark;
+
+ int i;
+ for ( i = 0; i < lelInfo[exec->parser->pdaRun->tokenId].numCaptureAttr; i++ ) {
+ CaptureAttr *ca = &prg->rtd->captureAttr[lelInfo[exec->parser->pdaRun->tokenId].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->framePtr, -1 - i, string );
+ }
+ break;
+ }
+ case IN_INIT_RHS_EL: {
+ Half position;
+ short field;
+ read_half( position );
+ read_half( field );
+
+ debug( prg, REALM_BYTECODE, "IN_INIT_RHS_EL %hd\n", field );
+
+ Tree *val = getRhsEl( prg, exec->parser->pdaRun->redLel->shadow->tree, position );
+ treeUpref( val );
+ vm_local(field) = val;
+ break;
+ }
+
+ case IN_INIT_LHS_EL: {
+ short field;
+ read_half( field );
+
+ debug( prg, REALM_BYTECODE, "IN_INIT_LHS_EL %hd\n", field );
+
+ /* We transfer it to to the local field. Possibly take a copy. */
+ Tree *val = exec->parser->pdaRun->redLel->shadow->tree;
+
+ /* Save it. */
+ treeUpref( val );
+ exec->parser->pdaRun->parsed = val;
+
+ exec->parser->pdaRun->redLel->shadow->tree = 0;
+ vm_local(field) = val;
+ break;
+ }
+ case IN_STORE_LHS_EL: {
+ short field;
+ read_half( field );
+
+ debug( prg, REALM_BYTECODE, "IN_STORE_LHS_EL %hd\n", field );
+
+ Tree *val = vm_local(field);
+ vm_local(field) = 0;
+ exec->parser->pdaRun->redLel->shadow->tree = val;
+ break;
+ }
+ case IN_UITER_ADVANCE: {
+ short field;
+ read_half( field );
+
+ debug( prg, REALM_BYTECODE, "IN_UITER_ADVANCE\n" );
+
+ /* Get the iterator. */
+ UserIter *uiter = (UserIter*) vm_local(field);
+
+ long yieldSize = vm_ssize() - uiter->rootSize;
+ assert( uiter->yieldSize == yieldSize );
+
+ /* Fix the return instruction pointer. */
+ uiter->stackRoot[-IFR_AA + IFR_RIN] = (SW)instr;
+
+ instr = uiter->resume;
+ exec->framePtr = uiter->frame;
+ exec->iframePtr = &uiter->stackRoot[-IFR_AA];
+ break;
+ }
+ case IN_UITER_GET_CUR_R: {
+ short field;
+ read_half( field );
+
+ debug( prg, REALM_BYTECODE, "IN_UITER_GET_CUR_R\n" );
+
+ UserIter *uiter = (UserIter*) vm_local(field);
+ Tree *val = uiter->ref.kid->tree;
+ treeUpref( val );
+ vm_push( val );
+ break;
+ }
+ case IN_UITER_GET_CUR_WC: {
+ short field;
+ read_half( field );
+
+ debug( prg, REALM_BYTECODE, "IN_UITER_GET_CUR_WC\n" );
+
+ UserIter *uiter = (UserIter*) vm_local(field);
+ splitRef( prg, &sp, &uiter->ref );
+ Tree *split = uiter->ref.kid->tree;
+ treeUpref( split );
+ vm_push( split );
+ break;
+ }
+ case IN_UITER_SET_CUR_WC: {
+ short field;
+ read_half( field );
+
+ debug( prg, REALM_BYTECODE, "IN_UITER_SET_CUR_WC\n" );
+
+ Tree *t = vm_pop();
+ UserIter *uiter = (UserIter*) vm_local(field);
+ splitRef( prg, &sp, &uiter->ref );
+ Tree *old = uiter->ref.kid->tree;
+ setUiterCur( prg, uiter, t );
+ treeDownref( prg, sp, old );
+ break;
+ }
+ case IN_GET_LOCAL_R: {
+ short field;
+ read_half( field );
+
+ debug( prg, REALM_BYTECODE, "IN_GET_LOCAL_R %hd\n", field );
+
+ Tree *val = vm_local(field);
+ treeUpref( val );
+ vm_push( val );
+ break;
+ }
+ case IN_GET_LOCAL_WC: {
+ short field;
+ read_half( field );
+
+ debug( prg, REALM_BYTECODE, "IN_GET_LOCAL_WC %hd\n", field );
+
+ Tree *split = getLocalSplit( prg, exec->framePtr, field );
+ treeUpref( split );
+ vm_push( split );
+ break;
+ }
+ case IN_SET_LOCAL_WC: {
+ short field;
+ read_half( field );
+
+ debug( prg, REALM_BYTECODE, "IN_SET_LOCAL_WC %hd\n", field );
+
+ Tree *val = vm_pop();
+ treeDownref( prg, sp, vm_local(field) );
+ setLocal( exec->framePtr, field, val );
+ break;
+ }
+ case IN_SAVE_RET: {
+ debug( prg, REALM_BYTECODE, "IN_SAVE_RET\n" );
+
+ Tree *val = vm_pop();
+ vm_local(FR_RV) = val;
+ break;
+ }
+ case IN_GET_LOCAL_REF_R: {
+ short field;
+ read_half( field );
+
+ debug( prg, REALM_BYTECODE, "IN_GET_LOCAL_REF_R\n" );
+
+ Ref *ref = (Ref*) vm_plocal(field);
+ Tree *val = ref->kid->tree;
+ treeUpref( val );
+ vm_push( val );
+ break;
+ }
+ case IN_GET_LOCAL_REF_WC: {
+ short field;
+ read_half( field );
+
+ debug( prg, REALM_BYTECODE, "IN_GET_LOCAL_REF_WC\n" );
+
+ Ref *ref = (Ref*) vm_plocal(field);
+ splitRef( prg, &sp, ref );
+ Tree *val = ref->kid->tree;
+ treeUpref( val );
+ vm_push( val );
+ break;
+ }
+ case IN_SET_LOCAL_REF_WC: {
+ short field;
+ read_half( field );
+
+ debug( prg, REALM_BYTECODE, "IN_SET_LOCAL_REF_WC\n" );
+
+ Tree *val = vm_pop();
+ Ref *ref = (Ref*) vm_plocal(field);
+ splitRef( prg, &sp, ref );
+ refSetValue( prg, sp, ref, val );
+ break;
+ }
+ case IN_GET_FIELD_R: {
+ short field;
+ read_half( field );
+
+ debug( prg, REALM_BYTECODE, "IN_GET_FIELD_R %d\n", field );
+
+ Tree *obj = vm_pop();
+ treeDownref( prg, sp, obj );
+
+ Tree *val = getField( obj, field );
+ treeUpref( val );
+ vm_push( val );
+ break;
+ }
+ case IN_GET_FIELD_WC: {
+ short field;
+ read_half( field );
+
+ debug( prg, REALM_BYTECODE, "IN_GET_FIELD_WC %d\n", field );
+
+ Tree *obj = vm_pop();
+ treeDownref( prg, sp, obj );
+
+ Tree *split = getFieldSplit( prg, obj, field );
+ treeUpref( split );
+ vm_push( split );
+ break;
+ }
+ case IN_GET_FIELD_WV: {
+ short field;
+ read_half( field );
+
+ debug( prg, REALM_BYTECODE, "IN_GET_FIELD_WV\n" );
+
+ Tree *obj = vm_pop();
+ treeDownref( prg, sp, obj );
+
+ Tree *split = getFieldSplit( prg, obj, field );
+ treeUpref( split );
+ vm_push( split );
+
+ /* Set up the reverse instruction. */
+ rcodeCode( exec, IN_GET_FIELD_BKT );
+ rcodeHalf( exec, field );
+ break;
+ }
+ case IN_GET_FIELD_BKT: {
+ short field;
+ read_half( field );
+
+ debug( prg, REALM_BYTECODE, "IN_GET_FIELD_BKT\n" );
+
+ Tree *obj = vm_pop();
+ treeDownref( prg, sp, obj );
+
+ Tree *split = getFieldSplit( prg, obj, field );
+ treeUpref( split );
+ vm_push( split );
+ break;
+ }
+ case IN_SET_FIELD_WC: {
+ short field;
+ read_half( field );
+
+ debug( prg, REALM_BYTECODE, "IN_SET_FIELD_WC %d\n", field );
+
+ Tree *obj = vm_pop();
+ Tree *val = vm_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 );
+
+ debug( prg, REALM_BYTECODE, "IN_SET_FIELD_WV %d\n", field );
+
+ Tree *obj = vm_pop();
+ Tree *val = vm_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. */
+ rcodeCode( exec, IN_SET_FIELD_BKT );
+ rcodeHalf( exec, field );
+ rcodeWord( exec, (Word)prev );
+ rcodeUnitTerm( exec );
+ break;
+ }
+ case IN_SET_FIELD_BKT: {
+ short field;
+ Tree *val;
+ read_half( field );
+ read_tree( val );
+
+ debug( prg, REALM_BYTECODE, "IN_SET_FIELD_BKT\n" );
+
+ Tree *obj = vm_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 );
+
+ debug( prg, REALM_BYTECODE, "IN_SET_FIELD_LEAVE_WC\n" );
+
+ /* Note that we don't downref the object here because we are
+ * leaving it on the stack. */
+ Tree *obj = vm_pop();
+ Tree *val = vm_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. */
+ vm_push( obj );
+ break;
+ }
+ case IN_GET_RHS_VAL_R: {
+ debug( prg, REALM_BYTECODE, "IN_GET_RHS_VAL_R\n" );
+ int i, done = 0;
+ uchar len;
+
+ Tree *obj = vm_pop(), *val = 0;
+ treeDownref( prg, sp, obj );
+
+ read_byte( len );
+ for ( i = 0; i < len; i++ ) {
+ uchar prodNum, childNum;
+ read_byte( prodNum );
+ read_byte( childNum );
+ if ( !done && obj->prodNum == prodNum ) {
+ val = getRhsEl( prg, obj, childNum );
+ done = 1;
+ }
+ }
+
+ treeUpref( val );
+ vm_push( val );
+ break;
+ }
+ case IN_POP: {
+ debug( prg, REALM_BYTECODE, "IN_POP\n" );
+
+ Tree *val = vm_pop();
+ treeDownref( prg, sp, val );
+ break;
+ }
+ case IN_POP_N_WORDS: {
+ short n;
+ read_half( n );
+
+ debug( prg, REALM_BYTECODE, "IN_POP_N_WORDS %hd\n", n );
+
+ vm_popn( n );
+ break;
+ }
+ case IN_SPRINTF: {
+ debug( prg, REALM_BYTECODE, "IN_SPRINTF\n" );
+
+ Tree *f = vm_pop();
+ f++;
+ Tree *integer = vm_pop();
+ Tree *format = vm_pop();
+ Head *res = stringSprintf( prg, (Str*)format, (Int*)integer );
+ Tree *str = constructString( prg, res );
+ treeUpref( str );
+ vm_push( str );
+ treeDownref( prg, sp, integer );
+ treeDownref( prg, sp, format );
+ break;
+ }
+ case IN_STR_ATOI: {
+ debug( prg, REALM_BYTECODE, "IN_STR_ATOI\n" );
+
+ Str *str = (Str*)vm_pop();
+ Word res = strAtoi( str->value );
+ Tree *integer = constructInteger( prg, res );
+ treeUpref( integer );
+ vm_push( integer );
+ treeDownref( prg, sp, (Tree*)str );
+ break;
+ }
+ case IN_INT_TO_STR: {
+ debug( prg, REALM_BYTECODE, "IN_INT_TO_STR\n" );
+
+ Int *i = (Int*)vm_pop();
+ Head *res = intToStr( prg, i->value );
+ Tree *str = constructString( prg, res );
+ treeUpref( str );
+ vm_push( str );
+ treeDownref( prg, sp, (Tree*) i );
+ break;
+ }
+ case IN_TREE_TO_STR: {
+ debug( prg, REALM_BYTECODE, "IN_TREE_TO_STR\n" );
+
+ Tree *tree = vm_pop();
+ Head *res = treeToStr( prg, sp, tree, false );
+ Tree *str = constructString( prg, res );
+ treeUpref( str );
+ vm_push( str );
+ treeDownref( prg, sp, tree );
+ break;
+ }
+ case IN_TREE_TO_STR_TRIM: {
+ debug( prg, REALM_BYTECODE, "IN_TREE_TO_STR_TRIM\n" );
+
+ Tree *tree = vm_pop();
+ Head *res = treeToStr( prg, sp, tree, true );
+ Tree *str = constructString( prg, res );
+ treeUpref( str );
+ vm_push( str );
+ treeDownref( prg, sp, tree );
+ break;
+ }
+ case IN_TREE_TRIM: {
+ debug( prg, REALM_BYTECODE, "IN_TREE_TRIM\n" );
+
+ Tree *tree = vm_pop();
+ Tree *trimmed = treeTrim( prg, sp, tree );
+ vm_push( trimmed );
+ break;
+ }
+ case IN_CONCAT_STR: {
+ debug( prg, REALM_BYTECODE, "IN_CONCAT_STR\n" );
+
+ Str *s2 = (Str*)vm_pop();
+ Str *s1 = (Str*)vm_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 );
+ vm_push( str );
+ break;
+ }
+ case IN_STR_UORD8: {
+ debug( prg, REALM_BYTECODE, "IN_STR_UORD8\n" );
+
+ Str *str = (Str*)vm_pop();
+ Word res = strUord8( str->value );
+ Tree *tree = constructInteger( prg, res );
+ treeUpref( tree );
+ vm_push( tree );
+ treeDownref( prg, sp, (Tree*)str );
+ break;
+ }
+ case IN_STR_UORD16: {
+ debug( prg, REALM_BYTECODE, "IN_STR_UORD16\n" );
+
+ Str *str = (Str*)vm_pop();
+ Word res = strUord16( str->value );
+ Tree *tree = constructInteger( prg, res );
+ treeUpref( tree );
+ vm_push( tree );
+ treeDownref( prg, sp, (Tree*)str );
+ break;
+ }
+
+ case IN_STR_LENGTH: {
+ debug( prg, REALM_BYTECODE, "IN_STR_LENGTH\n" );
+
+ Str *str = (Str*)vm_pop();
+ long len = stringLength( str->value );
+ Tree *res = constructInteger( prg, len );
+ treeUpref( res );
+ vm_push( res );
+ treeDownref( prg, sp, (Tree*)str );
+ break;
+ }
+ case IN_JMP_FALSE: {
+ short dist;
+ read_half( dist );
+
+ debug( prg, REALM_BYTECODE, "IN_JMP_FALSE %d\n", dist );
+
+ Tree *tree = vm_pop();
+ if ( testFalse( prg, tree ) )
+ instr += dist;
+ treeDownref( prg, sp, tree );
+ break;
+ }
+ case IN_JMP_TRUE: {
+ short dist;
+ read_half( dist );
+
+ debug( prg, REALM_BYTECODE, "IN_JMP_TRUE %d\n", dist );
+
+ Tree *tree = vm_pop();
+ if ( !testFalse( prg, tree ) )
+ instr += dist;
+ treeDownref( prg, sp, tree );
+ break;
+ }
+ case IN_JMP: {
+ short dist;
+ read_half( dist );
+
+ debug( prg, REALM_BYTECODE, "IN_JMP\n" );
+
+ instr += dist;
+ break;
+ }
+ case IN_REJECT: {
+ debug( prg, REALM_BYTECODE, "IN_REJECT\n" );
+ exec->parser->pdaRun->reject = true;
+ break;
+ }
+
+ /*
+ * Binary comparison operators.
+ */
+ case IN_TST_EQL: {
+ debug( prg, REALM_BYTECODE, "IN_TST_EQL\n" );
+
+ Tree *o2 = vm_pop();
+ Tree *o1 = vm_pop();
+ long r = cmpTree( prg, o1, o2 );
+ Tree *val = r ? prg->falseVal : prg->trueVal;
+ treeUpref( val );
+ vm_push( val );
+ treeDownref( prg, sp, o1 );
+ treeDownref( prg, sp, o2 );
+ break;
+ }
+ case IN_TST_NOT_EQL: {
+ debug( prg, REALM_BYTECODE, "IN_TST_NOT_EQL\n" );
+
+ Tree *o2 = vm_pop();
+ Tree *o1 = vm_pop();
+ long r = cmpTree( prg, o1, o2 );
+ Tree *val = r ? prg->trueVal : prg->falseVal;
+ treeUpref( val );
+ vm_push( val );
+ treeDownref( prg, sp, o1 );
+ treeDownref( prg, sp, o2 );
+ break;
+ }
+ case IN_TST_LESS: {
+ debug( prg, REALM_BYTECODE, "IN_TST_LESS\n" );
+
+ Tree *o2 = vm_pop();
+ Tree *o1 = vm_pop();
+ long r = cmpTree( prg, o1, o2 );
+ Tree *val = r < 0 ? prg->trueVal : prg->falseVal;
+ treeUpref( val );
+ vm_push( val );
+ treeDownref( prg, sp, o1 );
+ treeDownref( prg, sp, o2 );
+ break;
+ }
+ case IN_TST_LESS_EQL: {
+ debug( prg, REALM_BYTECODE, "IN_TST_LESS_EQL\n" );
+
+ Tree *o2 = vm_pop();
+ Tree *o1 = vm_pop();
+ long r = cmpTree( prg, o1, o2 );
+ Tree *val = r <= 0 ? prg->trueVal : prg->falseVal;
+ treeUpref( val );
+ vm_push( val );
+ treeDownref( prg, sp, o1 );
+ treeDownref( prg, sp, o2 );
+ }
+ case IN_TST_GRTR: {
+ debug( prg, REALM_BYTECODE, "IN_TST_GRTR\n" );
+
+ Tree *o2 = vm_pop();
+ Tree *o1 = vm_pop();
+ long r = cmpTree( prg, o1, o2 );
+ Tree *val = r > 0 ? prg->trueVal : prg->falseVal;
+ treeUpref( val );
+ vm_push( val );
+ treeDownref( prg, sp, o1 );
+ treeDownref( prg, sp, o2 );
+ break;
+ }
+ case IN_TST_GRTR_EQL: {
+ debug( prg, REALM_BYTECODE, "IN_TST_GRTR_EQL\n" );
+
+ Tree *o2 = (Tree*)vm_pop();
+ Tree *o1 = (Tree*)vm_pop();
+ long r = cmpTree( prg, o1, o2 );
+ Tree *val = r >= 0 ? prg->trueVal : prg->falseVal;
+ treeUpref( val );
+ vm_push( val );
+ treeDownref( prg, sp, o1 );
+ treeDownref( prg, sp, o2 );
+ break;
+ }
+ case IN_TST_LOGICAL_AND: {
+ debug( prg, REALM_BYTECODE, "IN_TST_LOGICAL_AND\n" );
+
+ Tree *o2 = vm_pop();
+ Tree *o1 = vm_pop();
+ long v2 = !testFalse( prg, o2 );
+ long v1 = !testFalse( prg, o1 );
+ Word r = v1 && v2;
+ Tree *val = r ? prg->trueVal : prg->falseVal;
+ treeUpref( val );
+ vm_push( val );
+ treeDownref( prg, sp, o1 );
+ treeDownref( prg, sp, o2 );
+ break;
+ }
+ case IN_TST_LOGICAL_OR: {
+ debug( prg, REALM_BYTECODE, "IN_TST_LOGICAL_OR\n" );
+
+ Tree *o2 = vm_pop();
+ Tree *o1 = vm_pop();
+ long v2 = !testFalse( prg, o2 );
+ long v1 = !testFalse( prg, o1 );
+ Word r = v1 || v2;
+ Tree *val = r ? prg->trueVal : prg->falseVal;
+ treeUpref( val );
+ vm_push( val );
+ treeDownref( prg, sp, o1 );
+ treeDownref( prg, sp, o2 );
+ break;
+ }
+ case IN_NOT: {
+ debug( prg, REALM_BYTECODE, "IN_NOT\n" );
+
+ Tree *tree = (Tree*)vm_pop();
+ long r = testFalse( prg, tree );
+ Tree *val = r ? prg->trueVal : prg->falseVal;
+ treeUpref( val );
+ vm_push( val );
+ treeDownref( prg, sp, tree );
+ break;
+ }
+
+ case IN_ADD_INT: {
+ debug( prg, REALM_BYTECODE, "IN_ADD_INT\n" );
+
+ Int *o2 = (Int*)vm_pop();
+ Int *o1 = (Int*)vm_pop();
+ long r = o1->value + o2->value;
+ Tree *tree = constructInteger( prg, r );
+ treeUpref( tree );
+ vm_push( tree );
+ treeDownref( prg, sp, (Tree*)o1 );
+ treeDownref( prg, sp, (Tree*)o2 );
+ break;
+ }
+ case IN_MULT_INT: {
+ debug( prg, REALM_BYTECODE, "IN_MULT_INT\n" );
+
+ Int *o2 = (Int*)vm_pop();
+ Int *o1 = (Int*)vm_pop();
+ long r = o1->value * o2->value;
+ Tree *tree = constructInteger( prg, r );
+ treeUpref( tree );
+ vm_push( tree );
+ treeDownref( prg, sp, (Tree*)o1 );
+ treeDownref( prg, sp, (Tree*)o2 );
+ break;
+ }
+ case IN_DIV_INT: {
+ debug( prg, REALM_BYTECODE, "IN_DIV_INT\n" );
+
+ Int *o2 = (Int*)vm_pop();
+ Int *o1 = (Int*)vm_pop();
+ long r = o1->value / o2->value;
+ Tree *tree = constructInteger( prg, r );
+ treeUpref( tree );
+ vm_push( tree );
+ treeDownref( prg, sp, (Tree*)o1 );
+ treeDownref( prg, sp, (Tree*)o2 );
+ break;
+ }
+ case IN_SUB_INT: {
+ debug( prg, REALM_BYTECODE, "IN_SUB_INT\n" );
+
+ Int *o2 = (Int*)vm_pop();
+ Int *o1 = (Int*)vm_pop();
+ long r = o1->value - o2->value;
+ Tree *tree = constructInteger( prg, r );
+ treeUpref( tree );
+ vm_push( tree );
+ treeDownref( prg, sp, (Tree*)o1 );
+ treeDownref( prg, sp, (Tree*)o2 );
+ break;
+ }
+ case IN_TOP_SWAP: {
+ debug( prg, REALM_BYTECODE, "IN_TOP_SWAP\n" );
+
+ Tree *v1 = vm_pop();
+ Tree *v2 = vm_pop();
+ vm_push( v1 );
+ vm_push( v2 );
+ break;
+ }
+ case IN_DUP_TOP: {
+ debug( prg, REALM_BYTECODE, "IN_DUP_TOP\n" );
+
+ Tree *val = vm_top();
+ treeUpref( val );
+ vm_push( val );
+ break;
+ }
+ case IN_TRITER_FROM_REF: {
+ short field;
+ Half searchTypeId;
+ read_half( field );
+ read_half( searchTypeId );
+
+ debug( prg, REALM_BYTECODE, "IN_TRITER_FROM_REF\n" );
+
+ Ref rootRef;
+ rootRef.kid = (Kid*)vm_pop();
+ rootRef.next = (Ref*)vm_pop();
+ void *mem = vm_plocal(field);
+
+ Tree **stackRoot = vm_ptop();
+ long rootSize = vm_ssize();
+
+ initTreeIter( (TreeIter*)mem, stackRoot, rootSize, &rootRef, searchTypeId );
+ break;
+ }
+ case IN_TRITER_DESTROY: {
+ short field;
+ read_half( field );
+
+ debug( prg, REALM_BYTECODE, "IN_TRITER_DESTROY\n" );
+
+ TreeIter *iter = (TreeIter*) vm_plocal(field);
+ treeIterDestroy( prg, &sp, iter );
+ break;
+ }
+ case IN_REV_TRITER_FROM_REF: {
+ short field;
+ Half searchTypeId;
+ read_half( field );
+ read_half( searchTypeId );
+
+ debug( prg, REALM_BYTECODE, "IN_REV_TRITER_FROM_REF\n" );
+
+ Ref rootRef;
+ rootRef.kid = (Kid*)vm_pop();
+ rootRef.next = (Ref*)vm_pop();
+
+ Tree **stackRoot = vm_ptop();
+ long rootSize = vm_ssize();
+
+ int children = 0;
+ Kid *kid = treeChild( prg, rootRef.kid->tree );
+ while ( kid != 0 ) {
+ vm_push( (SW)kid );
+ kid = kid->next;
+ children++;
+ }
+
+ void *mem = vm_plocal(field);
+ initRevTreeIter( (RevTreeIter*)mem, stackRoot, rootSize, &rootRef, searchTypeId, children );
+ break;
+ }
+ case IN_REV_TRITER_DESTROY: {
+ short field;
+ read_half( field );
+
+ debug( prg, REALM_BYTECODE, "IN_REV_TRITER_DESTROY\n" );
+
+ RevTreeIter *iter = (RevTreeIter*) vm_plocal(field);
+ revTreeIterDestroy( prg, &sp, iter );
+ break;
+ }
+ case IN_TREE_SEARCH: {
+ Word id;
+ read_word( id );
+
+ debug( prg, REALM_BYTECODE, "IN_TREE_SEARCH\n" );
+
+ Tree *tree = vm_pop();
+ Tree *res = treeSearch( prg, tree, id );
+ treeUpref( res );
+ vm_push( res );
+ treeDownref( prg, sp, tree );
+ break;
+ }
+ case IN_TRITER_ADVANCE: {
+ short field;
+ read_half( field );
+
+ debug( prg, REALM_BYTECODE, "IN_TRITER_ADVANCE\n" );
+
+ TreeIter *iter = (TreeIter*) vm_plocal(field);
+ Tree *res = treeIterAdvance( prg, &sp, iter );
+ treeUpref( res );
+ vm_push( res );
+ break;
+ }
+ case IN_TRITER_NEXT_CHILD: {
+ short field;
+ read_half( field );
+
+ debug( prg, REALM_BYTECODE, "IN_TRITER_NEXT_CHILD\n" );
+
+ TreeIter *iter = (TreeIter*) vm_plocal(field);
+ Tree *res = treeIterNextChild( prg, &sp, iter );
+ treeUpref( res );
+ vm_push( res );
+ break;
+ }
+ case IN_REV_TRITER_PREV_CHILD: {
+ short field;
+ read_half( field );
+
+ debug( prg, REALM_BYTECODE, "IN_REV_TRITER_PREV_CHILD\n" );
+
+ RevTreeIter *iter = (RevTreeIter*) vm_plocal(field);
+ Tree *res = treeRevIterPrevChild( prg, &sp, iter );
+ treeUpref( res );
+ vm_push( res );
+ break;
+ }
+ case IN_TRITER_NEXT_REPEAT: {
+ short field;
+ read_half( field );
+
+ debug( prg, REALM_BYTECODE, "IN_TRITER_NEXT_REPEAT\n" );
+
+ TreeIter *iter = (TreeIter*) vm_plocal(field);
+ Tree *res = treeIterNextRepeat( prg, &sp, iter );
+ treeUpref( res );
+ vm_push( res );
+ break;
+ }
+ case IN_TRITER_PREV_REPEAT: {
+ short field;
+ read_half( field );
+
+ debug( prg, REALM_BYTECODE, "IN_TRITER_PREV_REPEAT\n" );
+
+ TreeIter *iter = (TreeIter*) vm_plocal(field);
+ Tree *res = treeIterPrevRepeat( prg, &sp, iter );
+ treeUpref( res );
+ vm_push( res );
+ break;
+ }
+ case IN_TRITER_GET_CUR_R: {
+ short field;
+ read_half( field );
+
+ debug( prg, REALM_BYTECODE, "IN_TRITER_GET_CUR_R\n" );
+
+ TreeIter *iter = (TreeIter*) vm_plocal(field);
+ Tree *tree = treeIterDerefCur( iter );
+ treeUpref( tree );
+ vm_push( tree );
+ break;
+ }
+ case IN_TRITER_GET_CUR_WC: {
+ short field;
+ read_half( field );
+
+ debug( prg, REALM_BYTECODE, "IN_TRITER_GET_CUR_WC\n" );
+
+ TreeIter *iter = (TreeIter*) vm_plocal(field);
+ splitIterCur( prg, &sp, iter );
+ Tree *tree = treeIterDerefCur( iter );
+ treeUpref( tree );
+ vm_push( tree );
+ break;
+ }
+ case IN_TRITER_SET_CUR_WC: {
+ short field;
+ read_half( field );
+
+ debug( prg, REALM_BYTECODE, "IN_TRITER_SET_CUR_WC\n" );
+
+ Tree *tree = vm_pop();
+ TreeIter *iter = (TreeIter*) vm_plocal(field);
+ splitIterCur( prg, &sp, iter );
+ Tree *old = treeIterDerefCur( iter );
+ setTriterCur( prg, iter, tree );
+ treeDownref( prg, sp, old );
+ break;
+ }
+ case IN_MATCH: {
+ Half patternId;
+ read_half( patternId );
+
+ debug( prg, REALM_BYTECODE, "IN_MATCH\n" );
+
+ Tree *tree = vm_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 );
+ }
+
+ Tree *result = matched ? tree : 0;
+ treeUpref( result );
+ vm_push( result ? tree : 0 );
+ int b;
+ for ( b = 1; b <= numBindings; b++ ) {
+ treeUpref( bindings[b] );
+ vm_push( bindings[b] );
+ }
+
+ treeDownref( prg, sp, tree );
+ break;
+ }
+
+ case IN_GET_PARSER_CTX_R: {
+ debug( prg, REALM_BYTECODE, "IN_GET_PARSER_CTX_R\n" );
+
+ Tree *obj = vm_pop();
+ Tree *ctx = ((Parser*)obj)->pdaRun->context;
+ treeUpref( ctx );
+ vm_push( ctx );
+ treeDownref( prg, sp, obj );
+ break;
+ }
+
+ case IN_SET_PARSER_CTX_WC: {
+ debug( prg, REALM_BYTECODE, "IN_SET_PARSER_CTX_WC\n" );
+
+ Tree *parser = vm_pop();
+ Tree *val = vm_pop();
+ parserSetContext( prg, sp, (Parser*)parser, val );
+ treeDownref( prg, sp, parser );
+ break;
+ }
+
+// case IN_GET_PARSER_CTX_WC:
+// case IN_GET_PARSER_CTX_WV:
+// case IN_SET_PARSER_CTX_WC:
+// case IN_SET_PARSER_CTX_WV:
+// break;
+
+ case IN_INPUT_APPEND_WC: {
+ debug( prg, REALM_BYTECODE, "IN_INPUT_APPEND_WC \n" );
+
+ Stream *accumStream = (Stream*)vm_pop();
+ Tree *input = vm_pop();
+ streamAppend( prg, sp, input, accumStream->in );
+
+ vm_push( (Tree*)accumStream );
+ treeDownref( prg, sp, input );
+ break;
+ }
+ case IN_INPUT_APPEND_WV: {
+ debug( prg, REALM_BYTECODE, "IN_INPUT_APPEND_WV \n" );
+
+ Stream *accumStream = (Stream*)vm_pop();
+ Tree *input = vm_pop();
+ Word len = streamAppend( prg, sp, input, accumStream->in );
+
+ treeUpref( (Tree*)accumStream );
+ vm_push( (Tree*)accumStream );
+
+ rcodeUnitStart( exec );
+ rcodeCode( exec, IN_INPUT_APPEND_BKT );
+ rcodeWord( exec, (Word) accumStream );
+ rcodeWord( exec, (Word) input );
+ rcodeWord( exec, (Word) len );
+ rcodeUnitTerm( exec );
+ break;
+ }
+
+ case IN_INPUT_APPEND_BKT: {
+ Tree *accumStream;
+ Tree *input;
+ Word len;
+ read_tree( accumStream );
+ read_tree( input );
+ read_word( len );
+
+ debug( prg, REALM_BYTECODE, "IN_INPUT_APPEND_BKT\n" );
+
+ undoStreamAppend( prg, sp, ((Stream*)accumStream)->in, input, len );
+ treeDownref( prg, sp, accumStream );
+ treeDownref( prg, sp, input );
+ break;
+ }
+
+ case IN_SET_ERROR: {
+ debug( prg, REALM_BYTECODE, "IN_SET_ERROR\n" );
+
+ Tree *error = vm_pop();
+ treeDownref( prg, sp, prg->error );
+ prg->error = error;
+ break;
+ }
+
+ case IN_GET_ERROR: {
+ debug( prg, REALM_BYTECODE, "IN_GET_ERROR\n" );
+
+ Tree *obj = vm_pop();
+ treeDownref( prg, sp, obj );
+
+ treeUpref( (Tree*)prg->error );
+ vm_push( (Tree*)prg->error );
+ break;
+ }
+
+ case IN_PARSE_SAVE_STEPS: {
+ debug( prg, REALM_BYTECODE, "IN_PARSE_SAVE_STEPS\n" );
+
+ Parser *parser = (Parser*)vm_pop();
+ long steps = parser->pdaRun->steps;
+
+ vm_push( (SW)exec->parser );
+ vm_push( (SW)exec->pcr );
+ vm_push( (SW)exec->steps );
+
+ exec->parser = parser;
+ exec->steps = steps;
+ exec->pcr = PcrStart;
+ break;
+ }
+
+ case IN_PARSE_INIT_BKT: {
+ debug( prg, REALM_BYTECODE, "IN_PARSE_INIT_BKT\n" );
+
+ Tree *parser;
+ Word pcr;
+ Word steps;
+
+ read_tree( parser );
+ read_word( pcr );
+ read_word( steps );
+
+ vm_push( (SW)exec->parser );
+ vm_push( (SW)exec->pcr );
+ vm_push( (SW)exec->steps );
+
+ exec->parser = (Parser*)parser;
+ exec->steps = steps;
+ exec->pcr = pcr;
+ break;
+ }
+
+ case IN_PCR_CALL: {
+ debug( prg, REALM_BYTECODE, "IN_PCR_CALL\n" );
+
+ FrameInfo *fi = &prg->rtd->frameInfo[exec->parser->pdaRun->frameId];
+ long stretch = fi->argSize + 4 + fi->frameSize;
+ vm_contiguous( stretch );
+
+ vm_push( (SW)exec->framePtr );
+ vm_push( (SW)exec->iframePtr );
+ vm_push( (SW)exec->frameId );
+
+ /* Return location one instruction back. Depends on the size of of the frag/finish. */
+ Code *returnTo = instr - ( SIZEOF_CODE + SIZEOF_CODE + SIZEOF_HALF );
+ vm_push( (SW)returnTo );
+
+ exec->framePtr = 0;
+ exec->iframePtr = 0;
+ exec->frameId = 0;
+
+ exec->frameId = exec->parser->pdaRun->frameId;
+
+ instr = exec->parser->pdaRun->code;
+ break;
+ }
+
+ case IN_PCR_RET: {
+ debug( prg, REALM_BYTECODE, "IN_PCR_RET\n" );
+
+ FrameInfo *fi = &prg->rtd->frameInfo[exec->frameId];
+ downrefLocalTrees( prg, sp, exec->framePtr, fi->locals, fi->localsLen );
+ debug( prg, REALM_BYTECODE, "RET: %d\n", fi->frameSize );
+ vm_popn( fi->frameSize );
+
+ instr = (Code*) vm_pop();
+ exec->frameId = ( long ) vm_pop();
+ exec->iframePtr = ( Tree ** ) vm_pop();
+ exec->framePtr = ( Tree ** ) vm_pop();
+
+ if ( instr == 0 ) {
+ fflush( stdout );
+ goto out;
+ }
+ break;
+ }
+
+ case IN_PCR_END_DECK: {
+ debug( prg, REALM_BYTECODE, "IN_PCR_END_DECK\n" );
+ exec->parser->pdaRun->onDeck = false;
+ break;
+ }
+
+ case IN_PARSE_FRAG_WC: {
+ Half stopId;
+ read_half( stopId );
+
+ debug( prg, REALM_BYTECODE, "IN_PARSE_FRAG_WC %hd\n", stopId );
+
+ exec->pcr = parseFrag( prg, sp, exec->parser, stopId, exec->pcr );
+
+ /* If done, jump to the terminating instruction, otherwise fall
+ * through to call some code, then jump back here. */
+ if ( exec->pcr == PcrDone )
+ instr += SIZEOF_CODE;
+ break;
+ }
+
+ case IN_PARSE_FRAG_EXIT_WC: {
+ debug( prg, REALM_BYTECODE, "IN_PARSE_FRAG_EXIT_WC\n" );
+
+ Parser *parser = exec->parser;
+
+ exec->steps = (long)vm_pop();
+ exec->pcr = (long)vm_pop();
+ exec->parser = (Parser*) vm_pop();
+
+ treeDownref( prg, sp, (Tree*)parser );
+
+ if ( prg->induceExit )
+ goto out;
+
+ break;
+ }
+
+ case IN_PARSE_FRAG_WV: {
+ Half stopId;
+ read_half( stopId );
+
+ debug( prg, REALM_BYTECODE, "IN_PARSE_FRAG_WV %hd\n", stopId );
+
+ exec->pcr = parseFrag( prg, sp, exec->parser, stopId, exec->pcr );
+
+ /* If done, jump to the terminating instruction, otherwise fall
+ * through to call some code, then jump back here. */
+ if ( exec->pcr == PcrDone )
+ instr += SIZEOF_CODE;
+ break;
+ }
+
+ case IN_PARSE_FRAG_EXIT_WV: {
+ debug( prg, REALM_BYTECODE, "IN_PARSE_FRAG_EXIT_WV \n" );
+
+ Parser *parser = exec->parser;
+ long steps = exec->steps;
+
+ exec->steps = (long)vm_pop();
+ exec->pcr = (long)vm_pop();
+ exec->parser = (Parser*)vm_pop();
+
+ rcodeUnitStart( exec );
+ rcodeCode( exec, IN_PARSE_INIT_BKT );
+ rcodeWord( exec, (Word)parser );
+ rcodeWord( exec, (Word)PcrStart );
+ rcodeWord( exec, steps );
+ rcodeCode( exec, IN_PARSE_FRAG_BKT );
+ rcodeHalf( exec, 0 );
+ rcodeCode( exec, IN_PCR_CALL );
+ rcodeCode( exec, IN_PARSE_FRAG_EXIT_BKT );
+ rcodeUnitTerm( exec );
+
+ if ( prg->induceExit )
+ goto out;
+ break;
+ }
+
+ case IN_PARSE_FRAG_BKT: {
+ Half stopId;
+ read_half( stopId );
+
+ debug( prg, REALM_BYTECODE, "IN_PARSE_FRAG_BKT %hd\n", stopId );
+
+ exec->pcr = undoParseFrag( prg, sp, exec->parser, exec->steps, exec->pcr );
+
+ if ( exec->pcr == PcrDone )
+ instr += SIZEOF_CODE;
+ break;
+ }
+
+ case IN_PARSE_FRAG_EXIT_BKT: {
+ debug( prg, REALM_BYTECODE, "IN_PARSE_FRAG_EXIT_BKT\n" );
+
+ Parser *parser = exec->parser;
+
+ exec->steps = (long)vm_pop();
+ exec->pcr = (long)vm_pop();
+ exec->parser = (Parser*)vm_pop();
+
+ treeDownref( prg, sp, (Tree*)parser );
+ break;
+ }
+
+ case IN_PARSE_FINISH_WC: {
+ Half stopId;
+ read_half( stopId );
+
+ debug( prg, REALM_BYTECODE, "IN_PARSE_FINISH_WC %hd\n", stopId );
+
+ exec->parser->result = 0;
+ exec->pcr = parseFinish( &exec->parser->result, prg, sp, exec->parser, false, exec->pcr );
+
+ /* If done, jump to the terminating instruction, otherwise fall
+ * through to call some code, then jump back here. */
+ if ( exec->pcr == PcrDone )
+ instr += SIZEOF_CODE;
+ break;
+ }
+
+ case IN_PARSE_FINISH_EXIT_WC: {
+ debug( prg, REALM_BYTECODE, "IN_PARSE_FINISH_EXIT_WC\n" );
+
+ Parser *parser = exec->parser;
+
+ exec->steps = (long)vm_pop();
+ exec->pcr = (long)vm_pop();
+ exec->parser = (Parser*)vm_pop();
+
+ vm_push( parser->result );
+ treeDownref( prg, sp, (Tree*)parser );
+ if ( prg->induceExit )
+ goto out;
+
+ break;
+ }
+
+ case IN_PARSE_FINISH_WV: {
+ Half stopId;
+ read_half( stopId );
+
+ debug( prg, REALM_BYTECODE, "IN_PARSE_FINISH_WV %hd\n", stopId );
+
+ exec->parser->result = 0;
+ exec->pcr = parseFinish( &exec->parser->result, prg, sp, exec->parser, true, exec->pcr );
+
+ if ( exec->pcr == PcrDone )
+ instr += SIZEOF_CODE;
+ break;
+ }
+
+ case IN_PARSE_FINISH_EXIT_WV: {
+ debug( prg, REALM_BYTECODE, "IN_PARSE_FINISH_EXIT_WV\n" );
+
+ Parser *parser = exec->parser;
+ long steps = exec->steps;
+
+ exec->steps = (long)vm_pop();
+ exec->pcr = (long)vm_pop();
+ exec->parser = (Parser *) vm_pop();
+
+ vm_push( parser->result );
+
+ rcodeUnitStart( exec );
+ rcodeCode( exec, IN_PARSE_INIT_BKT );
+ rcodeWord( exec, (Word)parser );
+ rcodeWord( exec, (Word)PcrStart );
+ rcodeWord( exec, steps );
+ rcodeCode( exec, IN_PARSE_FINISH_BKT );
+ rcodeHalf( exec, 0 );
+ rcodeCode( exec, IN_PCR_CALL );
+ rcodeCode( exec, IN_PARSE_FINISH_EXIT_BKT );
+ rcodeUnitTerm( exec );
+
+ if ( prg->induceExit )
+ goto out;
+
+ break;
+ }
+
+ case IN_PARSE_FINISH_BKT: {
+ Half stopId;
+ read_half( stopId );
+
+ debug( prg, REALM_BYTECODE, "IN_PARSE_FINISH_BKT %hd\n", stopId );
+
+ exec->pcr = undoParseFrag( prg, sp, exec->parser, exec->steps, exec->pcr );
+
+ if ( exec->pcr == PcrDone )
+ instr += SIZEOF_CODE;
+ break;
+ }
+
+ case IN_PARSE_FINISH_EXIT_BKT: {
+ debug( prg, REALM_BYTECODE, "IN_PARSE_FINISH_EXIT_BKT\n" );
+
+ Parser *parser = exec->parser;
+
+ exec->steps = (long)vm_pop();
+ exec->pcr = (long)vm_pop();
+ exec->parser = (Parser*)vm_pop();
+
+ parser->input->in->funcs->unsetEof( parser->input->in );
+ treeDownref( prg, sp, (Tree*)parser );
+ break;
+ }
+
+ case IN_INPUT_PULL_WV: {
+ debug( prg, REALM_BYTECODE, "IN_INPUT_PULL_WV\n" );
+
+ Stream *accumStream = (Stream*)vm_pop();
+ Tree *len = vm_pop();
+ PdaRun *pdaRun = exec->parser != 0 ? exec->parser->pdaRun : 0;
+ Tree *string = streamPullBc( prg, pdaRun, accumStream->in, len );
+ treeUpref( string );
+ vm_push( string );
+
+ /* Single unit. */
+ treeUpref( string );
+ rcodeCode( exec, IN_INPUT_PULL_BKT );
+ rcodeWord( exec, (Word) string );
+ rcodeUnitTerm( exec );
+
+ treeDownref( prg, sp, (Tree*)accumStream );
+ treeDownref( prg, sp, len );
+ break;
+ }
+
+ case IN_INPUT_PULL_WC: {
+ debug( prg, REALM_BYTECODE, "IN_INPUT_PULL_WC\n" );
+
+ Stream *accumStream = (Stream*)vm_pop();
+ Tree *len = vm_pop();
+ PdaRun *pdaRun = exec->parser != 0 ? exec->parser->pdaRun : 0;
+ Tree *string = streamPullBc( prg, pdaRun, accumStream->in, len );
+ treeUpref( string );
+ vm_push( string );
+
+ treeDownref( prg, sp, (Tree*)accumStream );
+ treeDownref( prg, sp, len );
+ break;
+ }
+ case IN_INPUT_PULL_BKT: {
+ Tree *string;
+ read_tree( string );
+
+ Tree *accumStream = vm_pop();
+
+ debug( prg, REALM_BYTECODE, "IN_INPUT_PULL_BKT\n" );
+
+ undoPull( prg, ((Stream*)accumStream)->in, string );
+ treeDownref( prg, sp, accumStream );
+ treeDownref( prg, sp, string );
+ break;
+ }
+ case IN_INPUT_PUSH_WV: {
+ debug( prg, REALM_BYTECODE, "IN_INPUT_PUSH_WV\n" );
+
+ Stream *input = (Stream*)vm_pop();
+ Tree *tree = vm_pop();
+ long len = streamPush( prg, sp, input->in, tree, false );
+ vm_push( 0 );
+
+ /* Single unit. */
+ rcodeCode( exec, IN_INPUT_PUSH_BKT );
+ rcodeWord( exec, len );
+ rcodeUnitTerm( exec );
+
+ treeDownref( prg, sp, (Tree*)input );
+ treeDownref( prg, sp, tree );
+ break;
+ }
+ case IN_INPUT_PUSH_IGNORE_WV: {
+ debug( prg, REALM_BYTECODE, "IN_INPUT_PUSH_IGNORE_WV\n" );
+
+ Stream *input = (Stream*)vm_pop();
+ Tree *tree = vm_pop();
+ long len = streamPush( prg, sp, input->in, tree, true );
+ vm_push( 0 );
+
+ /* Single unit. */
+ rcodeCode( exec, IN_INPUT_PUSH_BKT );
+ rcodeWord( exec, len );
+ rcodeUnitTerm( exec );
+
+ treeDownref( prg, sp, (Tree*)input );
+ treeDownref( prg, sp, tree );
+ break;
+ }
+ case IN_INPUT_PUSH_BKT: {
+ Word len;
+ read_word( len );
+
+ Stream *input = (Stream*)vm_pop();
+
+ debug( prg, REALM_BYTECODE, "IN_INPUT_PUSH_BKT\n" );
+
+ undoStreamPush( prg, sp, input->in, len );
+ treeDownref( prg, sp, (Tree*)input );
+ break;
+ }
+ case IN_CONSTRUCT: {
+ Half patternId;
+ read_half( patternId );
+
+ debug( prg, REALM_BYTECODE, "IN_CONSTRUCT\n" );
+
+ 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] = vm_pop();
+ assert( bindings[b] != 0 );
+ }
+
+ Tree *replTree = 0;
+ PatConsNode *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( 0, bindings,
+ prg, rootNode );
+ }
+
+ vm_push( replTree );
+ break;
+ }
+ case IN_CONSTRUCT_INPUT: {
+ debug( prg, REALM_BYTECODE, "IN_CONSTRUCT_INPUT\n" );
+
+ Tree *input = constructStream( prg );
+ treeUpref( input );
+ vm_push( input );
+ break;
+ }
+ case IN_GET_INPUT: {
+ debug( prg, REALM_BYTECODE, "IN_GET_INPUT\n" );
+
+ Parser *parser = (Parser*)vm_pop();
+ treeUpref( (Tree*)parser->input );
+ vm_push( (Tree*)parser->input );
+ treeDownref( prg, sp, (Tree*)parser );
+ break;
+ }
+ case IN_SET_INPUT: {
+ debug( prg, REALM_BYTECODE, "IN_SET_INPUT\n" );
+
+ Parser *parser = (Parser*)vm_pop();
+ Stream *accumStream = (Stream*)vm_pop();
+ parser->input = accumStream;
+ treeUpref( (Tree*)accumStream );
+ treeDownref( prg, sp, (Tree*)parser );
+ treeDownref( prg, sp, (Tree*)accumStream );
+ break;
+ }
+ case IN_CONSTRUCT_TERM: {
+ Half tokenId;
+ read_half( tokenId );
+
+ debug( prg, REALM_BYTECODE, "IN_CONSTRUCT_TERM\n" );
+
+ /* Pop the string we are constructing the token from. */
+ Str *str = (Str*)vm_pop();
+ Tree *res = constructTerm( prg, tokenId, str->value );
+ treeUpref( res );
+ vm_push( res );
+ break;
+ }
+ case IN_MAKE_TOKEN: {
+ uchar nargs;
+ int i;
+ read_byte( nargs );
+
+ debug( prg, REALM_BYTECODE, "IN_MAKE_TOKEN\n" );
+
+ Tree *arg[nargs];
+ for ( i = nargs-1; i >= 0; i-- )
+ arg[i] = vm_pop();
+
+ Tree *result = constructToken( prg, arg, nargs );
+ for ( i = 0; i < nargs; i++ )
+ treeDownref( prg, sp, arg[i] );
+ vm_push( result );
+ break;
+ }
+ case IN_MAKE_TREE: {
+ uchar nargs;
+ int i;
+ read_byte( nargs );
+
+ debug( prg, REALM_BYTECODE, "IN_MAKE_TREE\n" );
+
+ Tree *arg[nargs];
+ for ( i = nargs-1; i >= 0; i-- )
+ arg[i] = vm_pop();
+
+ Tree *result = makeTree( prg, arg, nargs );
+ for ( i = 0; i < nargs; i++ )
+ treeDownref( prg, sp, arg[i] );
+
+ vm_push( result );
+ break;
+ }
+ case IN_TREE_CAST: {
+ Half langElId;
+ read_half( langElId );
+
+ debug( prg, REALM_BYTECODE, "IN_TREE_CAST %hd\n", langElId );
+
+ Tree *tree = vm_pop();
+ Tree *res = castTree( prg, langElId, tree );
+ treeUpref( res );
+ treeDownref( prg, sp, tree );
+ vm_push( res );
+ break;
+ }
+ case IN_TREE_NEW: {
+ debug( prg, REALM_BYTECODE, "IN_TREE_NEW \n" );
+
+ Tree *tree = vm_pop();
+ Tree *res = constructPointer( prg, tree );
+ treeUpref( res );
+ vm_push( res );
+ break;
+ }
+ case IN_PTR_DEREF_R: {
+ debug( prg, REALM_BYTECODE, "IN_PTR_DEREF_R\n" );
+
+ Pointer *ptr = (Pointer*)vm_pop();
+ treeDownref( prg, sp, (Tree*)ptr );
+
+ Tree *dval = getPtrVal( ptr );
+ treeUpref( dval );
+ vm_push( dval );
+ break;
+ }
+ case IN_PTR_DEREF_WC: {
+ debug( prg, REALM_BYTECODE, "IN_PTR_DEREF_WC\n" );
+
+ Pointer *ptr = (Pointer*)vm_pop();
+ treeDownref( prg, sp, (Tree*)ptr );
+
+ Tree *dval = getPtrValSplit( prg, ptr );
+ treeUpref( dval );
+ vm_push( dval );
+ break;
+ }
+ case IN_PTR_DEREF_WV: {
+ debug( prg, REALM_BYTECODE, "IN_PTR_DEREF_WV\n" );
+
+ Pointer *ptr = (Pointer*)vm_pop();
+ /* Don't downref the pointer since it is going into the reverse
+ * instruction. */
+
+ Tree *dval = getPtrValSplit( prg, ptr );
+ treeUpref( dval );
+ vm_push( dval );
+
+ /* This is an initial global load. Need to reverse execute it. */
+ rcodeUnitStart( exec );
+ rcodeCode( exec, IN_PTR_DEREF_BKT );
+ rcodeWord( exec, (Word) ptr );
+ break;
+ }
+ case IN_PTR_DEREF_BKT: {
+ Word p;
+ read_word( p );
+
+ debug( prg, REALM_BYTECODE, "IN_PTR_DEREF_BKT\n" );
+
+ Pointer *ptr = (Pointer*)p;
+
+ Tree *dval = getPtrValSplit( prg, ptr );
+ treeUpref( dval );
+ vm_push( dval );
+
+ treeDownref( prg, sp, (Tree*)ptr );
+ break;
+ }
+ case IN_REF_FROM_LOCAL: {
+ short int field;
+ read_half( field );
+
+ debug( prg, REALM_BYTECODE, "IN_REF_FROM_LOCAL %hd\n", field );
+
+ /* First push the null next pointer, then the kid pointer. */
+ Tree **ptr = vm_plocal(field);
+ vm_contiguous( 2 );
+ vm_push( 0 );
+ vm_push( (SW)ptr );
+ break;
+ }
+ case IN_REF_FROM_REF: {
+ short int field;
+ read_half( field );
+
+ debug( prg, REALM_BYTECODE, "IN_REF_FROM_REF\n" );
+
+ Ref *ref = (Ref*)vm_plocal(field);
+ vm_contiguous( 2 );
+ vm_push( (SW)ref );
+ vm_push( (SW)ref->kid );
+ break;
+ }
+ case IN_REF_FROM_QUAL_REF: {
+ short int back;
+ short int field;
+ read_half( back );
+ read_half( field );
+
+ debug( prg, REALM_BYTECODE, "IN_REF_FROM_QUAL_REF\n" );
+
+ Ref *ref = (Ref*)(sp + back);
+
+ Tree *obj = ref->kid->tree;
+ Kid *attr_kid = getFieldKid( obj, field );
+
+ vm_contiguous( 2 );
+ vm_push( (SW)ref );
+ vm_push( (SW)attr_kid );
+ break;
+ }
+ case IN_REF_FROM_BACK: {
+ short int back;
+ read_half( back );
+
+ debug( prg, REALM_BYTECODE, "IN_REF_FROM_BACK %hd\n", back );
+
+ Tree **ptr = (Tree**)(sp + back);
+
+ vm_contiguous( 2 );
+ vm_push( 0 );
+ vm_push( (SW)ptr );
+ break;
+ }
+ case IN_TRITER_REF_FROM_CUR: {
+ short int field;
+ read_half( field );
+
+ debug( prg, REALM_BYTECODE, "IN_TRITER_REF_FROM_CUR\n" );
+
+ /* Push the next pointer first, then the kid. */
+ TreeIter *iter = (TreeIter*) vm_plocal(field);
+ Ref *ref = &iter->ref;
+ vm_contiguous( 2 );
+ vm_push( (SW)ref );
+ vm_push( (SW)iter->ref.kid );
+ break;
+ }
+ case IN_UITER_REF_FROM_CUR: {
+ short int field;
+ read_half( field );
+
+ debug( prg, REALM_BYTECODE, "IN_UITER_REF_FROM_CUR\n" );
+
+ /* Push the next pointer first, then the kid. */
+ UserIter *uiter = (UserIter*) vm_local(field);
+ vm_contiguous( 2 );
+ vm_push( (SW)uiter->ref.next );
+ vm_push( (SW)uiter->ref.kid );
+ break;
+ }
+ case IN_GET_TOKEN_DATA_R: {
+ debug( prg, REALM_BYTECODE, "IN_GET_TOKEN_DATA_R\n" );
+
+ Tree *tree = (Tree*) vm_pop();
+ Head *data = stringCopy( prg, tree->tokdata );
+ Tree *str = constructString( prg, data );
+ treeUpref( str );
+ vm_push( str );
+ treeDownref( prg, sp, tree );
+ break;
+ }
+ case IN_SET_TOKEN_DATA_WC: {
+ debug( prg, REALM_BYTECODE, "IN_SET_TOKEN_DATA_WC\n" );
+
+ Tree *tree = vm_pop();
+ Tree *val = vm_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: {
+ debug( prg, REALM_BYTECODE, "IN_SET_TOKEN_DATA_WV\n" );
+
+ Tree *tree = vm_pop();
+ Tree *val = vm_pop();
+
+ Head *oldval = tree->tokdata;
+ Head *head = stringCopy( prg, ((Str*)val)->value );
+ tree->tokdata = head;
+
+ /* Set up reverse code. Needs no args. */
+ rcodeCode( exec, IN_SET_TOKEN_DATA_BKT );
+ rcodeWord( exec, (Word)oldval );
+ rcodeUnitTerm( exec );
+
+ treeDownref( prg, sp, tree );
+ treeDownref( prg, sp, val );
+ break;
+ }
+ case IN_SET_TOKEN_DATA_BKT: {
+ debug( prg, REALM_BYTECODE, "IN_SET_TOKEN_DATA_BKT \n" );
+
+ Word oldval;
+ read_word( oldval );
+
+ Tree *tree = vm_pop();
+ Head *head = (Head*)oldval;
+ stringFree( prg, tree->tokdata );
+ tree->tokdata = head;
+ treeDownref( prg, sp, tree );
+ break;
+ }
+ case IN_GET_TOKEN_POS_R: {
+ debug( prg, REALM_BYTECODE, "IN_GET_TOKEN_POS_R\n" );
+
+ Tree *tree = (Tree*) vm_pop();
+ Tree *integer = 0;
+ if ( tree->tokdata->location ) {
+ integer = constructInteger( prg, tree->tokdata->location->byte );
+ treeUpref( integer );
+ }
+ vm_push( integer );
+ treeDownref( prg, sp, tree );
+ break;
+ }
+ case IN_GET_TOKEN_LINE_R: {
+ debug( prg, REALM_BYTECODE, "IN_GET_TOKEN_LINE_R\n" );
+
+ Tree *tree = (Tree*) vm_pop();
+ Tree *integer = 0;
+ if ( tree->tokdata->location ) {
+ integer = constructInteger( prg, tree->tokdata->location->line );
+ treeUpref( integer );
+ }
+ vm_push( integer );
+ treeDownref( prg, sp, tree );
+ break;
+ }
+ case IN_GET_MATCH_LENGTH_R: {
+ debug( prg, REALM_BYTECODE, "IN_GET_MATCH_LENGTH_R\n" );
+
+ Tree *integer = constructInteger( prg, stringLength(exec->parser->pdaRun->tokdata) );
+ treeUpref( integer );
+ vm_push( integer );
+ break;
+ }
+ case IN_GET_MATCH_TEXT_R: {
+ debug( prg, REALM_BYTECODE, "IN_GET_MATCH_TEXT_R\n" );
+
+ Head *s = stringCopy( prg, exec->parser->pdaRun->tokdata );
+ Tree *tree = constructString( prg, s );
+ treeUpref( tree );
+ vm_push( tree );
+ break;
+ }
+ case IN_LIST_LENGTH: {
+ debug( prg, REALM_BYTECODE, "IN_LIST_LENGTH\n" );
+
+ List *list = (List*) vm_pop();
+ long len = listLength( list );
+ Tree *res = constructInteger( prg, len );
+ treeDownref( prg, sp, (Tree*)list );
+ treeUpref( res );
+ vm_push( res );
+ break;
+ }
+ case IN_LIST_APPEND_WV: {
+ debug( prg, REALM_BYTECODE, "IN_LIST_APPEND_WV\n" );
+
+ Tree *obj = vm_pop();
+ Tree *val = vm_pop();
+
+ treeDownref( prg, sp, obj );
+
+ listAppend2( prg, (List*)obj, val );
+ treeUpref( prg->trueVal );
+ vm_push( prg->trueVal );
+
+ /* Set up reverse code. Needs no args. */
+ rcodeCode( exec, IN_LIST_APPEND_BKT );
+ rcodeUnitTerm( exec );
+ break;
+ }
+ case IN_LIST_APPEND_WC: {
+ debug( prg, REALM_BYTECODE, "IN_LIST_APPEND_WC\n" );
+
+ Tree *obj = vm_pop();
+ Tree *val = vm_pop();
+
+ treeDownref( prg, sp, obj );
+
+ listAppend2( prg, (List*)obj, val );
+ treeUpref( prg->trueVal );
+ vm_push( prg->trueVal );
+ break;
+ }
+ case IN_LIST_APPEND_BKT: {
+ debug( prg, REALM_BYTECODE, "IN_LIST_APPEND_BKT\n" );
+
+ Tree *obj = vm_pop();
+ treeDownref( prg, sp, obj );
+
+ Tree *tree = listRemoveEnd( prg, (List*)obj );
+ treeDownref( prg, sp, tree );
+ break;
+ }
+ case IN_LIST_REMOVE_END_WC: {
+ debug( prg, REALM_BYTECODE, "IN_LIST_REMOVE_END_WC\n" );
+
+ Tree *obj = vm_pop();
+ treeDownref( prg, sp, obj );
+
+ Tree *end = listRemoveEnd( prg, (List*)obj );
+ vm_push( end );
+ break;
+ }
+ case IN_LIST_REMOVE_END_WV: {
+ debug( prg, REALM_BYTECODE, "IN_LIST_REMOVE_END_WV\n" );
+
+ Tree *obj = vm_pop();
+ treeDownref( prg, sp, obj );
+
+ Tree *end = listRemoveEnd( prg, (List*)obj );
+ vm_push( end );
+
+ /* Set up reverse. The result comes off the list downrefed.
+ * Need it up referenced for the reverse code too. */
+ treeUpref( end );
+ rcodeCode( exec, IN_LIST_REMOVE_END_BKT );
+ rcodeWord( exec, (Word)end );
+ rcodeUnitTerm( exec );
+ break;
+ }
+ case IN_LIST_REMOVE_END_BKT: {
+ debug( prg, REALM_BYTECODE, "IN_LIST_REMOVE_END_BKT\n" );
+
+ Tree *val;
+ read_tree( val );
+
+ Tree *obj = vm_pop();
+ treeDownref( prg, sp, obj );
+
+ listAppend2( prg, (List*)obj, val );
+ break;
+ }
+ case IN_GET_LIST_MEM_R: {
+ short field;
+ read_half( field );
+
+ debug( prg, REALM_BYTECODE, "IN_GET_LIST_MEM_R\n" );
+
+ Tree *obj = vm_pop();
+ treeDownref( prg, sp, obj );
+
+ Tree *val = getListMem( (List*)obj, field );
+ treeUpref( val );
+ vm_push( val );
+ break;
+ }
+ case IN_GET_LIST_MEM_WC: {
+ short field;
+ read_half( field );
+
+ debug( prg, REALM_BYTECODE, "IN_GET_LIST_MEM_WC\n" );
+
+ Tree *obj = vm_pop();
+ treeDownref( prg, sp, obj );
+
+ Tree *val = getListMemSplit( prg, (List*)obj, field );
+ treeUpref( val );
+ vm_push( val );
+ break;
+ }
+ case IN_GET_LIST_MEM_WV: {
+ short field;
+ read_half( field );
+
+ debug( prg, REALM_BYTECODE, "IN_GET_LIST_MEM_WV\n" );
+
+ Tree *obj = vm_pop();
+ treeDownref( prg, sp, obj );
+
+ Tree *val = getListMemSplit( prg, (List*)obj, field );
+ treeUpref( val );
+ vm_push( val );
+
+ /* Set up the reverse instruction. */
+ rcodeCode( exec, IN_GET_LIST_MEM_BKT );
+ rcodeHalf( exec, field );
+ break;
+ }
+ case IN_GET_LIST_MEM_BKT: {
+ short field;
+ read_half( field );
+
+ debug( prg, REALM_BYTECODE, "IN_GET_LIST_MEM_BKT\n" );
+
+ Tree *obj = vm_pop();
+ treeDownref( prg, sp, obj );
+
+ Tree *res = getListMemSplit( prg, (List*)obj, field );
+ treeUpref( res );
+ vm_push( res );
+ break;
+ }
+ case IN_SET_LIST_MEM_WC: {
+ Half field;
+ read_half( field );
+
+ debug( prg, REALM_BYTECODE, "IN_SET_LIST_MEM_WC\n" );
+
+ Tree *obj = vm_pop();
+ treeDownref( prg, sp, obj );
+
+ Tree *val = vm_pop();
+ Tree *existing = setListMem( (List*)obj, field, val );
+ treeDownref( prg, sp, existing );
+ break;
+ }
+ case IN_SET_LIST_MEM_WV: {
+ Half field;
+ read_half( field );
+
+ debug( prg, REALM_BYTECODE, "IN_SET_LIST_MEM_WV\n" );
+
+ Tree *obj = vm_pop();
+ treeDownref( prg, sp, obj );
+
+ Tree *val = vm_pop();
+ Tree *existing = setListMem( (List*)obj, field, val );
+
+ /* Set up the reverse instruction. */
+ rcodeCode( exec, IN_SET_LIST_MEM_BKT );
+ rcodeHalf( exec, field );
+ rcodeWord( exec, (Word)existing );
+ rcodeUnitTerm( exec );
+ break;
+ }
+ case IN_SET_LIST_MEM_BKT: {
+ Half field;
+ Tree *val;
+ read_half( field );
+ read_tree( val );
+
+ debug( prg, REALM_BYTECODE, "IN_SET_LIST_MEM_BKT\n" );
+
+ Tree *obj = vm_pop();
+ treeDownref( prg, sp, obj );
+
+ Tree *undid = setListMem( (List*)obj, field, val );
+ treeDownref( prg, sp, undid );
+ break;
+ }
+ case IN_GET_PARSER_MEM_R: {
+ short field;
+ read_half( field );
+
+ debug( prg, REALM_BYTECODE, "IN_GET_PARSER_MEM_R %hd\n", field );
+
+ Tree *obj = vm_pop();
+ Tree *val = getParserMem( (Parser*)obj, field );
+ treeUpref( val );
+
+ /* In at least one case we extract the result on a parser with ref
+ * one. Do it after. */
+ treeDownref( prg, sp, obj );
+ vm_push( val );
+ break;
+ }
+ case IN_MAP_INSERT_WV: {
+ debug( prg, REALM_BYTECODE, "IN_MAP_INSERT_WV\n" );
+
+ Tree *obj = vm_pop();
+ Tree *val = vm_pop();
+ Tree *key = vm_pop();
+
+ treeDownref( prg, sp, obj );
+
+ int inserted = mapInsert( prg, (Map*)obj, key, val );
+ Tree *result = inserted ? prg->trueVal : prg->falseVal;
+ treeUpref( result );
+ vm_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 );
+ rcodeCode( exec, IN_MAP_INSERT_BKT );
+ rcodeCode( exec, inserted );
+ rcodeWord( exec, (Word)key );
+ rcodeUnitTerm( exec );
+
+ if ( ! inserted ) {
+ treeDownref( prg, sp, key );
+ treeDownref( prg, sp, val );
+ }
+ break;
+ }
+ case IN_MAP_INSERT_WC: {
+ debug( prg, REALM_BYTECODE, "IN_MAP_INSERT_WC\n" );
+
+ Tree *obj = vm_pop();
+ Tree *val = vm_pop();
+ Tree *key = vm_pop();
+
+ treeDownref( prg, sp, obj );
+
+ int inserted = mapInsert( prg, (Map*)obj, key, val );
+ Tree *result = inserted ? prg->trueVal : prg->falseVal;
+ treeUpref( result );
+ vm_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 );
+
+ debug( prg, REALM_BYTECODE, "IN_MAP_INSERT_BKT\n" );
+
+ Tree *obj = vm_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: {
+ debug( prg, REALM_BYTECODE, "IN_MAP_STORE_WC\n" );
+
+ Tree *obj = vm_pop();
+ Tree *element = vm_pop();
+ Tree *key = vm_pop();
+
+ Tree *existing = mapStore( prg, (Map*)obj, key, element );
+ Tree *result = existing == 0 ? prg->trueVal : prg->falseVal;
+ treeUpref( result );
+ vm_push( result );
+
+ treeDownref( prg, sp, obj );
+ if ( existing != 0 ) {
+ treeDownref( prg, sp, key );
+ treeDownref( prg, sp, existing );
+ }
+ break;
+ }
+ case IN_MAP_STORE_WV: {
+ debug( prg, REALM_BYTECODE, "IN_MAP_STORE_WV\n" );
+
+ Tree *obj = vm_pop();
+ Tree *element = vm_pop();
+ Tree *key = vm_pop();
+
+ Tree *existing = mapStore( prg, (Map*)obj, key, element );
+ Tree *result = existing == 0 ? prg->trueVal : prg->falseVal;
+ treeUpref( result );
+ vm_push( result );
+
+ /* Set up the reverse instruction. */
+ treeUpref( key );
+ treeUpref( existing );
+ rcodeCode( exec, IN_MAP_STORE_BKT );
+ rcodeWord( exec, (Word)key );
+ rcodeWord( exec, (Word)existing );
+ rcodeUnitTerm( exec );
+
+ 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 );
+
+ debug( prg, REALM_BYTECODE, "IN_MAP_STORE_BKT\n" );
+
+ Tree *obj = vm_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: {
+ debug( prg, REALM_BYTECODE, "IN_MAP_REMOVE_WC\n" );
+
+ Tree *obj = vm_pop();
+ Tree *key = vm_pop();
+ TreePair pair = mapRemove( prg, (Map*)obj, key );
+
+ vm_push( pair.val );
+
+ treeDownref( prg, sp, obj );
+ treeDownref( prg, sp, key );
+ treeDownref( prg, sp, pair.key );
+ break;
+ }
+ case IN_MAP_REMOVE_WV: {
+ debug( prg, REALM_BYTECODE, "IN_MAP_REMOVE_WV\n" );
+
+ Tree *obj = vm_pop();
+ Tree *key = vm_pop();
+ TreePair pair = mapRemove( prg, (Map*)obj, key );
+
+ treeUpref( pair.val );
+ vm_push( pair.val );
+
+ /* Reverse instruction. */
+ rcodeCode( exec, IN_MAP_REMOVE_BKT );
+ rcodeWord( exec, (Word)pair.key );
+ rcodeWord( exec, (Word)pair.val );
+ rcodeUnitTerm( exec );
+
+ treeDownref( prg, sp, obj );
+ treeDownref( prg, sp, key );
+ break;
+ }
+ case IN_MAP_REMOVE_BKT: {
+ Tree *key, *val;
+ read_tree( key );
+ read_tree( val );
+
+ debug( prg, REALM_BYTECODE, "IN_MAP_REMOVE_BKT\n" );
+
+ /* Either both or neither. */
+ assert( ( key == 0 ) ^ ( val != 0 ) );
+
+ Tree *obj = vm_pop();
+ if ( key != 0 )
+ mapUnremove( prg, (Map*)obj, key, val );
+
+ treeDownref( prg, sp, obj );
+ break;
+ }
+ case IN_MAP_LENGTH: {
+ debug( prg, REALM_BYTECODE, "IN_MAP_LENGTH\n" );
+
+ Tree *obj = vm_pop();
+ long len = mapLength( (Map*)obj );
+ Tree *res = constructInteger( prg, len );
+ treeUpref( res );
+ vm_push( res );
+
+ treeDownref( prg, sp, obj );
+ break;
+ }
+ case IN_MAP_FIND: {
+ debug( prg, REALM_BYTECODE, "IN_MAP_FIND\n" );
+
+ Tree *obj = vm_pop();
+ Tree *key = vm_pop();
+ Tree *result = mapFind( prg, (Map*)obj, key );
+ treeUpref( result );
+ vm_push( result );
+
+ treeDownref( prg, sp, obj );
+ treeDownref( prg, sp, key );
+ break;
+ }
+ case IN_CONTIGUOUS: {
+ Half size;
+ read_half( size );
+ debug( prg, REALM_BYTECODE, "IN_CONTIGUOUS %hd\n", size );
+ vm_contiguous( size );
+ vm_push( 0 );
+ break;
+ }
+ case IN_INIT_LOCALS: {
+ Half size;
+ read_half( size );
+
+ debug( prg, REALM_BYTECODE, "IN_INIT_LOCALS %hd\n", size );
+
+ exec->framePtr = vm_ptop();
+ vm_pushn( size );
+ memset( vm_ptop(), 0, sizeof(Word) * size );
+ break;
+ }
+ case IN_CALL_WV: {
+ Half funcId;
+ read_half( funcId );
+
+ FunctionInfo *fi = &prg->rtd->functionInfo[funcId];
+
+ debug( prg, REALM_BYTECODE, "IN_CALL_WV %s\n", fi->name );
+
+ vm_push( 0 ); /* Return value. */
+ vm_push( (SW)instr );
+ vm_push( (SW)exec->framePtr );
+ vm_push( (SW)exec->frameId );
+
+ instr = prg->rtd->frameInfo[fi->frameId].codeWV;
+ exec->framePtr = vm_ptop();
+ exec->frameId = fi->frameId;
+ break;
+ }
+ case IN_CALL_WC: {
+ Half funcId;
+ read_half( funcId );
+
+ FunctionInfo *fi = &prg->rtd->functionInfo[funcId];
+
+ debug( prg, REALM_BYTECODE, "IN_CALL_WC %s\n", fi->name );
+
+ vm_push( 0 ); /* Return value. */
+ vm_push( (SW)instr );
+ vm_push( (SW)exec->framePtr );
+ vm_push( (SW)exec->frameId );
+
+ instr = prg->rtd->frameInfo[fi->frameId].codeWC;
+ exec->framePtr = vm_ptop();
+ exec->frameId = fi->frameId;
+ break;
+ }
+ case IN_YIELD: {
+ debug( prg, REALM_BYTECODE, "IN_YIELD\n" );
+
+ Kid *kid = (Kid*)vm_pop();
+ Ref *next = (Ref*)vm_pop();
+ UserIter *uiter = (UserIter*) vm_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->yieldSize = vm_ssize() - uiter->rootSize;
+ uiter->resume = instr;
+ uiter->frame = exec->framePtr;
+
+ /* Restore the instruction and frame pointer. */
+ instr = (Code*) vm_local_iframe(IFR_RIN);
+ exec->framePtr = (Tree**) vm_local_iframe(IFR_RFR);
+ exec->iframePtr = (Tree**) vm_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 );
+ vm_push( result );
+ }
+ break;
+ }
+ case IN_UITER_CREATE_WV: {
+ short field;
+ Half funcId, searchId;
+ read_half( field );
+ read_half( funcId );
+ read_half( searchId );
+
+ debug( prg, REALM_BYTECODE, "IN_UITER_CREATE_WV\n" );
+
+ FunctionInfo *fi = prg->rtd->functionInfo + funcId;
+ UserIter *uiter = uiterCreate( prg, &sp, fi, searchId );
+ vm_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. */
+ vm_push( 0 ); /* Return instruction pointer, */
+ vm_push( (SW)exec->iframePtr ); /* Return iframe. */
+ vm_push( (SW)exec->framePtr ); /* 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 );
+
+ debug( prg, REALM_BYTECODE, "IN_UITER_CREATE_WC\n" );
+
+ FunctionInfo *fi = prg->rtd->functionInfo + funcId;
+ UserIter *uiter = uiterCreate( prg, &sp, fi, searchId );
+ vm_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. */
+ vm_push( 0 ); /* Return instruction pointer, */
+ vm_push( (SW)exec->iframePtr ); /* Return iframe. */
+ vm_push( (SW)exec->framePtr ); /* Return frame. */
+
+ uiterInit( prg, sp, uiter, fi, false );
+ break;
+ }
+ case IN_UITER_DESTROY: {
+ short field;
+ read_half( field );
+
+ debug( prg, REALM_BYTECODE, "IN_UITER_DESTROY\n" );
+
+ UserIter *uiter = (UserIter*) vm_local(field);
+ userIterDestroy( prg, &sp, uiter );
+ break;
+ }
+ case IN_RET: {
+ debug( prg, REALM_BYTECODE, "IN_RET\n" );
+
+ FrameInfo *fi = &prg->rtd->frameInfo[exec->frameId];
+ downrefLocalTrees( prg, sp, exec->framePtr, fi->locals, fi->localsLen );
+ vm_popn( fi->frameSize );
+
+ exec->frameId = (long) vm_pop();
+ exec->framePtr = (Tree**) vm_pop();
+ instr = (Code*) vm_pop();
+ Tree *retVal = vm_pop();
+ vm_popn( fi->argSize );
+ vm_push( retVal );
+
+ /* This if for direct calls of functions. */
+ if ( instr == 0 ){
+ //assert( sp == root );
+ return sp;
+ }
+
+ break;
+ }
+ case IN_TO_UPPER: {
+ debug( prg, REALM_BYTECODE, "IN_TO_UPPER\n" );
+
+ Tree *in = vm_pop();
+ Head *head = stringToUpper( in->tokdata );
+ Tree *upper = constructString( prg, head );
+ treeUpref( upper );
+ vm_push( upper );
+ treeDownref( prg, sp, in );
+ break;
+ }
+ case IN_TO_LOWER: {
+ debug( prg, REALM_BYTECODE, "IN_TO_LOWER\n" );
+
+ Tree *in = vm_pop();
+ Head *head = stringToLower( in->tokdata );
+ Tree *lower = constructString( prg, head );
+ treeUpref( lower );
+ vm_push( lower );
+ treeDownref( prg, sp, in );
+ break;
+ }
+ case IN_OPEN_FILE: {
+ debug( prg, REALM_BYTECODE, "IN_OPEN_FILE\n" );
+
+ Tree *mode = vm_pop();
+ Tree *name = vm_pop();
+ Tree *res = (Tree*)openFile( prg, name, mode );
+ treeUpref( res );
+ vm_push( res );
+ treeDownref( prg, sp, name );
+ treeDownref( prg, sp, mode );
+ break;
+ }
+ case IN_GET_STDIN: {
+ debug( prg, REALM_BYTECODE, "IN_GET_STDIN\n" );
+
+ /* Pop the root object. */
+ Tree *obj = vm_pop();
+ treeDownref( prg, sp, obj );
+ if ( prg->stdinVal == 0 ) {
+ prg->stdinVal = openStreamFd( prg, "<stdin>", 0 );
+ treeUpref( (Tree*)prg->stdinVal );
+ }
+
+ treeUpref( (Tree*)prg->stdinVal );
+ vm_push( (Tree*)prg->stdinVal );
+ break;
+ }
+ case IN_GET_STDOUT: {
+ debug( prg, REALM_BYTECODE, "IN_GET_STDOUT\n" );
+
+ /* Pop the root object. */
+ Tree *obj = vm_pop();
+ treeDownref( prg, sp, obj );
+ if ( prg->stdoutVal == 0 ) {
+ prg->stdoutVal = openStreamFd( prg, "<stdout>", 1 );
+ treeUpref( (Tree*)prg->stdoutVal );
+ }
+
+ treeUpref( (Tree*)prg->stdoutVal );
+ vm_push( (Tree*)prg->stdoutVal );
+ break;
+ }
+ case IN_GET_STDERR: {
+ debug( prg, REALM_BYTECODE, "IN_GET_STDERR\n" );
+
+ /* Pop the root object. */
+ Tree *obj = vm_pop();
+ treeDownref( prg, sp, obj );
+ if ( prg->stderrVal == 0 ) {
+ prg->stderrVal = openStreamFd( prg, "<stderr>", 2 );
+ treeUpref( (Tree*)prg->stderrVal );
+ }
+
+ treeUpref( (Tree*)prg->stderrVal );
+ vm_push( (Tree*)prg->stderrVal );
+ break;
+ }
+ case IN_LOAD_ARGV: {
+ Half field;
+ read_half( field );
+ debug( prg, REALM_BYTECODE, "IN_LOAD_ARGV %lu\n", field );
+
+ /* Tree comes back upreffed. */
+ Tree *tree = constructArgv( prg, prg->argc, prg->argv );
+ setField( prg, prg->global, field, tree );
+ break;
+ }
+
+ case IN_SYSTEM: {
+ debug( prg, REALM_BYTECODE, "IN_SYSTEM\n" );
+
+ Tree *global = vm_pop();
+ Str *cmd = (Str*)vm_pop();
+
+ char *cmd0 = malloc( cmd->value->length + 1 );
+ memcpy( cmd0, cmd->value->data, cmd->value->length );
+ cmd0[cmd->value->length] = 0;
+
+ int r = system( cmd0 );
+
+ treeDownref( prg, sp, global );
+ treeDownref( prg, sp, (Tree*)cmd );
+
+ Tree *result = constructInteger( prg, r );
+ treeUpref( result );
+ vm_push( result );
+ break;
+ }
+
+ case IN_EXIT: {
+ debug( prg, REALM_BYTECODE, "IN_EXIT\n" );
+
+ Tree *global = vm_pop();
+ Int *status = (Int*)vm_pop();
+ prg->exitStatus = status->value;
+ prg->induceExit = 1;
+ treeDownref( prg, sp, global );
+ treeDownref( prg, sp, (Tree*)status );
+
+ while ( true ) {
+ FrameInfo *fi = &prg->rtd->frameInfo[exec->frameId];
+ int frameId = exec->frameId;
+
+ downrefLocals( prg, &sp, exec->framePtr, fi->locals, fi->localsLen );
+
+ vm_popn( fi->frameSize );
+
+ /* We stop on the root, leaving the psuedo-call setup on the
+ * stack. Note we exclude the local data. */
+ if ( frameId == prg->rtd->rootFrameId )
+ break;
+
+ /* Call layout. */
+ exec->frameId = (long) vm_pop();
+ exec->framePtr = (Tree**) vm_pop();
+ instr = (Code*) vm_pop();
+ Tree *retVal = vm_pop();
+ vm_popn( fi->argSize );
+ vm_pop();
+
+ treeDownref( prg, sp, retVal );
+ }
+
+ goto out;
+ }
+
+ case IN_STOP: {
+ debug( prg, REALM_BYTECODE, "IN_STOP\n" );
+
+ FrameInfo *fi = &prg->rtd->frameInfo[exec->frameId];
+ downrefLocalTrees( prg, sp, exec->framePtr, fi->locals, fi->localsLen );
+ vm_popn( fi->frameSize );
+
+ 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: 0x%2x -- something is wrong\n", *(instr-1) );
+ assert(false);
+ break;
+ }
+ }
+ goto again;
+
+out:
+ if ( ! prg->induceExit )
+ assert( sp == root );
+ return sp;
+}
+