summaryrefslogtreecommitdiff
path: root/src/declare.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/declare.cc')
-rw-r--r--src/declare.cc1255
1 files changed, 1255 insertions, 0 deletions
diff --git a/src/declare.cc b/src/declare.cc
new file mode 100644
index 0000000..d18ce5d
--- /dev/null
+++ b/src/declare.cc
@@ -0,0 +1,1255 @@
+/*
+ * Copyright 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 "bytecode.h"
+#include "parsedata.h"
+#include <iostream>
+#include <assert.h>
+
+void Compiler::initUniqueTypes( )
+{
+ uniqueTypeNil = new UniqueType( TYPE_NIL );
+ uniqueTypeVoid = new UniqueType( TYPE_TREE, voidLangEl );
+ uniqueTypePtr = new UniqueType( TYPE_TREE, ptrLangEl );
+ uniqueTypeBool = new UniqueType( TYPE_TREE, boolLangEl );
+ uniqueTypeInt = new UniqueType( TYPE_TREE, intLangEl );
+ uniqueTypeStr = new UniqueType( TYPE_TREE, strLangEl );
+ uniqueTypeStream = new UniqueType( TYPE_TREE, streamLangEl );
+ uniqueTypeIgnore = new UniqueType( TYPE_TREE, ignoreLangEl );
+ uniqueTypeAny = new UniqueType( TYPE_TREE, anyLangEl );
+
+ uniqeTypeMap.insert( uniqueTypeNil );
+ uniqeTypeMap.insert( uniqueTypeVoid );
+ uniqeTypeMap.insert( uniqueTypePtr );
+ uniqeTypeMap.insert( uniqueTypeBool );
+ uniqeTypeMap.insert( uniqueTypeInt );
+ uniqeTypeMap.insert( uniqueTypeStr );
+ uniqeTypeMap.insert( uniqueTypeStream );
+ uniqeTypeMap.insert( uniqueTypeIgnore );
+ uniqeTypeMap.insert( uniqueTypeAny );
+}
+
+ObjectField *ObjNameScope::checkRedecl( const String &name )
+{
+ return owner->checkRedecl( this, name );
+}
+
+void ObjNameScope::insertField( const String &name, ObjectField *value )
+{
+ return owner->insertField( this, name, value );
+}
+
+ObjectField *ObjectDef::checkRedecl( ObjNameScope *inScope, const String &name )
+{
+ ObjFieldMapEl *objDefMapEl = inScope->objFieldMap->find( name );
+ if ( objDefMapEl != 0 )
+ return objDefMapEl->value;
+ return 0;
+}
+
+void ObjectDef::insertField( ObjNameScope *inScope, const String &name, ObjectField *value )
+{
+ inScope->objFieldMap->insert( name, value );
+ objFieldList->append( value );
+ value->scope = inScope;
+}
+
+ObjNameScope *ObjectDef::pushScope( ObjNameScope *curScope )
+{
+ ObjNameScope *newScope = new ObjNameScope;
+ newScope->objFieldMap = new ObjFieldMap;
+
+ newScope->owner = this;
+ newScope->parentScope = curScope;
+ curScope->children.append( newScope );
+
+ return newScope;
+}
+
+void LexJoin::varDecl( Compiler *pd, TokenDef *tokenDef )
+{
+ expr->varDecl( pd, tokenDef );
+}
+
+void LexExpression::varDecl( Compiler *pd, TokenDef *tokenDef )
+{
+ switch ( type ) {
+ case OrType: case IntersectType: case SubtractType:
+ case StrongSubtractType:
+ expression->varDecl( pd, tokenDef );
+ term->varDecl( pd, tokenDef );
+ break;
+ case TermType:
+ term->varDecl( pd, tokenDef );
+ break;
+ case BuiltinType:
+ break;
+ }
+}
+
+void LexTerm::varDecl( Compiler *pd, TokenDef *tokenDef )
+{
+ switch ( type ) {
+ case ConcatType:
+ case RightStartType:
+ case RightFinishType:
+ case LeftType:
+ term->varDecl( pd, tokenDef );
+ factorAug->varDecl( pd, tokenDef );
+ break;
+ case FactorAugType:
+ factorAug->varDecl( pd, tokenDef );
+ break;
+ }
+}
+
+void LexFactorAug::varDecl( Compiler *pd, TokenDef *tokenDef )
+{
+ for ( ReCaptureVect::Iter re = reCaptureVect; re.lte(); re++ ) {
+ if ( tokenDef->objectDef->rootScope->checkRedecl( re->objField->name ) != 0 ) {
+ error(re->objField->loc) << "label name \"" <<
+ re->objField->name << "\" already in use" << endp;
+ }
+
+ /* Insert it into the map. */
+ tokenDef->objectDef->rootScope->insertField( re->objField->name, re->objField );
+
+ /* Store it in the TokenDef. */
+ tokenDef->reCaptureVect.append( *re );
+ }
+}
+
+void Compiler::declareReVars()
+{
+ for ( NamespaceList::Iter n = namespaceList; n.lte(); n++ ) {
+ for ( TokenDefListNs::Iter tok = n->tokenDefList; tok.lte(); tok++ ) {
+ if ( tok->join != 0 )
+ tok->join->varDecl( this, tok );
+ }
+ }
+
+ /* FIXME: declare RE captures in token generation actions. */
+#if 0
+ /* Add captures to the local frame. We Depend on these becoming the
+ * first local variables so we can compute their location. */
+
+ /* Make local variables corresponding to the local capture vector. */
+ for ( ReCaptureVect::Iter c = reCaptureVect; c.lte(); c++ )
+ {
+ ObjectField *objField = ObjectField::cons( c->objField->loc,
+ c->objField->typeRef, c->objField->name );
+
+ /* Insert it into the field map. */
+ pd->curLocalFrame->insertField( objField->name, objField );
+ }
+#endif
+}
+
+LangEl *declareLangEl( Compiler *pd, Namespace *nspace, const String &data, LangEl::Type type )
+{
+ /* If the id is already in the dict, it will be placed in last found. If
+ * it is not there then it will be inserted and last found will be set to it. */
+ TypeMapEl *inDict = nspace->typeMap.find( data );
+ if ( inDict != 0 )
+ error() << "'" << data << "' already defined as something else" << endp;
+
+ /* Language element not there. Make the new lang el and insert.. */
+ LangEl *langEl = new LangEl( nspace, data, type );
+ TypeMapEl *typeMapEl = new TypeMapEl( data, langEl );
+ nspace->typeMap.insert( typeMapEl );
+ pd->langEls.append( langEl );
+
+ return langEl;
+}
+
+/* Does not map the new language element. */
+LangEl *addLangEl( Compiler *pd, Namespace *nspace, const String &data, LangEl::Type type )
+{
+ LangEl *langEl = new LangEl( nspace, data, type );
+ pd->langEls.append( langEl );
+ return langEl;
+}
+
+void declareTypeAlias( Compiler *pd, Namespace *nspace, const String &data, TypeRef *typeRef )
+{
+ /* If the id is already in the dict, it will be placed in last found. If
+ * it is not there then it will be inserted and last found will be set to it. */
+ TypeMapEl *inDict = nspace->typeMap.find( data );
+ if ( inDict != 0 )
+ error() << "'" << data << "' already defined as something else" << endp;
+
+ /* Language element not there. Make the new lang el and insert.. */
+ TypeMapEl *typeMapEl = new TypeMapEl( data, typeRef );
+ nspace->typeMap.insert( typeMapEl );
+}
+
+LangEl *findType( Compiler *pd, Namespace *nspace, const String &data )
+{
+ /* If the id is already in the dict, it will be placed in last found. If
+ * it is not there then it will be inserted and last found will be set to it. */
+ TypeMapEl *inDict = nspace->typeMap.find( data );
+
+ if ( inDict == 0 )
+ error() << "'" << data << "' not declared as anything" << endp;
+
+ return inDict->value;
+}
+
+
+void Compiler::declareBaseLangEls()
+{
+ /* Order here is important because we make assumptions about the inbuilt
+ * language elements in the runtime. Note tokens are have identifiers set
+ * in an initial pass. */
+
+ /* Make a "_notoken" language element. This element is used when a
+ * generation action fails to generate anything, but there is reverse code
+ * that needs to be associated with a language element. This allows us to
+ * always associate reverse code with the first language element produced
+ * after a generation action. */
+ noTokenLangEl = declareLangEl( this, rootNamespace, "_notoken", LangEl::Term );
+ noTokenLangEl->isIgnore = true;
+
+ ptrLangEl = declareLangEl( this, rootNamespace, "ptr", LangEl::Term );
+ voidLangEl = declareLangEl( this, rootNamespace, "void", LangEl::Term );
+ boolLangEl = declareLangEl( this, rootNamespace, "bool", LangEl::Term );
+ intLangEl = declareLangEl( this, rootNamespace, "int", LangEl::Term );
+ strLangEl = declareLangEl( this, rootNamespace, "str", LangEl::Term );
+ streamLangEl = declareLangEl( this, rootNamespace, "stream", LangEl::Term );
+ ignoreLangEl = declareLangEl( this, rootNamespace, "il", LangEl::Term );
+
+ /* Make the EOF language element. */
+ eofLangEl = 0;
+
+ /* Make the "any" language element */
+ anyLangEl = declareLangEl( this, rootNamespace, "any", LangEl::NonTerm );
+}
+
+
+void Compiler::addProdRedObjectVar( ObjectDef *localFrame, LangEl *nonTerm )
+{
+ UniqueType *prodNameUT = findUniqueType( TYPE_TREE, nonTerm );
+ TypeRef *typeRef = TypeRef::cons( internal, prodNameUT );
+ ObjectField *el = ObjectField::cons( internal, typeRef, "lhs" );
+
+ el->isLhsEl = true;
+
+ initLocalInstructions( el );
+
+ localFrame->rootScope->insertField( el->name, el );
+}
+
+void Compiler::addProdLHSLoad( Production *prod, CodeVect &code, long &insertPos )
+{
+ ObjNameScope *scope = prod->redBlock->localFrame->rootScope;
+ ObjectField *lhsField = scope->findField("lhs");
+ assert( lhsField != 0 );
+
+ CodeVect loads;
+ if ( lhsField->beenReferenced ) {
+ loads.append( IN_INIT_LHS_EL );
+ loads.appendHalf( lhsField->offset );
+ }
+
+ code.insert( insertPos, loads );
+ insertPos += loads.length();
+}
+
+void Compiler::addPushBackLHS( Production *prod, CodeVect &code, long &insertPos )
+{
+ CodeBlock *block = prod->redBlock;
+
+ /* If the lhs tree is dirty then we will need to save off the old lhs
+ * before it gets modified. We want to avoid this for attribute
+ * modifications. The computation of dirtyTree should deal with this for
+ * us. */
+ ObjNameScope *scope = block->localFrame->rootScope;
+ ObjectField *lhsField = scope->findField("lhs");
+ assert( lhsField != 0 );
+
+ if ( lhsField->beenReferenced ) {
+ code.append( IN_STORE_LHS_EL );
+ code.appendHalf( lhsField->offset );
+ }
+}
+
+void Compiler::addProdRHSVars( ObjectDef *localFrame, ProdElList *prodElList )
+{
+ long position = 1;
+ for ( ProdElList::Iter rhsEl = *prodElList; rhsEl.lte(); rhsEl++, position++ ) {
+ if ( rhsEl->type == ProdEl::ReferenceType ) {
+ /* Use an offset of zero. For frame objects we compute the offset on
+ * demand. */
+ String name( 8, "r%d", position );
+ ObjectField *el = ObjectField::cons( InputLoc(), rhsEl->typeRef, name );
+ rhsEl->rhsElField = el;
+
+ /* Right hand side elements are constant. */
+ el->isConst = true;
+ el->isRhsEl = true;
+
+ /* Only ever fetch for reading since they are constant. */
+ el->inGetR = IN_GET_LOCAL_R;
+
+ localFrame->rootScope->insertField( el->name, el );
+ }
+ }
+}
+
+void Compiler::addProdRHSLoads( Production *prod, CodeVect &code, long &insertPos )
+{
+ CodeVect loads;
+ long elPos = 0;
+ for ( ProdElList::Iter rhsEl = *prod->prodElList; rhsEl.lte(); rhsEl++, elPos++ ) {
+ if ( rhsEl->type == ProdEl::ReferenceType ) {
+ if ( rhsEl->rhsElField->beenReferenced ) {
+ loads.append ( IN_INIT_RHS_EL );
+ loads.appendHalf( elPos );
+ loads.appendHalf( rhsEl->rhsElField->offset );
+ }
+ }
+ }
+
+ /* Insert and update the insert position. */
+ code.insert( insertPos, loads );
+ insertPos += loads.length();
+}
+
+void GenericType::declare( Compiler *pd, Namespace *nspace )
+{
+ //std::cout << "generic " << g->name << std::endl;
+
+ LangEl *langEl = declareLangEl( pd, nspace, name, LangEl::NonTerm );
+
+ /* Add one empty production. */
+ ProdElList *emptyList = new ProdElList;
+ //addProduction( g->loc, langEl, emptyList, false, 0, 0 );
+
+ {
+ LangEl *prodName = langEl;
+ assert( prodName->type == LangEl::NonTerm );
+
+ Production *newDef = Production::cons( InputLoc(), prodName,
+ emptyList, String(), false, 0,
+ pd->prodList.length(), prodName->defList.length() );
+
+ prodName->defList.append( newDef );
+ pd->prodList.append( newDef );
+ newDef->predOf = 0;
+ }
+
+ langEl->generic = this;
+ this->langEl = langEl;
+
+ utArg = typeArg->uniqueType;
+
+ if ( typeId == GEN_MAP )
+ keyUT = keyTypeArg->uniqueType;
+
+ objDef = ObjectDef::cons( ObjectDef::BuiltinType,
+ name, pd->nextObjectId++ );
+
+ switch ( typeId ) {
+ case GEN_MAP:
+ pd->initMapFunctions( this );
+ break;
+ case GEN_LIST:
+ pd->initListFunctions( this );
+ pd->initListFields( this );
+ break;
+ case GEN_VECTOR:
+ pd->initVectorFunctions( this );
+ break;
+ case GEN_PARSER:
+ /* Need to generate a parser for the type. */
+ utArg->langEl->parserId = pd->nextParserId++;
+ pd->initParserFunctions( this );
+ pd->initParserFields( this );
+ break;
+ }
+
+ langEl->objectDef = objDef;
+}
+
+void Namespace::declare( Compiler *pd )
+{
+ for ( GenericList::Iter g = genericList; g.lte(); g++ )
+ g->declare( pd, this );
+
+ for ( TokenDefListNs::Iter tokenDef = tokenDefList; tokenDef.lte(); tokenDef++ ) {
+ if ( tokenDef->isLiteral ) {
+ if ( tokenDef->isZero ) {
+ assert( tokenDef->regionSet->collectIgnore->zeroLel != 0 );
+ tokenDef->tdLangEl = tokenDef->regionSet->collectIgnore->zeroLel;
+ }
+ else {
+ /* Original. Create a token for the literal. */
+ LangEl *litEl = declareLangEl( pd, this, tokenDef->name, LangEl::Term );
+
+ litEl->lit = tokenDef->literal;
+ litEl->isLiteral = true;
+ litEl->tokenDef = tokenDef;
+ litEl->objectDef = tokenDef->objectDef;
+
+ tokenDef->tdLangEl = litEl;
+
+ if ( tokenDef->noPreIgnore )
+ litEl->noPreIgnore = true;
+ if ( tokenDef->noPostIgnore )
+ litEl->noPostIgnore = true;
+ }
+ }
+ }
+
+ for ( ContextDefList::Iter c = contextDefList; c.lte(); c++ ) {
+ LangEl *lel = declareLangEl( pd, this, c->name, LangEl::NonTerm );
+ ProdElList *emptyList = new ProdElList;
+ //addProduction( c->context->loc, c->name, emptyList, false, 0, 0 );
+
+ {
+ LangEl *prodName = lel;
+ assert( prodName->type == LangEl::NonTerm );
+
+ Production *newDef = Production::cons( loc, prodName,
+ emptyList, String(), false, 0,
+ pd->prodList.length(), prodName->defList.length() );
+
+ prodName->defList.append( newDef );
+ pd->prodList.append( newDef );
+ newDef->predOf = 0;
+
+ /* If the token has the same name as the region it is in, then also
+ * insert it into the symbol map for the parent region. */
+ if ( strcmp( c->name, this->name ) == 0 ) {
+ /* Insert the name into the top of the region stack after popping the
+ * region just created. We need it in the parent. */
+ TypeMapEl *typeMapEl = new TypeMapEl( c->name, prodName );
+ this->parentNamespace->typeMap.insert( typeMapEl );
+ }
+ }
+
+ c->context->lel = lel;
+ lel->contextDef = c->context;
+ lel->objectDef = c->context->contextObjDef;
+ }
+
+ for ( TokenDefListNs::Iter tokenDef = tokenDefList; tokenDef.lte(); tokenDef++ ) {
+ /* Literals already taken care of. */
+ if ( ! tokenDef->isLiteral ) {
+ /* Create the token. */
+ LangEl *tokEl = declareLangEl( pd, this, tokenDef->name, LangEl::Term );
+ tokEl->isIgnore = tokenDef->isIgnore;
+ tokEl->transBlock = tokenDef->codeBlock;
+ tokEl->objectDef = tokenDef->objectDef;
+ tokEl->contextIn = tokenDef->contextIn;
+ tokEl->tokenDef = tokenDef;
+
+ if ( tokenDef->noPreIgnore )
+ tokEl->noPreIgnore = true;
+ if ( tokenDef->noPostIgnore )
+ tokEl->noPostIgnore = true;
+
+ tokenDef->tdLangEl = tokEl;
+
+ if ( tokenDef->isZero ) {
+ /* Setting zero lel to newly created tokEl. */
+ tokenDef->regionSet->collectIgnore->zeroLel = tokEl;
+ tokEl->isZero = true;
+ }
+ }
+ }
+
+ for ( NtDefList::Iter n = ntDefList; n.lte(); n++ ) {
+ /* Get the language element. */
+ LangEl *langEl = declareLangEl( pd, this, n->name, LangEl::NonTerm );
+ //$$->langEl = langEl;
+
+ /* Get the language element. */
+ langEl->objectDef = n->objectDef;
+ langEl->reduceFirst = n->reduceFirst;
+ langEl->contextIn = n->contextIn;
+ langEl->defList.transfer( *n->defList );
+
+ for ( LelDefList::Iter d = langEl->defList; d.lte(); d++ ) {
+ d->prodName = langEl;
+
+ if ( d->redBlock != 0 ) {
+ pd->addProdRedObjectVar( d->redBlock->localFrame, langEl );
+ pd->addProdRHSVars( d->redBlock->localFrame, d->prodElList );
+ }
+
+ /* References to the reduce item. */
+ }
+ }
+
+ for ( TypeAliasList::Iter ta = typeAliasList; ta.lte(); ta++ )
+ declareTypeAlias( pd, this, ta->name, ta->typeRef );
+
+ /* Go into child aliases. */
+ for ( NamespaceVect::Iter c = childNamespaces; c.lte(); c++ )
+ (*c)->declare( pd );
+}
+
+void Compiler::makeIgnoreCollectors()
+{
+ for ( RegionSetList::Iter regionSet = regionSetList; regionSet.lte(); regionSet++ ) {
+ if ( regionSet->collectIgnore->zeroLel == 0 ) {
+ String name( 128, "_ign_%p", regionSet->tokenIgnore );
+ LangEl *zeroLel = new LangEl( rootNamespace, name, LangEl::Term );
+ langEls.append( zeroLel );
+ zeroLel->isZero = true;
+ zeroLel->regionSet = regionSet;
+
+ regionSet->collectIgnore->zeroLel = zeroLel;
+ }
+ }
+}
+
+void LangStmt::chooseDefaultIter( Compiler *pd, IterCall *iterCall ) const
+{
+ /* The iterator name. */
+ LangVarRef *callVarRef = LangVarRef::cons( loc, context, scope, "triter" );
+
+ /* The parameters. */
+ CallArgVect *callExprVect = new CallArgVect;
+ callExprVect->append( new CallArg( iterCall->langExpr ) );
+ iterCall->langTerm = LangTerm::cons( InputLoc(), callVarRef, callExprVect );
+ iterCall->langExpr = 0;
+ iterCall->form = IterCall::IterCallForm;
+}
+
+
+void LangStmt::declareForIter( Compiler *pd ) const
+{
+ if ( iterCall->form != IterCall::IterCallForm )
+ chooseDefaultIter( pd, iterCall );
+
+ objField->typeRef = TypeRef::cons( loc, typeRef, iterCall );
+}
+
+void LangStmt::declare( Compiler *pd ) const
+{
+ switch ( type ) {
+ case PrintType:
+ break;
+ case PrintXMLACType:
+ break;
+ case PrintXMLType:
+ break;
+ case PrintStreamType:
+ break;
+ case ExprType:
+ break;
+ case IfType:
+ for ( StmtList::Iter stmt = *stmtList; stmt.lte(); stmt++ )
+ stmt->declare( pd );
+
+ if ( elsePart != 0 )
+ elsePart->declare( pd );
+ break;
+
+ case ElseType:
+ for ( StmtList::Iter stmt = *stmtList; stmt.lte(); stmt++ )
+ stmt->declare( pd );
+ break;
+ case RejectType:
+ break;
+ case WhileType:
+ for ( StmtList::Iter stmt = *stmtList; stmt.lte(); stmt++ )
+ stmt->declare( pd );
+ break;
+ case AssignType:
+ break;
+ case ForIterType:
+ declareForIter( pd );
+
+ for ( StmtList::Iter stmt = *stmtList; stmt.lte(); stmt++ )
+ stmt->declare( pd );
+ break;
+ case ReturnType:
+ break;
+ case BreakType:
+ break;
+ case YieldType:
+ break;
+ }
+}
+
+void CodeBlock::declare( Compiler *pd ) const
+{
+ for ( StmtList::Iter stmt = *stmtList; stmt.lte(); stmt++ )
+ stmt->declare( pd );
+}
+
+
+void Compiler::declareFunction( Function *func )
+{
+ CodeBlock *block = func->codeBlock;
+ block->declare( this );
+}
+
+void Compiler::declareReductionCode( Production *prod )
+{
+ CodeBlock *block = prod->redBlock;
+ block->declare( this );
+}
+
+void Compiler::declareTranslateBlock( LangEl *langEl )
+{
+ CodeBlock *block = langEl->transBlock;
+
+ /* References to the reduce item. */
+ addMatchLength( block->localFrame, langEl );
+ addMatchText( block->localFrame, langEl );
+ addInput( block->localFrame );
+ addCtx( block->localFrame );
+
+ block->declare( this );
+}
+
+void Compiler::declarePreEof( TokenRegion *region )
+{
+ CodeBlock *block = region->preEofBlock;
+
+ addInput( block->localFrame );
+ addCtx( block->localFrame );
+
+ block->declare( this );
+}
+
+void Compiler::declareRootBlock()
+{
+ CodeBlock *block = rootCodeBlock;
+ block->declare( this );
+}
+
+void Compiler::declareByteCode()
+{
+ for ( FunctionList::Iter f = functionList; f.lte(); f++ )
+ declareFunction( f );
+
+ for ( DefList::Iter prod = prodList; prod.lte(); prod++ ) {
+ if ( prod->redBlock != 0 )
+ declareReductionCode( prod );
+ }
+
+ for ( LelList::Iter lel = langEls; lel.lte(); lel++ ) {
+ if ( lel->transBlock != 0 )
+ declareTranslateBlock( lel );
+ }
+
+ for ( RegionList::Iter r = regionList; r.lte(); r++ ) {
+ if ( r->preEofBlock != 0 )
+ declarePreEof( r );
+ }
+
+ declareRootBlock( );
+}
+
+void Compiler::makeDefaultIterators()
+{
+ /* Tree iterator. */
+ {
+ UniqueType *anyRefUT = findUniqueType( TYPE_REF, anyLangEl );
+ ObjMethod *objMethod = initFunction( uniqueTypeAny, globalObjectDef,
+ "triter", IN_HALT, IN_HALT, anyRefUT, true );
+
+ IterDef *triter = findIterDef( IterDef::Tree );
+ objMethod->iterDef = triter;
+ }
+
+ /* Child iterator. */
+ {
+ UniqueType *anyRefUT = findUniqueType( TYPE_REF, anyLangEl );
+ ObjMethod *objMethod = initFunction( uniqueTypeAny, globalObjectDef,
+ "child", IN_HALT, IN_HALT, anyRefUT, true );
+
+ IterDef *triter = findIterDef( IterDef::Child );
+ objMethod->iterDef = triter;
+ }
+
+ /* Reverse iterator. */
+ {
+ UniqueType *anyRefUT = findUniqueType( TYPE_REF, anyLangEl );
+ ObjMethod *objMethod = initFunction( uniqueTypeAny, globalObjectDef,
+ "rev_child", IN_HALT, IN_HALT, anyRefUT, true );
+
+ IterDef *triter = findIterDef( IterDef::RevChild );
+ objMethod->iterDef = triter;
+ }
+
+ /* Repeat iterator. */
+ {
+ UniqueType *anyRefUT = findUniqueType( TYPE_REF, anyLangEl );
+ ObjMethod *objMethod = initFunction( uniqueTypeAny, globalObjectDef,
+ "repeat", IN_HALT, IN_HALT, anyRefUT, true );
+
+ IterDef *triter = findIterDef( IterDef::Repeat );
+ objMethod->iterDef = triter;
+ }
+
+ /* Reverse repeat iterator. */
+ {
+ UniqueType *anyRefUT = findUniqueType( TYPE_REF, anyLangEl );
+ ObjMethod *objMethod = initFunction( uniqueTypeAny, globalObjectDef,
+ "rev_repeat", IN_HALT, IN_HALT, anyRefUT, true );
+
+ IterDef *triter = findIterDef( IterDef::RevRepeat );
+ objMethod->iterDef = triter;
+ }
+}
+
+void Compiler::addMatchLength( ObjectDef *frame, LangEl *lel )
+{
+ /* Make the type ref. */
+ TypeRef *typeRef = TypeRef::cons( internal, uniqueTypeInt );
+
+ /* Create the field and insert it into the map. */
+ ObjectField *el = ObjectField::cons( InputLoc(), typeRef, "match_length" );
+ el->beenReferenced = true;
+ el->beenInitialized = true;
+ el->isConst = true;
+ el->useOffset = false;
+ el->inGetR = IN_GET_MATCH_LENGTH_R;
+ frame->rootScope->insertField( el->name, el );
+}
+
+void Compiler::addMatchText( ObjectDef *frame, LangEl *lel )
+{
+ /* Make the type ref. */
+ TypeRef *typeRef = TypeRef::cons( internal, uniqueTypeStr );
+
+ /* Create the field and insert it into the map. */
+ ObjectField *el = ObjectField::cons( internal, typeRef, "match_text" );
+ el->beenReferenced = true;
+ el->beenInitialized = true;
+ el->isConst = true;
+ el->useOffset = false;
+ el->inGetR = IN_GET_MATCH_TEXT_R;
+ frame->rootScope->insertField( el->name, el );
+}
+
+void Compiler::addInput( ObjectDef *frame )
+{
+ /* Make the type ref. */
+ TypeRef *typeRef = TypeRef::cons( internal, uniqueTypeStream );
+
+ /* Create the field and insert it into the map. */
+ ObjectField *el = ObjectField::cons( internal, typeRef, "input" );
+ el->beenReferenced = true;
+ el->beenInitialized = true;
+ el->isConst = false;
+ el->useOffset = false;
+ el->isCustom = true;
+ el->inGetR = IN_LOAD_INPUT_R;
+ el->inGetWV = IN_LOAD_INPUT_WV;
+ el->inGetWC = IN_LOAD_INPUT_WC;
+ frame->rootScope->insertField( el->name, el );
+}
+
+void Compiler::addCtx( ObjectDef *frame )
+{
+ /* Make the type ref. */
+ TypeRef *typeRef = TypeRef::cons( internal, uniqueTypeStream );
+
+ /* Create the field and insert it into the map. */
+ ObjectField *el = ObjectField::cons( internal, typeRef, "ctx" );
+ el->beenReferenced = true;
+ el->beenInitialized = true;
+ el->isConst = false;
+ el->useOffset = false;
+ el->isCustom = true;
+ el->inGetR = IN_LOAD_CTX_R;
+ el->inGetWV = IN_LOAD_CTX_WV;
+ el->inGetWC = IN_LOAD_CTX_WC;
+ frame->rootScope->insertField( el->name, el );
+}
+
+void Compiler::initIntObject( )
+{
+ intObj = ObjectDef::cons( ObjectDef::BuiltinType, "int", nextObjectId++ );
+ intLangEl->objectDef = intObj;
+
+ initFunction( uniqueTypeStr, intObj, "to_string", IN_INT_TO_STR, IN_INT_TO_STR, true );
+}
+
+void Compiler::initStrObject( )
+{
+ strObj = ObjectDef::cons( ObjectDef::BuiltinType, "str", nextObjectId++ );
+ strLangEl->objectDef = strObj;
+
+ initFunction( uniqueTypeInt, strObj, "atoi", IN_STR_ATOI, IN_STR_ATOI, true );
+ initFunction( uniqueTypeInt, strObj, "uord8", IN_STR_UORD8, IN_STR_UORD8, true );
+ initFunction( uniqueTypeInt, strObj, "sord8", IN_STR_SORD8, IN_STR_SORD8, true );
+ initFunction( uniqueTypeInt, strObj, "uord16", IN_STR_UORD16, IN_STR_UORD16, true );
+ initFunction( uniqueTypeInt, strObj, "sord16", IN_STR_SORD16, IN_STR_SORD16, true );
+ initFunction( uniqueTypeInt, strObj, "uord32", IN_STR_UORD32, IN_STR_UORD32, true );
+ initFunction( uniqueTypeInt, strObj, "sord32", IN_STR_SORD32, IN_STR_SORD32, true );
+ addLengthField( strObj, IN_STR_LENGTH );
+
+ initFunction( uniqueTypeStr, globalObjectDef, "sprintf",
+ IN_SPRINTF, IN_SPRINTF, uniqueTypeStr, uniqueTypeInt, true );
+}
+
+void Compiler::initStreamObject( )
+{
+ streamObj = ObjectDef::cons( ObjectDef::BuiltinType,
+ "stream", nextObjectId++ );
+ streamLangEl->objectDef = streamObj;
+
+ initFunction( uniqueTypeStr, streamObj, "pull",
+ IN_INPUT_PULL_WV, IN_INPUT_PULL_WC, uniqueTypeInt, false );
+ initFunction( uniqueTypeStr, streamObj, "push",
+ IN_INPUT_PUSH_WV, IN_INPUT_PUSH_WV, uniqueTypeAny, false );
+ initFunction( uniqueTypeStr, streamObj, "push_ignore",
+ IN_INPUT_PUSH_IGNORE_WV, IN_INPUT_PUSH_IGNORE_WV, uniqueTypeAny, false );
+}
+
+ObjectField *Compiler::makeDataEl()
+{
+ /* Create the "data" field. */
+ TypeRef *typeRef = TypeRef::cons( internal, uniqueTypeStr );
+ ObjectField *el = ObjectField::cons( internal, typeRef, "data" );
+
+ /* Setting beenReferenced to true prevents us from assigning instructions
+ * and an offset to the field. */
+
+ el->beenReferenced = true;
+ el->beenInitialized = true;
+ el->useOffset = false;
+ el->inGetR = IN_GET_TOKEN_DATA_R;
+ el->inSetWC = IN_SET_TOKEN_DATA_WC;
+ el->inSetWV = IN_SET_TOKEN_DATA_WV;
+ return el;
+}
+
+ObjectField *Compiler::makePosEl()
+{
+ /* Create the "data" field. */
+ TypeRef *typeRef = TypeRef::cons( internal, uniqueTypeInt );
+ ObjectField *el = ObjectField::cons( internal, typeRef, "pos" );
+
+ /* Setting beenReferenced to true prevents us from assigning instructions
+ * and an offset to the field. */
+
+ el->isConst = true;
+ el->beenReferenced = true;
+ el->beenInitialized = true;
+ el->useOffset = false;
+ el->inGetR = IN_GET_TOKEN_POS_R;
+ return el;
+}
+
+ObjectField *Compiler::makeLineEl()
+{
+ /* Create the "data" field. */
+ TypeRef *typeRef = TypeRef::cons( internal, uniqueTypeInt );
+ ObjectField *el = ObjectField::cons( internal, typeRef, "line" );
+
+ /* Setting beenReferenced to true prevents us from assigning instructions
+ * and an offset to the field. */
+
+ el->isConst = true;
+ el->beenReferenced = true;
+ el->beenInitialized = true;
+ el->useOffset = false;
+ el->inGetR = IN_GET_TOKEN_LINE_R;
+ return el;
+}
+
+void Compiler::initFieldInstructions( ObjectField *el )
+{
+ el->inGetR = IN_GET_FIELD_R;
+ el->inGetWC = IN_GET_FIELD_WC;
+ el->inGetWV = IN_GET_FIELD_WV;
+ el->inSetWC = IN_SET_FIELD_WC;
+ el->inSetWV = IN_SET_FIELD_WV;
+}
+
+void Compiler::initLocalInstructions( ObjectField *el )
+{
+ el->inGetR = IN_GET_LOCAL_R;
+ el->inGetWC = IN_GET_LOCAL_WC;
+ el->inSetWC = IN_SET_LOCAL_WC;
+}
+
+void Compiler::initLocalRefInstructions( ObjectField *el )
+{
+ el->inGetR = IN_GET_LOCAL_REF_R;
+ el->inGetWC = IN_GET_LOCAL_REF_WC;
+ el->inSetWC = IN_SET_LOCAL_REF_WC;
+}
+
+/* Add a constant length field to the object.
+ * Opcode supplied by the caller. */
+void Compiler::addLengthField( ObjectDef *objDef, Code getLength )
+{
+ /* Create the "length" field. */
+ TypeRef *typeRef = TypeRef::cons( internal, uniqueTypeInt );
+ ObjectField *el = ObjectField::cons( internal, typeRef, "length" );
+ el->beenReferenced = true;
+ el->beenInitialized = true;
+ el->isConst = true;
+ el->useOffset = false;
+ el->inGetR = getLength;
+
+ objDef->rootScope->insertField( el->name, el );
+}
+
+void Compiler::initTokenObjects( )
+{
+ /* Give all user terminals the token object type. */
+ for ( LelList::Iter lel = langEls; lel.lte(); lel++ ) {
+ if ( lel->type == LangEl::Term ) {
+ if ( lel->objectDef != 0 ) {
+ /* Create the "data" field. */
+ ObjectField *dataEl = makeDataEl();
+ lel->objectDef->rootScope->insertField( dataEl->name, dataEl );
+
+ /* Create the "pos" field. */
+ ObjectField *posEl = makePosEl();
+ lel->objectDef->rootScope->insertField( posEl->name, posEl );
+
+ /* Create the "line" field. */
+ ObjectField *lineEl = makeLineEl();
+ lel->objectDef->rootScope->insertField( lineEl->name, lineEl );
+ }
+ }
+ }
+}
+
+void Compiler::initGlobalFunctions()
+{
+ ObjMethod *method;
+
+ method = initFunction( uniqueTypeStream, globalObjectDef, "open",
+ IN_OPEN_FILE, IN_OPEN_FILE, uniqueTypeStr, uniqueTypeStr, true );
+ method->useCallObj = false;
+
+ method = initFunction( uniqueTypeStr, globalObjectDef, "tolower",
+ IN_TO_LOWER, IN_TO_LOWER, uniqueTypeStr, true );
+ method->useCallObj = false;
+
+ method = initFunction( uniqueTypeStr, globalObjectDef, "toupper",
+ IN_TO_UPPER, IN_TO_UPPER, uniqueTypeStr, true );
+ method->useCallObj = false;
+
+ method = initFunction( uniqueTypeInt, globalObjectDef, "exit",
+ IN_EXIT, IN_EXIT, uniqueTypeInt, true );
+
+ method = initFunction( uniqueTypeInt, globalObjectDef, "system",
+ IN_SYSTEM, IN_SYSTEM, uniqueTypeStr, true );
+
+ addStdin();
+ addStdout();
+ addStderr();
+ addArgv();
+ addError();
+}
+
+void Compiler::addStdin()
+{
+ /* Make the type ref. */
+ TypeRef *typeRef = TypeRef::cons( internal, uniqueTypeStream );
+
+ /* Create the field and insert it into the map. */
+ ObjectField *el = ObjectField::cons( internal, typeRef, "stdin" );
+ el->beenReferenced = true;
+ el->beenInitialized = true;
+ el->isConst = true;
+ el->useOffset = false;
+ el->inGetR = IN_GET_STDIN;
+ el->inGetWC = IN_GET_STDIN;
+ el->inGetWV = IN_GET_STDIN;
+ globalObjectDef->rootScope->insertField( el->name, el );
+}
+
+void Compiler::addStdout()
+{
+ /* Make the type ref. */
+ TypeRef *typeRef = TypeRef::cons( internal, uniqueTypeStream );
+
+ /* Create the field and insert it into the map. */
+ ObjectField *el = ObjectField::cons( internal, typeRef, "stdout" );
+ el->beenReferenced = true;
+ el->beenInitialized = true;
+ el->isConst = true;
+ el->useOffset = false;
+ el->inGetR = IN_GET_STDOUT;
+ el->inGetWC = IN_GET_STDOUT;
+ el->inGetWV = IN_GET_STDOUT;
+ globalObjectDef->rootScope->insertField( el->name, el );
+}
+
+void Compiler::addStderr()
+{
+ /* Make the type ref. */
+ TypeRef *typeRef = TypeRef::cons( internal, uniqueTypeStream );
+
+ /* Create the field and insert it into the map. */
+ ObjectField *el = ObjectField::cons( internal, typeRef, "stderr" );
+ el->beenReferenced = true;
+ el->beenInitialized = true;
+ el->isConst = true;
+ el->useOffset = false;
+ el->inGetR = IN_GET_STDERR;
+ el->inGetWC = IN_GET_STDERR;
+ el->inGetWV = IN_GET_STDERR;
+ globalObjectDef->rootScope->insertField( el->name, el );
+}
+
+void Compiler::addArgv()
+{
+ /* Create the field and insert it into the map. */
+ ObjectField *el = ObjectField::cons( internal, argvTypeRef, "argv" );
+ el->isArgv = true;
+ el->isConst = true;
+ globalObjectDef->rootScope->insertField( el->name, el );
+}
+
+void Compiler::addError()
+{
+ /* Make the type ref. */
+ TypeRef *typeRef = TypeRef::cons( internal, uniqueTypeStr );
+
+ /* Create the field and insert it into the map. */
+ ObjectField *el = ObjectField::cons( internal, typeRef, "error" );
+ el->beenReferenced = true;
+ el->beenInitialized = true;
+ el->isConst = true;
+ el->useOffset = false;
+ el->inGetR = IN_GET_ERROR;
+ el->inGetWC = IN_GET_ERROR;
+ el->inGetWV = IN_GET_ERROR;
+ globalObjectDef->rootScope->insertField( el->name, el );
+}
+
+int Compiler::argvOffset()
+{
+ for ( ObjFieldList::Iter field = *globalObjectDef->objFieldList;
+ field.lte(); field++ )
+ {
+ if ( field->value->isArgv ) {
+ globalObjectDef->referenceField( this, field->value );
+ return field->value->offset;
+ }
+ }
+ assert(false);
+}
+
+void Compiler::initMapFunctions( GenericType *gen )
+{
+ addLengthField( gen->objDef, IN_MAP_LENGTH );
+ initFunction( gen->utArg, gen->objDef, "find",
+ IN_MAP_FIND, IN_MAP_FIND, gen->keyUT, true );
+ initFunction( uniqueTypeInt, gen->objDef, "insert",
+ IN_MAP_INSERT_WV, IN_MAP_INSERT_WC, gen->keyUT, gen->utArg, false );
+ initFunction( uniqueTypeInt, gen->objDef, "store",
+ IN_MAP_STORE_WV, IN_MAP_STORE_WC, gen->keyUT, gen->utArg, false );
+ initFunction( gen->utArg, gen->objDef, "remove",
+ IN_MAP_REMOVE_WV, IN_MAP_REMOVE_WC, gen->keyUT, false );
+}
+
+void Compiler::initListFunctions( GenericType *gen )
+{
+ addLengthField( gen->objDef, IN_LIST_LENGTH );
+
+ initFunction( uniqueTypeInt, gen->objDef, "append",
+ IN_LIST_APPEND_WV, IN_LIST_APPEND_WC, gen->utArg, false );
+ initFunction( uniqueTypeInt, gen->objDef, "push",
+ IN_LIST_APPEND_WV, IN_LIST_APPEND_WC, gen->utArg, false );
+
+ initFunction( gen->utArg, gen->objDef, "remove_end",
+ IN_LIST_REMOVE_END_WV, IN_LIST_REMOVE_END_WC, false );
+ initFunction( gen->utArg, gen->objDef, "pop",
+ IN_LIST_REMOVE_END_WV, IN_LIST_REMOVE_END_WC, false );
+}
+
+void Compiler::initListField( GenericType *gen, const char *name, int offset )
+{
+ /* Make the type ref and create the field. */
+ TypeRef *typeRef = TypeRef::cons( internal, gen->utArg );
+ ObjectField *el = ObjectField::cons( internal, typeRef, name );
+
+ el->inGetR = IN_GET_LIST_MEM_R;
+ el->inGetWC = IN_GET_LIST_MEM_WC;
+ el->inGetWV = IN_GET_LIST_MEM_WV;
+ el->inSetWC = IN_SET_LIST_MEM_WC;
+ el->inSetWV = IN_SET_LIST_MEM_WV;
+
+ gen->objDef->rootScope->insertField( el->name, el );
+
+ el->useOffset = true;
+ el->beenReferenced = true;
+ el->beenInitialized = true;
+
+ /* Zero for head, One for tail. */
+ el->offset = offset;
+}
+
+void Compiler::initListFields( GenericType *gen )
+{
+ initListField( gen, "head", 0 );
+ initListField( gen, "tail", 1 );
+ initListField( gen, "top", 1 );
+}
+
+void Compiler::initVectorFunctions( GenericType *gen )
+{
+ addLengthField( gen->objDef, IN_VECTOR_LENGTH );
+ initFunction( uniqueTypeInt, gen->objDef, "append",
+ IN_VECTOR_APPEND_WV, IN_VECTOR_APPEND_WC, gen->utArg, false );
+ initFunction( uniqueTypeInt, gen->objDef, "insert",
+ IN_VECTOR_INSERT_WV, IN_VECTOR_INSERT_WC, uniqueTypeInt, gen->utArg, false );
+}
+
+void Compiler::initParserFunctions( GenericType *gen )
+{
+ initFunction( gen->utArg, gen->objDef, "finish",
+ IN_PARSE_FINISH_WV, IN_PARSE_FINISH_WC, true );
+
+ initFunction( gen->utArg, gen->objDef, "eof",
+ IN_PARSE_FINISH_WV, IN_PARSE_FINISH_WC, true );
+}
+
+void Compiler::initParserField( GenericType *gen, const char *name, int offset, TypeRef *typeRef )
+{
+ /* Make the type ref and create the field. */
+ ObjectField *el = ObjectField::cons( internal, typeRef, name );
+
+ el->inGetR = IN_GET_PARSER_MEM_R;
+ el->inGetWC = IN_GET_PARSER_MEM_WC;
+ el->inGetWV = IN_GET_PARSER_MEM_WV;
+ el->inSetWC = IN_SET_PARSER_MEM_WC;
+ el->inSetWV = IN_SET_PARSER_MEM_WV;
+
+ gen->objDef->rootScope->insertField( el->name, el );
+
+ el->useOffset = true;
+ el->beenReferenced = true;
+ el->beenInitialized = true;
+
+ /* Zero for head, One for tail. */
+ el->offset = offset;
+}
+
+void Compiler::initCtxField( GenericType *gen )
+{
+ LangEl *langEl = gen->utArg->langEl;
+ Context *context = langEl->contextIn;
+
+ /* Make the type ref and create the field. */
+ UniqueType *ctxUT = findUniqueType( TYPE_TREE, context->lel );
+ TypeRef *typeRef = TypeRef::cons( internal, ctxUT );
+ ObjectField *el = ObjectField::cons( internal, typeRef, "ctx" );
+
+ el->inGetR = IN_GET_PARSER_CTX_R;
+ el->inGetWC = IN_GET_PARSER_CTX_WC;
+ el->inGetWV = IN_GET_PARSER_CTX_WV;
+ el->inSetWC = IN_SET_PARSER_CTX_WC;
+ el->inSetWV = IN_SET_PARSER_CTX_WV;
+
+ gen->objDef->rootScope->insertField( el->name, el );
+
+ el->useOffset = false;
+ el->beenReferenced = true;
+ el->beenInitialized = true;
+}
+
+void Compiler::initParserFields( GenericType *gen )
+{
+ LangEl *langEl = gen->utArg->langEl;
+ if ( langEl->contextIn != 0 )
+ initCtxField( gen );
+
+ TypeRef *typeRef;
+
+ typeRef = TypeRef::cons( internal, gen->utArg );
+ initParserField( gen, "tree", 0, typeRef );
+
+ typeRef = TypeRef::cons( internal, uniqueTypeStr );
+ initParserField( gen, "error", 1, typeRef );
+}
+
+void Compiler::makeFuncVisible( Function *func, bool isUserIter )
+{
+ func->localFrame = func->codeBlock->localFrame;
+
+ /* Set up the parameters. */
+ long paramPos = 0;
+ for ( ParameterList::Iter param = *func->paramList; param.lte(); param++ ) {
+ if ( func->localFrame->rootScope->findField( param->name ) != 0 )
+ error(param->loc) << "parameter " << param->name << " redeclared" << endp;
+
+ func->localFrame->rootScope->insertField( param->name, param );
+ param->beenInitialized = true;
+ param->pos = paramPos;
+
+ paramPos += 1;
+ }
+
+ /* Insert the function into the global function map. */
+ ObjMethod *objMethod = new ObjMethod( func->typeRef, func->name,
+ IN_CALL_WV, IN_CALL_WC,
+ func->paramList->length(), 0, func->paramList, false );
+ objMethod->funcId = func->funcId;
+ objMethod->useFuncId = true;
+ objMethod->useCallObj = false;
+ objMethod->func = func;
+
+ if ( isUserIter ) {
+ IterDef *uiter = findIterDef( IterDef::User, func );
+ objMethod->iterDef = uiter;
+ }
+
+ globalObjectDef->objMethodMap->insert( func->name, objMethod );
+
+ func->objMethod = objMethod;
+}
+
+/*
+ * Type Declaration Root.
+ */
+void Compiler::declarePass()
+{
+ declareReVars();
+
+ makeDefaultIterators();
+
+ for ( FunctionList::Iter f = functionList; f.lte(); f++ )
+ makeFuncVisible( f, f->isUserIter );
+
+ rootNamespace->declare( this );
+
+ /* Will fill in zero lels that were not declared. */
+ makeIgnoreCollectors();
+
+ declareByteCode();
+
+ initIntObject();
+ initStrObject();
+ initStreamObject();
+ initTokenObjects();
+ initGlobalFunctions();
+
+ /* Fill any empty scanners with a default token. */
+ initEmptyScanners();
+}