summaryrefslogtreecommitdiff
path: root/src/reduce.cc
diff options
context:
space:
mode:
authorAdrian Thurston <thurston@colm.net>2020-03-14 15:29:52 +0200
committerAdrian Thurston <thurston@colm.net>2020-03-14 15:29:52 +0200
commitf653735830d537715f2885bd832cf04851d35401 (patch)
tree95e6551e39407543366d4f49aedf7b78c6e8bbe1 /src/reduce.cc
parentbcc54d5df10cf425e7134b06f70d7ffe1abee4e4 (diff)
downloadcolm-f653735830d537715f2885bd832cf04851d35401.tar.gz
moved source files into commit repository
Diffstat (limited to 'src/reduce.cc')
-rw-r--r--src/reduce.cc954
1 files changed, 954 insertions, 0 deletions
diff --git a/src/reduce.cc b/src/reduce.cc
new file mode 100644
index 00000000..89a95015
--- /dev/null
+++ b/src/reduce.cc
@@ -0,0 +1,954 @@
+/*
+ * Copyright 2015-2018 Adrian Thurston <thurston@colm.net>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <string.h>
+#include <stdbool.h>
+
+#include <iostream>
+
+#include "fsmcodegen.h"
+
+void Compiler::writeCommitStub()
+{
+ *outStream <<
+ "void " << objectName << "_commit_reduce_forward( program_t *prg, tree_t **root,\n"
+ " struct pda_run *pda_run, parse_tree_t *pt )\n"
+ "{\n"
+ " commit_clear_parse_tree( prg, root, pda_run, pt->child );\n"
+ "}\n"
+ "\n"
+ "long " << objectName << "_commit_union_sz( int reducer ) { return 0; }\n"
+ "void " << objectName << "_init_need() {}\n"
+ "int " << objectName << "_reducer_need_tok( program_t *prg, "
+ "struct pda_run *pda_run, int id ) { return COLM_RN_BOTH; }\n"
+ "int " << objectName << "_reducer_need_ign( program_t *prg, "
+ "struct pda_run *pda_run ) { return COLM_RN_BOTH; }\n"
+ "\n"
+ "void " << objectName << "_read_reduce( program_t *prg, int reducer, input_t *stream ) {}\n"
+ ;
+}
+
+void Compiler::findRhsRefs( bool &lhsUsed, Vector<ProdEl*> &rhsUsed, Vector<ProdEl*> &treeUsed,
+ Vector<ProdEl*> &locUsed, Reduction *reduction, Production *production,
+ const ReduceTextItemList &list )
+{
+ ObjectDef *objectDef = production->prodName->objectDef;
+
+ rhsUsed.setAsNew( production->prodElList->length() );
+ treeUsed.setAsNew( production->prodElList->length() );
+ locUsed.setAsNew( production->prodElList->length() );
+
+ for ( ReduceTextItemList::Iter i = list; i.lte(); i++ ) {
+ if ( i->type == ReduceTextItem::LhsRef ) {
+ lhsUsed = true;
+ }
+
+ if ( i->type == ReduceTextItem::RhsRef ||
+ i->type == ReduceTextItem::RhsLoc ||
+ i->type == ReduceTextItem::TreeRef )
+ {
+ if ( i->n > 0 ) {
+ /* Numbered. */
+ ProdEl *prodEl = production->prodElList->head;
+ int adv = i->n - 1;
+ while ( adv > 0 ) {
+ prodEl = prodEl->next;
+ adv -= 1;
+ }
+
+ if ( i->type == ReduceTextItem::RhsLoc )
+ locUsed[i->n-1] = prodEl;
+ else if ( i->type == ReduceTextItem::TreeRef )
+ treeUsed[i->n-1] = prodEl;
+ else
+ rhsUsed[i->n-1] = prodEl;
+ }
+ else {
+ /* Named. */
+ String name( i->txt.data + 1, i->txt.length() - 1 );
+ ObjectField *field = objectDef->rootScope->findField( name );
+ if ( field != 0 ) {
+ for ( Vector<RhsVal>::Iter r = field->rhsVal; r.lte(); r++ ) {
+ if ( r->prodEl->production == production ) {
+ if ( i->type == ReduceTextItem::RhsLoc )
+ locUsed[r->prodEl->pos] = r->prodEl;
+ else
+ rhsUsed[r->prodEl->pos] = r->prodEl;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void Compiler::computeNeeded( Reduction *reduction, Production *production,
+ const ReduceTextItemList &list )
+{
+ bool lhsUsed = false;
+ Vector<ProdEl*> rhsUsed;
+ Vector<ProdEl*> treeUsed;
+ Vector<ProdEl*> locUsed;
+
+ findRhsRefs( lhsUsed, rhsUsed, treeUsed, locUsed, reduction, production, list );
+
+ /* Same length, can concurrently walk with one test. */
+ Vector<ProdEl*>::Iter rhs = rhsUsed;
+ Vector<ProdEl*>::Iter loc = locUsed;
+
+ for ( ; rhs.lte(); rhs++, loc++ ) {
+ ProdEl *prodEl = *rhs;
+ if ( prodEl != 0 ) {
+ if ( prodEl->production == production && prodEl->langEl->type == LangEl::Term )
+ reduction->needData[prodEl->langEl->id] = true;
+ }
+
+ ProdEl *locEl = *loc;
+ if ( locEl != 0 && locEl->production == production )
+ reduction->needLoc[locEl->langEl->id] = true;
+ }
+}
+
+void Compiler::loadRefs( Reduction *reduction, Production *production,
+ const ReduceTextItemList &list, bool read )
+{
+ bool lhsUsed = false;
+ Vector<ProdEl*> rhsUsed;
+ Vector<ProdEl*> treeUsed;
+ Vector<ProdEl*> locUsed;
+
+ findRhsRefs( lhsUsed, rhsUsed, treeUsed, locUsed, reduction, production, list );
+
+ if ( lhsUsed ) {
+ *outStream << " lel_" << production->prodName->fullName << " *_lhs = ";
+
+ if ( read ) {
+ *outStream <<
+ "&node->u." << production->prodName->fullName << ";\n";
+ }
+ else {
+ *outStream <<
+ "&((commit_reduce_union*)(lel+1))->" << production->prodName->fullName << ";\n";
+ }
+ }
+
+ /*
+ * In the first pass we load using a parse tree cursor. This is for
+ * nonterms.
+ */
+ bool useCursor = false;
+ for ( Vector<ProdEl*>::Iter rhs = rhsUsed; rhs.lte(); rhs++ ) {
+ if ( *rhs != 0 && (*rhs)->production == production &&
+ (*rhs)->langEl->type != LangEl::Term )
+ {
+ useCursor = true;
+ break;
+ }
+ }
+
+ if ( useCursor ) {
+ int cursorPos = 0;
+
+ if ( read ) {
+ *outStream <<
+ " struct read_reduce_node *_pt_cursor = node->child;\n";
+ }
+ else {
+ *outStream <<
+ " struct colm_parse_tree *_pt_cursor = lel->child;\n";
+ }
+
+ /* Same length, can concurrently walk with one test. */
+ Vector<ProdEl*>::Iter rhs = rhsUsed;
+ Vector<ProdEl*>::Iter loc = locUsed;
+
+ for ( ; rhs.lte(); rhs++, loc++ ) {
+ ProdEl *prodEl = *rhs;
+ if ( prodEl != 0 ) {
+ while ( cursorPos < rhs.pos() ) {
+ *outStream <<
+ " _pt_cursor = _pt_cursor->next;\n";
+ cursorPos += 1;
+ }
+
+ if ( prodEl->production == production ) {
+ if ( prodEl->langEl->type != LangEl::Term ) {
+ *outStream <<
+ "lel_" << prodEl->langEl->fullName << " *" "_rhs" << rhs.pos() << " = ";
+
+ if ( read ) {
+ *outStream << "&_pt_cursor->u." << prodEl->langEl->fullName << ";\n";
+ }
+ else {
+ *outStream << "&((commit_reduce_union*)(_pt_cursor+1))->" << prodEl->langEl->fullName << ";\n";
+ }
+ }
+ }
+
+ }
+ }
+ }
+
+ /* In the second pass we load using a tree cursor. This is for token/tree
+ * data and locations. */
+
+ useCursor = false;
+ for ( Vector<ProdEl*>::Iter rhs = rhsUsed; rhs.lte(); rhs++ ) {
+ if ( *rhs != 0 && (*rhs)->production == production &&
+ (*rhs)->langEl->type == LangEl::Term )
+ {
+ useCursor = true;
+ break;
+ }
+ }
+ for ( Vector<ProdEl*>::Iter rhs = treeUsed; rhs.lte(); rhs++ ) {
+ if ( *rhs != 0 ) {
+ useCursor = true;
+ break;
+ }
+ }
+ for ( Vector<ProdEl*>::Iter loc = locUsed; loc.lte(); loc++ ) {
+ if ( *loc != 0 ) {
+ useCursor = true;
+ break;
+ }
+ }
+
+ if ( useCursor ) {
+ int cursorPos = 0;
+
+ if ( read ) {
+ *outStream <<
+ " read_reduce_node *_tree_cursor = node->child;\n";
+ }
+ else {
+ *outStream <<
+ " kid_t *_tree_cursor = kid->tree->child;\n";
+ }
+
+ /* Same length, can concurrently walk with one test. */
+ Vector<ProdEl*>::Iter rhs = rhsUsed;
+ Vector<ProdEl*>::Iter tree = treeUsed;
+ Vector<ProdEl*>::Iter loc = locUsed;
+
+ for ( ; rhs.lte(); rhs++, loc++ ) {
+
+ ProdEl *prodEl = *rhs;
+ if ( prodEl != 0 ) {
+ if ( prodEl->production == production ) {
+ if ( prodEl->langEl->type == LangEl::Term ) {
+
+ while ( cursorPos < rhs.pos() ) {
+ *outStream <<
+ " _tree_cursor = _tree_cursor->next;\n";
+ cursorPos += 1;
+ }
+
+ *outStream << " colm_data *_rhs" << rhs.pos() << " = ";
+
+ if ( read ) {
+ *outStream <<
+ "&_tree_cursor->data;\n";
+ }
+ else {
+ *outStream <<
+ "_tree_cursor->tree->tokdata;\n";
+ }
+ }
+ }
+ }
+
+ ProdEl *treeEl = *tree;
+ if ( treeEl != 0 ) {
+ if ( treeEl->production == production ) {
+ while ( cursorPos < rhs.pos() ) {
+ *outStream <<
+ " _tree_cursor = _tree_cursor->next;\n";
+ cursorPos += 1;
+ }
+
+ *outStream << " colm_tree *_tree" << rhs.pos() << " = ";
+ *outStream << "_tree_cursor->tree;\n";
+ }
+ }
+
+ ProdEl *locEl = *loc;
+ if ( locEl != 0 ) {
+ if ( locEl->production == production ) {
+
+ while ( cursorPos < rhs.pos() ) {
+ *outStream <<
+ " _tree_cursor = _tree_cursor->next;\n";
+ cursorPos += 1;
+ }
+
+ *outStream <<
+ " colm_location *_loc" << loc.pos() << " = ";
+
+ if ( read ) {
+ *outStream << "&_tree_cursor->loc;\n";
+ }
+ else {
+ *outStream <<
+ "colm_find_location( prg, _tree_cursor->tree );\n";
+ }
+ }
+ }
+ }
+ }
+}
+
+void Compiler::writeRhsRef( Production *production, ReduceTextItem *i )
+{
+ if ( i->n > 0 ) {
+ *outStream << "_rhs" << ( i->n - 1 );
+ }
+ else {
+ ObjectDef *objectDef = production->prodName->objectDef;
+ String name( i->txt.data + 1, i->txt.length() - 1 );
+
+ /* Find the field in the rhsVal using capture field. */
+ ObjectField *field = objectDef->rootScope->findField( name );
+ if ( field != 0 ) {
+ for ( Vector<RhsVal>::Iter r = field->rhsVal;
+ r.lte(); r++ )
+ {
+ if ( r->prodEl->production == production )
+ *outStream << "_rhs" << r->prodEl->pos;
+ }
+ }
+ }
+}
+
+void Compiler::writeTreeRef( Production *production, ReduceTextItem *i )
+{
+ if ( i->n > 0 ) {
+ *outStream << "_tree" << ( i->n - 1 );
+ }
+ else {
+ ObjectDef *objectDef = production->prodName->objectDef;
+ String name( i->txt.data + 1, i->txt.length() - 1 );
+
+ /* Find the field in the rhsVal using capture field. */
+ ObjectField *field = objectDef->rootScope->findField( name );
+ if ( field != 0 ) {
+ for ( Vector<RhsVal>::Iter r = field->rhsVal;
+ r.lte(); r++ )
+ {
+ if ( r->prodEl->production == production )
+ *outStream << "_tree" << r->prodEl->pos;
+ }
+ }
+ }
+}
+
+void Compiler::writeRhsLoc( Production *production, ReduceTextItem *i )
+{
+ if ( i->n > 0 ) {
+ *outStream << "_loc" << ( i->n - 1 );
+ }
+ else {
+ ObjectDef *objectDef = production->prodName->objectDef;
+ String name( i->txt.data + 1, i->txt.length() - 1 );
+
+ /* Find the field in the rhsVal using capture field. */
+ ObjectField *field = objectDef->rootScope->findField( name );
+ if ( field != 0 ) {
+ for ( Vector<RhsVal>::Iter r = field->rhsVal;
+ r.lte(); r++ )
+ {
+ if ( r->prodEl->production == production )
+ *outStream << "_loc" << r->prodEl->pos;
+ }
+ }
+ }
+}
+
+void Compiler::writeLhsRef( Production *production, ReduceTextItem *i )
+{
+ *outStream << "_lhs";
+}
+
+void Compiler::writeHostItemList( Production *production,
+ const ReduceTextItemList &list )
+{
+ for ( ReduceTextItemList::Iter i = list; i.lte(); i++ ) {
+ switch ( i->type ) {
+ case ReduceTextItem::LhsRef:
+ writeLhsRef( production, i );
+ break;
+ case ReduceTextItem::RhsRef:
+ writeRhsRef( production, i );
+ break;
+ case ReduceTextItem::TreeRef:
+ writeTreeRef( production, i );
+ break;
+ case ReduceTextItem::RhsLoc:
+ writeRhsLoc( production, i );
+ break;
+ case ReduceTextItem::Txt:
+ *outStream << i->txt;
+ break;
+ }
+ }
+}
+
+/* For sorting according to prod name id, then by prod num. */
+struct CmpReduceAction
+{
+ static int compare( const ReduceAction *ra1 , const ReduceAction *ra2 )
+ {
+ if ( ra1->production->prodName->id < ra2->production->prodName->id )
+ return -1;
+ else if ( ra1->production->prodName->id > ra2->production->prodName->id )
+ return 1;
+ else {
+ if ( ra1->production->prodNum < ra2->production->prodNum )
+ return -1;
+ else if ( ra1->production->prodNum > ra2->production->prodNum )
+ return 1;
+ }
+ return 0;
+ }
+};
+
+void Compiler::initReductionNeeds( Reduction *reduction )
+{
+ reduction->needData = new bool[nextLelId];
+ reduction->needLoc = new bool[nextLelId];
+ memset( reduction->needData, 0, sizeof(bool)*nextLelId );
+ memset( reduction->needLoc, 0, sizeof(bool)*nextLelId );
+}
+
+void Compiler::writeNeeds()
+{
+
+ *outStream <<
+ "struct reduction_info\n"
+ "{\n"
+ " unsigned char need_data[" << nextLelId << "];\n"
+ " unsigned char need_loc[" << nextLelId << "];\n"
+ "};\n"
+ "\n";
+
+ *outStream <<
+ "static struct reduction_info ri[" << rootNamespace->reductions.length() + 1 << "];\n"
+ "\n";
+
+ *outStream <<
+ "extern \"C\" void " << objectName << "_init_need()\n"
+ "{\n";
+
+ for ( ReductionVect::Iter r = rootNamespace->reductions; r.lte(); r++ ) {
+ Reduction *reduction = *r;
+ *outStream <<
+ " memset( ri[" << reduction->id << "]"
+ ".need_data, 0, sizeof(unsigned char) * " << nextLelId << " );\n"
+ " memset( ri[" << reduction->id << "]"
+ ".need_loc, 0, sizeof(unsigned char) * " << nextLelId << " );\n";
+
+ for ( int i = 0; i < nextLelId; i++ ) {
+ if ( reduction->needData[i] ) {
+ *outStream <<
+ " ri[" << reduction->id << "].need_data[" << i << "] = COLM_RN_DATA;\n";
+ }
+
+ if ( reduction->needLoc[i] ) {
+ *outStream <<
+ " ri[" << reduction->id << "].need_loc[" << i << "] = COLM_RN_LOC;\n";
+ }
+ }
+ }
+
+ *outStream <<
+ "}\n";
+
+ *outStream <<
+ "extern \"C\" int " << objectName << "_reducer_need_tok( program_t *prg, "
+ "struct pda_run *pda_run, int id )\n"
+ "{\n"
+ " if ( prg->reduce_clean && pda_run->reducer > 0 ) {\n"
+ /* Note we are forcing the reducer need for data. Enabling requires finding
+ * a solution for backtracking push. */
+ " return COLM_RN_DATA | ri[pda_run->reducer].need_data[id] | \n"
+ " ri[pda_run->reducer].need_loc[id];\n"
+ " }\n"
+ " return COLM_RN_BOTH;\n"
+ "}\n"
+ "\n"
+ "extern \"C\" int " << objectName << "_reducer_need_ign( program_t *prg, struct pda_run *pda_run )\n"
+ "{\n"
+ // Using this requires finding a solution for backtracking push back.
+ //" if ( pda_run->reducer > 0 )\n"
+ //" return COLM_RN_NEITHER;\n"
+ " return COLM_RN_BOTH;\n"
+ "}\n";
+}
+
+void Compiler::writeReduceStructs()
+{
+ for ( ReductionVect::Iter r = rootNamespace->reductions; r.lte(); r++ ) {
+ for ( ReduceNonTermList::Iter rdi = (*r)->reduceNonTerms; rdi.lte(); rdi++ ) {
+ *outStream <<
+ "struct lel_" << rdi->nonTerm->uniqueType->langEl->fullName << "\n"
+ "{\n";
+
+ *outStream <<
+ "#line " << rdi->loc.line << "\"" << rdi->loc.fileName << "\"\n";
+
+ writeHostItemList( 0, rdi->itemList );
+
+ *outStream <<
+ "};\n";
+ }
+ }
+
+ *outStream <<
+ "union commit_reduce_union\n"
+ "{\n";
+
+ for ( ReductionVect::Iter r = rootNamespace->reductions; r.lte(); r++ ) {
+ for ( ReduceNonTermList::Iter rdi = (*r)->reduceNonTerms; rdi.lte(); rdi++ ) {
+ LangEl *langEl = rdi->nonTerm->uniqueType->langEl;
+ *outStream <<
+ " lel_" << langEl->fullName << " " << langEl->fullName << ";\n";
+ }
+ }
+
+ *outStream <<
+ "};\n"
+ "\n";
+
+ *outStream <<
+ "extern \"C\" long " << objectName << "_commit_union_sz( int reducer )\n"
+ "{\n"
+ " return sizeof( commit_reduce_union );\n"
+ "}\n";
+
+ *outStream <<
+ "struct read_reduce_node\n"
+ "{\n"
+ " std::string name;\n"
+ " int id;\n"
+ " int prod_num;\n"
+ " colm_location loc;\n"
+ " colm_data data;\n"
+ " commit_reduce_union u;\n"
+ " read_reduce_node *next;\n"
+ " read_reduce_node *child;\n"
+ "};\n"
+ "\n";
+}
+
+
+void Compiler::writeUnescape()
+{
+ *outStream <<
+ "static void unescape( colm_data *tokdata )\n"
+ "{\n"
+ " unsigned char *src = (unsigned char*)tokdata->data, *dest = (unsigned char*)tokdata->data;\n"
+ " while ( *src != 0 ) {\n"
+ " if ( *src == '\\\\' ) {\n"
+ " unsigned int i;\n"
+ " char buf[3];\n"
+ "\n"
+ " src += 1;\n"
+ " buf[0] = *src++;\n"
+ " buf[1] = *src++;\n"
+ " buf[2] = 0;\n"
+ "\n"
+ " sscanf( buf, \"%x\", &i );\n"
+ " *dest++ = (unsigned char)i;\n"
+ "\n"
+ " tokdata->length -= 2;\n"
+ " }\n"
+ " else {\n"
+ " *dest++ = *src++;\n"
+ " }\n"
+ " }\n"
+ " *dest = 0;\n"
+ "}\n"
+ "\n";
+}
+
+void Compiler::writeReduceDispatchers()
+{
+ *outStream <<
+ "\n"
+ "extern \"C\" void " << objectName << "_commit_reduce_forward( program_t *prg, tree_t **root,\n"
+ " struct pda_run *pda_run, parse_tree_t *pt )\n"
+ "{\n"
+ " switch ( pda_run->reducer ) {\n";
+
+ for ( ReductionVect::Iter r = rootNamespace->reductions; r.lte(); r++ ) {
+ Reduction *reduction = *r;
+ if ( reduction->parserBased ) {
+ *outStream <<
+ " case " << reduction->id << ":\n"
+ " ((" << reduction->name << "*)prg->red_ctx)->commit_reduce_forward( "
+ "prg, root, pda_run, pt );\n"
+ " break;\n";
+ }
+ }
+
+ *outStream <<
+ " }\n"
+ "}\n"
+ "\n";
+
+ *outStream <<
+ "extern \"C\" void " << objectName << "_read_reduce( program_t *prg, int reducer, stream_t *stream )\n"
+ "{\n"
+ " switch ( reducer ) {\n";
+
+ for ( ReductionVect::Iter r = rootNamespace->reductions; r.lte(); r++ ) {
+ Reduction *reduction = *r;
+ if ( reduction->postfixBased ) {
+ *outStream <<
+ " case " << reduction->id << ":\n"
+ " ((" << reduction->name << "*)prg->red_ctx)->read_reduce_forward( prg, stream->impl->file );\n"
+ " break;\n";
+ }
+ }
+
+ *outStream <<
+ " }\n"
+ "}\n"
+ "\n";
+}
+
+void Compiler::computeNeeded()
+{
+ for ( ReductionVect::Iter r = rootNamespace->reductions; r.lte(); r++ ) {
+ Reduction *reduction = *r;
+ initReductionNeeds( reduction );
+
+ for ( ReduceActionList::Iter rdi = reduction->reduceActions; rdi.lte(); rdi++ )
+ computeNeeded( reduction, rdi->production, rdi->itemList );
+ }
+}
+
+void Compiler::writeParseReduce( Reduction *reduction )
+{
+ *outStream <<
+ "void " << reduction->name << "::commit_reduce_forward( program_t *prg, \n"
+ " tree_t **root, struct pda_run *pda_run, parse_tree_t *pt )\n"
+ "{\n"
+ " tree_t **sp = root;\n"
+ "\n"
+ " parse_tree_t *lel = pt;\n"
+ " kid_t *kid = pt->shadow;\n"
+ "\n"
+ "recurse:\n"
+ "\n"
+ " if ( lel->child != 0 ) {\n"
+ " /* There are children. Must process all children first. */\n"
+ " vm_push_ptree( lel );\n"
+ " vm_push_kid( kid );\n"
+ "\n"
+ " lel = lel->child;\n"
+ " kid = tree_child( prg, kid->tree );\n"
+ " while ( lel != 0 ) {\n"
+ " goto recurse;\n"
+ " resume:\n"
+ " lel = lel->next;\n"
+ " kid = kid->next;\n"
+ " }\n"
+ "\n"
+ " kid = vm_pop_kid();\n"
+ " lel = vm_pop_ptree();\n"
+ " }\n"
+ "\n"
+ " if ( !( lel->flags & PF_COMMITTED ) ) {\n"
+ " /* Now can execute the reduction action. */\n"
+ " {\n";
+
+
+ *outStream <<
+ " { switch ( kid->tree->id ) {\n";
+
+ /* Populate a vector with the reduce actions. */
+ Vector<ReduceAction*> actions;
+ actions.setAsNew( reduction->reduceActions.length() );
+ long pos = 0;
+ for ( ReduceActionList::Iter rdi = reduction->reduceActions; rdi.lte(); rdi++ )
+ actions[pos++] = rdi;
+
+ /* Sort it by lhs id, then prod num. */
+ MergeSort<ReduceAction*, CmpReduceAction> sortActions;
+ sortActions.sort( actions.data, actions.length() );
+
+ ReduceAction *last = 0;
+
+ for ( Vector<ReduceAction*>::Iter rdi = actions; rdi.lte(); rdi++ ) {
+ ReduceAction *action = *rdi;
+ int lelId = action->production->prodName->id;
+ int prodNum = action->production->prodNum;
+
+ /* Maybe close off the last prod. */
+ if ( last != 0 &&
+ last->production->prodName != action->production->prodName )
+ {
+ *outStream <<
+ " break;\n"
+ " }\n";
+
+ }
+
+ /* Maybe open a new prod. */
+ if ( last == 0 ||
+ last->production->prodName != action->production->prodName )
+ {
+ *outStream <<
+ " case " << lelId << ": {\n";
+ }
+
+ *outStream <<
+ " if ( kid->tree->prod_num == " << prodNum << " ) {\n";
+
+
+ loadRefs( reduction, action->production, action->itemList, false );
+
+ *outStream <<
+ "#line " << action->loc.line << " \"" << action->loc.fileName << "\"\n";
+
+ writeHostItemList( action->production, action->itemList );
+
+ *outStream <<
+ " }\n";
+
+ last = action;
+ }
+
+ if ( last != 0 ) {
+ *outStream <<
+ " break;\n"
+ " }\n";
+ }
+
+ *outStream <<
+ " } }\n"
+ " }\n"
+ " }\n"
+ "\n"
+ " commit_clear_parse_tree( prg, sp, pda_run, lel->child );\n"
+ " if ( prg->reduce_clean ) {\n"
+ " commit_clear_kid_list( prg, sp, kid->tree->child );\n"
+ " kid->tree->child = 0;\n"
+ " kid->tree->flags &= ~( AF_LEFT_IGNORE | AF_RIGHT_IGNORE );\n"
+ " }\n"
+ " lel->child = 0;\n"
+ "\n"
+ " if ( sp != root )\n"
+ " goto resume;\n"
+ " pt->flags |= PF_COMMITTED;\n"
+ "}\n"
+ "\n";
+
+}
+
+void Compiler::writeParseReduce()
+{
+ for ( ReductionVect::Iter r = rootNamespace->reductions; r.lte(); r++ ) {
+ Reduction *reduction = *r;
+ if ( reduction->parserBased )
+ writeParseReduce( reduction );
+ }
+}
+
+void Compiler::writePostfixReduce( Reduction *reduction )
+{
+ *outStream <<
+ "void " << reduction->name << "::read_reduce_forward( program_t *prg, FILE *file )\n"
+ "{\n"
+ " __gnu_cxx::stdio_filebuf<char> fbuf( file, std::ios::in|std::ios::out|std::ios::app );\n"
+ " std::iostream in( &fbuf );\n"
+ " std::string type, tok, text;\n"
+ " long _id, line, column, byte, prod_num, children;\n"
+ " read_reduce_node sentinal;\n"
+ " sentinal.next = 0;\n"
+ " read_reduce_node *stack = &sentinal, *last = 0;\n"
+ " while ( in >> type ) {\n"
+ " /* read. */\n"
+ " if ( type == \"t\" ) {\n"
+ " in >> tok >> _id >> line >> column >> byte >> text;\n"
+ " read_reduce_node *node = new read_reduce_node;\n"
+ " node->name = tok;\n"
+ " node->id = _id;\n"
+ " node->loc.name = \"<>\";\n"
+ " node->loc.line = line;\n"
+ " node->loc.column = column;\n"
+ " node->loc.byte = byte;\n"
+ " node->data.data = strdup( text.c_str() );\n"
+ " node->data.length = text.size();\n"
+ " unescape( &node->data );\n"
+ "\n"
+ " node->next = stack;\n"
+ " node->child = 0;\n"
+ " stack = node;\n"
+ " }\n"
+ " else if ( type == \"r\" ) {\n"
+ " in >> tok >> _id >> prod_num >> children;\n"
+ " read_reduce_node *node = new read_reduce_node;\n"
+ " memset( &node->loc, 0, sizeof(colm_location) );\n"
+ " memset( &node->data, 0, sizeof(colm_data) );\n"
+ " node->name = tok;\n"
+ " node->id = _id;\n"
+ " node->prod_num = prod_num;\n"
+ " node->child = 0;\n"
+ " while ( children-- > 0 ) {\n"
+ " last = stack;\n"
+ " stack = stack->next;\n"
+ " last->next = node->child;\n"
+ " node->child = last;\n"
+ " }\n"
+ "\n"
+ " node->next = stack;\n"
+ " stack = node;\n"
+ "\n"
+ " { switch ( node->id ) {\n";
+
+ /* Populate a vector with the reduce actions. */
+ Vector<ReduceAction*> actions;
+ actions.setAsNew( reduction->reduceActions.length() );
+ long pos = 0;
+ for ( ReduceActionList::Iter rdi = reduction->reduceActions; rdi.lte(); rdi++ )
+ actions[pos++] = rdi;
+
+ /* Sort it by lhs id, then prod num. */
+ MergeSort<ReduceAction*, CmpReduceAction> sortActions;
+ sortActions.sort( actions.data, actions.length() );
+
+ ReduceAction *last = 0;
+
+ for ( Vector<ReduceAction*>::Iter rdi = actions; rdi.lte(); rdi++ ) {
+ ReduceAction *action = *rdi;
+ int lelId = action->production->prodName->id;
+ int prodNum = action->production->prodNum;
+
+ /* Maybe close off the last prod. */
+ if ( last != 0 &&
+ last->production->prodName != action->production->prodName )
+ {
+ *outStream <<
+ " break;\n"
+ " }\n";
+ }
+
+ /* Maybe open a new prod. */
+ if ( last == 0 ||
+ last->production->prodName != action->production->prodName )
+ {
+ *outStream <<
+ " case " << lelId << ": {\n";
+ }
+
+ *outStream <<
+ " if ( node->prod_num == " << prodNum << " ) {\n";
+
+ loadRefs( reduction, action->production, action->itemList, true );
+
+ *outStream <<
+ "#line " << action->loc.line << "\"" << action->loc.fileName << "\"\n";
+
+ writeHostItemList( action->production, action->itemList );
+
+ *outStream <<
+ " }\n";
+
+ last = action;
+ }
+
+ if ( last != 0 ) {
+ *outStream <<
+ " break;\n"
+ " }\n";
+ }
+
+ *outStream <<
+ " } }\n"
+ " /* delete the children */\n"
+ " last = node->child;\n"
+ " while ( last != 0 ) {\n"
+ " read_reduce_node *next = last->next;\n"
+ " delete last;\n"
+ " last = next;\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ "}\n"
+ "\n";
+}
+
+void Compiler::writePostfixReduce()
+{
+ bool unescape = false;
+ for ( ReductionVect::Iter r = rootNamespace->reductions; r.lte(); r++ ) {
+ Reduction *reduction = *r;
+ if ( reduction->postfixBased ) {
+ if ( !unescape )
+ writeUnescape();
+
+ writePostfixReduce( reduction );
+ }
+ }
+}
+
+void Compiler::writeCommit()
+{
+ *outStream <<
+ "#include <colm/pdarun.h>\n"
+ "#include <colm/bytecode.h>\n"
+ "#include <colm/defs.h>\n"
+ "#include <colm/input.h>\n"
+ "#include <colm/tree.h>\n"
+ "#include <colm/program.h>\n"
+ "#include <colm/colm.h>\n"
+ "\n"
+ "#include <stdio.h>\n"
+ "#include <stdlib.h>\n"
+ "#include <string.h>\n"
+ "#include <assert.h>\n"
+ "#include <errno.h>\n"
+ "\n"
+ "#include <iostream>\n"
+ /* Not available on MAC OS. */
+ // "#include <ext/stdio_filebuf.h>\n"
+ "#include <fstream>\n"
+ "\n"
+ "using std::endl;\n"
+ "\n"
+ "#include \"reducer.h\"\n"
+ "\n";
+
+ computeNeeded();
+
+ writeReduceStructs();
+
+ writeReduceDispatchers();
+
+ //writePostfixReduce();
+
+ writeParseReduce();
+
+ writeNeeds();
+}