// Lookup a symbol in the current context. // The context includes the lexical scope stack, super scopes, // and using directives // If it doesn't exist, then return null if !fMustExist and throw exception if fMustExist public virtual SymEntry LookupSymbolWithContext(Identifier id, bool fMustExist) { string strName = id.Text; // Search through stack of lexical scopes SymEntry sym = null; Scope t = m_CurrentContext; while(t != null) { sym = LookupSymbol(t, id, false); // <-- smart lookup, go through ILookupController if (sym != null) return sym; t = t.m_LexicalParent; } // Don't need this any more with ILookupControllers #if false // Check using directives if not found in the current scope stack // Do this by traversing the scope stack and looking for UserNamespaceEntry // (we can never be in an imported namespace, so that's ok) t = m_CurrentContext; while (t != null) { AST.NamespaceDecl node = t.Node as AST.NamespaceDecl; if (node != null) { sym = node.LookupSymbolInUsingDirectives(this, id); if (sym != null) return sym; } t = t.m_LexicalParent; } #endif // Symbol not found if (fMustExist) { //ThrowError_UndefinedSymbol(id); ThrowError(SymbolError.UndefinedSymbol(id)); } return null; }
// Global namespace has "" name. public UserNamespaceEntry(AST.NamespaceDecl node, string stFullName) { Debug.Assert(node != null); Debug.Assert(stFullName != null); m_strName = node.Name; m_stFullName = stFullName; // Create the real scope for the namespace. This scope just has the symbols, // but it can't be attached to a particular node or lexical parent // since it's shared by all blocks for that namespace. if (IsGlobal) { // Add filename as a debugging hint string stFilename = node.Location.Filename; m_scope = new Scope("global " + stFilename, null, null); } else { m_scope = new Scope("user_namespace:" + node.Name, null, null); } //m_node = node; m_node = null; }
} // end Driver.Main //----------------------------------------------------------------------------- // Parse multiple source files into a single program. // The Parser only understands Lexers (as opposed to filenames), so we can't // give the parser the string array of source files. But we don't want to // create the lexers all at once and pass them to the parser either. // Return null on errors. //----------------------------------------------------------------------------- private static AST.ProgramDecl ParseAllFiles( string [] arstSourceFiles ) { //AST.ProgramDecl root = null; AST.NamespaceDecl [] arFiles = new AST.NamespaceDecl[arstSourceFiles.Length]; bool fHasErrors = false; int iFile = 0; foreach (string stSourceFile in arstSourceFiles) { string stShort = IO.Path.GetFileNameWithoutExtension(stSourceFile); // Get a lexer for this file System.IO.StreamReader reader = null; try{ reader = new System.IO.StreamReader(stSourceFile); } catch (System.Exception e) { reader = null; PrintError_CantFindSourceFile(stSourceFile, e); fHasErrors = true; } if (reader == null) { arFiles[iFile] = null; } else { ILexer lex = new ManualParser.Lexer(stSourceFile, reader, m_defines); // Parse this file IParser p = new ManualParser.Parser(lex); Debug.Assert(p != null); // Return null on errors. Continue to try and parse the other source // files so that we can catch as many errors as possible, but // we won't resolve / codegen anything if it has parse errors. Log.WriteLine(Log.LF.Parser, "Parsing source file:" + stSourceFile); AST.NamespaceDecl nodeFile = p.ParseSourceFile(); if (nodeFile == null) { fHasErrors = true; } // Spit this out even if we have errors; it may be partially helpful. if (s_fGenerateXML) { System.Xml.XmlWriter oParse = new System.Xml.XmlTextWriter(stShort + "_parse.xml", null); AST.Node.DumpTree(nodeFile, oParse); } arFiles[iFile] = nodeFile; } // Add to program iFile++; } if (fHasErrors) { return(null); } return(new AST.ProgramDecl(arFiles)); }