//-------------------------------------------------------------------------------------------------- // // @ CopyRight Roberti & Parau Enterprises, Inc. 2021-2023 // // This work is licensed under the Creative Commons Attribution-NoDerivatives 4.0 International License. // To view a copy of this license, visit http://creativecommons.org/licenses/by-nd/4.0/ // or send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA. // //-------------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------- // // Class to manage symbols // //-------------------------------------------------------------------------------------------------- package framework; import java.util.*; import java.math.BigInteger; public class DVSymbols { protected DVSymbols(DVStatements statements) { this.statements= statements; } // // Symbol inner class // public class Symbol { protected Symbol(Token parseToken) { this.token= parseToken; this.name= parseToken.image.toUpperCase(); DVSymbols.this.symbolMap.put(this.name, this); } protected Symbol(Token parseToken, String name) { this.token= parseToken; this.name= name.toUpperCase(); DVSymbols.this.symbolMap.put(this.name, this); } // // Set symbol value dependency on value // protected void setValueValueDependency(Symbol depSymbol) { if (this.valueValueDependentList == null) this.valueValueDependentList= new HashSet();; if (! this.valueValueDependentList.add(depSymbol)) return; depSymbol.originalValueNumberDependencies++; } // // Set symbol value dependency on repl // protected void setValueReplDependency(Symbol depSymbol) { if (this.valueReplDependentList == null) this.valueReplDependentList= new HashSet();; if (! this.valueReplDependentList.add(depSymbol)) return; depSymbol.originalReplNumberDependencies++; } // // Set symbol repl dependency on value // protected void setReplValueDependency(Symbol depSymbol) { if (this.replValueDependentList == null) this.replValueDependentList= new HashSet();; if (! this.replValueDependentList.add(depSymbol)) return; depSymbol.originalValueNumberDependencies++; } // // Set symbol repl dependency on repl // protected void setReplReplDependency(Symbol depSymbol) { if (this.replReplDependentList == null) this.replReplDependentList= new HashSet(); if (! this.replReplDependentList.add(depSymbol)) return; depSymbol.originalReplNumberDependencies++; } // // Mark symbol as COMMON // protected void markSymbolCommon(DVStatements.Statement owner) { if (this.owner != null) { owner.putError("Symbol [" + this.name + "] defined as LOCAL - cannot be redefined as COMMON"); return; } if (this.isCommon) { owner.putError("Symbol [" + this.name + "] already defined as COMMON - statement ignored"); return; } if (this.isExternal){ owner.putError("Symbol [" + this.name + "] has already been defined as EXTERNAL - cannot be redefined as COMMON"); return; } this.isCommon= true; } // // Set common symbol parameters // protected void setSymbolCommon(BigInteger size, BigInteger align, String extName) { this.commonSize= size; this.CommonAlign= align; this.externalName= extName; } // // Mark symbol exported // protected void markSymbolExported(DVStatements.Statement owner) { if (this.isExported) { owner.putError("Symbol [" + this.name + "] has already been EXPORTED - statement ignored"); return; } this.isExported= true; } // // Export symbol // protected void exportSymbol(DVStatements.Statement owner, BigInteger bind, BigInteger type, BigInteger size, String exportName) { if (this.owner != null && this.owner.ownerSection != null && this.owner.ownerSection.type == DVSections.SectionType.MMAP) { owner.putError("Symbol [" + this.name + "] is defined in an MMAP and cannot be exported"); return; } if (! DVSymbols.this.statements.abi.verifySymbolType(type)) { owner.putError("External symbol type [0x" + type.toString(16) + "] is invalid" ); return; } this.exportType= type; if (! DVSymbols.this.statements.abi.verifyExportedSymbolBind(bind)) { owner.putError("External symbol bind [0x" + bind.toString(16) + "] is invalid" ); return; } this.exportBind= bind; if (size == null) size= this.length.multiply(this.resultRepl.intConstant); this.exportSize= size; if (exportName == null) this.exportName= this.name; else this.exportName= exportName; } // // Set a symbol external // protected void markSymbolExternal(DVStatements.Statement owner) { if (this.owner != null) { owner.putError("Symbol [" + this.name + "] is LOCAL - cannot be redefined as EXTERNAL"); return; } if (this.isCommon){ owner.putError("Symbol [" + this.name + "] has already been defined as COMMON - cannot be redefined as EXTERNAL"); return; } if (this.isExternal){ owner.putError("Symbol [" + this.name + "] has already been defined as EXTERNAL - statement ignored"); return; } this.isExternal= true; } // // Set external symbol external name // protected void setSymbolExternal(BigInteger bind, String externalName) { if (! DVSymbols.this.statements.abi.verifyExternalSymbolBind(bind)) { owner.putError("External symbol bind [0x" + bind.toString(16) + "] is invalid" ); return; } this.externalBind= bind; if (externalName == null) this.externalName= this.name; else this.externalName= externalName; } // // Set symbol locally exported // void setLocalExport() { this.isLocalExported= true; this.exportName= this.name; this.exportSize= this.length; } // // Add a reference to a symbol // protected void addReference(DVStatements.Statement statement) { this.referenceMap.put(statement.lines[0].lineNo, statement); } // // Getter methods // public String getName() { return this.name; } public DVSections.Section getSection() { return this.owner.ownerSection; } public BigInteger getValue() { return this.resultValue.intConstant; } // // Class fields // protected Token token; protected String name; protected DVStatements.Statement owner= null; protected BigInteger index= null; protected BigInteger align= null; protected DVExpression valueExpression= null; protected DVExpression.ExprToken resultValue= null; protected HashSet valueValueDependentList= null; protected HashSet valueReplDependentList= null; protected int valueNumberDependencies= 0; protected DVExpression replExpression= null; protected DVExpression.ExprToken resultRepl= null; protected HashSet replReplDependentList= null; protected HashSet replValueDependentList= null; protected int replNumberDependencies= 0; protected BigInteger length= null; protected int originalValueNumberDependencies; protected int originalReplNumberDependencies; protected BigInteger prevLength= null; protected boolean isExternal= false; protected boolean isCommon= false; protected String externalName= null; protected BigInteger externalBind= null; protected BigInteger commonSize= null; protected BigInteger CommonAlign= null; protected boolean isExported= false; protected boolean isLocalExported= false; protected String exportName= null; protected BigInteger exportBind= null; protected BigInteger exportType= null; protected BigInteger exportSize= null; protected TreeMap referenceMap= new TreeMap (); } // // Get a base symbol instance if it exists otherwise create one and return it // protected Symbol getSymbol(String name) { Symbol symbol= DVSymbols.this.symbolMap.get(name.toUpperCase()); if (symbol == null) symbol= new Symbol(null, name); return symbol; } // // Get a symbol instance without statement or create a new one and set statement // protected Symbol getSymbol(Token parseToken, DVStatements.Statement owner) { if (parseToken == null) return getHiddenSymbol(owner); Symbol symbol= DVSymbols.this.symbolMap.get(parseToken.image.toUpperCase()); if (symbol == null) { symbol= new Symbol(parseToken); symbol.owner= owner; return symbol; } if (symbol.owner != null) return null; if (symbol.isExternal) { owner.putError("Symbol [" + symbol.name + "] has been defined as External"); return null; } if (symbol.isCommon) { owner.putError("Symbol [" + symbol.name + "] has been defined as Common"); return null; } if (symbol.isExported && owner.ownerSection != null && owner.ownerSection.type == DVSections.SectionType.MMAP) { owner.putError("Symbol [" + symbol.name + "] is defined in an MMAP and cannot be exported"); return null; } symbol.owner= owner; if (symbol.token == null) symbol.token= parseToken; return symbol; } // // Compute all dependencies // protected void setDependencies() { // // Reset all symbol values // for (Symbol s : this.symbolMap.values()) { s.valueNumberDependencies= 0; s.replNumberDependencies= 0; s.externalName= null; } // // Scan all symbols and identify those with zero dependencies (value and/or repl) // for (Symbol s : this.symbolMap.values()) { // // Check if external or common // if (s.isExternal || s.isCommon) continue; // // Check if undefined // if (s.owner == null) continue; // // Set dependencies // s.valueExpression.setValueDependencies(s); s.replExpression.setReplDependencies(s); s.externalName= null; s.exportName= null; s.exportType= null; s.exportSize= null; s.isLocalExported= false; } for (Symbol s : this.symbolMap.values()) { if (s.valueValueDependentList != null) { this.statements.logTrace("Value on Value dependent list - Symbol: " + s.name); for (Symbol ds : s.valueValueDependentList) this.statements.logTrace(" Dependent Symbol: " + ds.name); } if (s.valueReplDependentList != null) { this.statements.logTrace("Value on Repl dependent list - Symbol: " + s.name); for (Symbol ds : s.valueReplDependentList) this.statements.logTrace(" Dependent Symbol: " + ds.name); } if (s.replValueDependentList != null) { this.statements.logTrace("Repl on Value dependent list - Symbol: " + s.name); for (Symbol ds : s.replValueDependentList) this.statements.logTrace(" Dependent Symbol: " + ds.name); } if (s.replReplDependentList != null) { this.statements.logTrace("Repl on Repl dependent list - Symbol: " + s.name); for (Symbol ds : s.replValueDependentList) this.statements.logTrace(" Dependent Symbol: " + ds.name); } } } // // Evaluate all symbols // protected boolean evaluate() { LinkedList toBeSolvedList= new LinkedList(); int noUnresolved= 0; // // Scan all symbols and identify those with zero dependencies (value and/or repl) // for (Symbol s : this.symbolMap.values()) { // // Handle orphan symbols // if (s.owner == null) { if (s.isExternal || s.isCommon) continue; for(Map.Entry entry : s.referenceMap.entrySet()) entry.getValue().putError("Symbol [%s] has not been defined and is unresolved", s.name); noUnresolved++; continue; } // // Check if dependencies // s.resultValue= null; s.valueNumberDependencies= s.originalValueNumberDependencies; s.resultRepl= null; s.replNumberDependencies= s.originalReplNumberDependencies; boolean toBeSolvedFlag= false; if (s.valueNumberDependencies == 0) toBeSolvedFlag= true; else noUnresolved++; if (s.replNumberDependencies == 0) toBeSolvedFlag= true; else noUnresolved++; if (toBeSolvedFlag) toBeSolvedList.addLast(s); this.statements.logTrace(String.format("*** Symbol %16s is resdy to be solved: %b", s.name, toBeSolvedFlag)); s.prevLength= s.length; } // // Start loop to resolve all symbols // while (! toBeSolvedList.isEmpty()) { Symbol s= toBeSolvedList.removeFirst(); if (s.resultValue == null && s.valueNumberDependencies <= 0) { this.statements.logTrace("--- Resolving value: " + s.name); s.resultValue= s.valueExpression.evaluate(false); // // Check all Value dependent symbols Value // if (s.valueValueDependentList != null) for (Symbol ds : s.valueValueDependentList) { ds.valueNumberDependencies--; if (ds.valueNumberDependencies <= 0) { noUnresolved--; toBeSolvedList.addLast(ds); } } // // Check all Value dependent symbols Repl // if (s.valueReplDependentList != null) for (Symbol ds : s.valueReplDependentList) { ds.replNumberDependencies--; if (ds.replNumberDependencies <= 0) { noUnresolved--; toBeSolvedList.addLast(ds); } } } if (s.resultRepl == null && s.replNumberDependencies <= 0) { this.statements.logTrace("--- Resolving repl : " + s.name); s.resultRepl= s.replExpression.evaluate(true); if (! DVExpression.INT_VALUE.contains(s.resultRepl.type)) s.owner.putError(String.format( "Replication for symbol [%s] resolves to [%s} - must resolve to either ABSOLUTE or DISPLACEMEN", s.name, s.resultRepl.type.name())); else { // // Check all Repl dependent symbols Value // if (s.replValueDependentList != null) for (Symbol ds : s.replValueDependentList) { ds.valueNumberDependencies--; if (ds.valueNumberDependencies <= 0) { noUnresolved--; toBeSolvedList.addLast(ds); } } // // Check all Repl dependent symbols Repl // if (s.replReplDependentList != null) for (Symbol ds : s.replReplDependentList) { ds.replNumberDependencies--; if (ds.replNumberDependencies <= 0) { noUnresolved--; toBeSolvedList.addLast(ds); } } } } } // // Check if any symbol is unresolved // this.statements.logTrace("--- List of symbols"); for (Symbol s : this.symbolMap.values()) { if (s.isExternal || s.isCommon) continue; if (s.resultValue == null) { this.statements.logTrace("--- Unresolved value: " + s.name); if (s.valueValueDependentList != null) for (Symbol ds : s.valueValueDependentList) if (s.owner == null) ds.owner.putError("Symbol [" + ds.name + "->Value] unresolved due to undefined symbol [" + s.name + "]"); else ds.owner.putError("Symbol [" + ds.name + "->Value] unresolved due to unresolved symbol [" + s.name + "->Value]"); if (s.valueReplDependentList != null) for (Symbol ds : s.valueReplDependentList) if (s.owner == null) ds.owner.putError("Symbol [" + ds.name + "->Repl] unresolved due to undefined symbol [" + s.name + "]"); else ds.owner.putError("Symbol [" + ds.name + "->Repl] unresolved due to unresolved symbol [" + s.name + "->Value]"); } else this.statements.logTrace("--- Resolved value: " + s.name + " Value: " + s.resultValue.getValue()); if (s.resultRepl == null) { this.statements.logTrace("--- Unresolved repl : " + s.name); if (s.replValueDependentList != null) for (Symbol ds : s.replValueDependentList) if (s.owner == null) ds.owner.putError("Symbol [" + ds.name + "->Value] unresolved due to undefined symbol [" + s.name + "]"); else ds.owner.putError("Symbol [" + ds.name + "->Value] unresolved due to unresolved symbol [" + s.name + "->Repl]"); if (s.replReplDependentList != null) for (Symbol ds : s.replReplDependentList) if (s.owner == null) ds.owner.putError("Symbol [" + ds.name + "->Repl] unresolved due to undefined symbol [" + s.name + "]"); else ds.owner.putError("Symbol [" + ds.name + "->Repl] unresolved due to unresolved symbol [" + s.name + "->Repl]"); } else this.statements.logTrace("--- Resolved repl : " + s.name + " Repl: " + s.resultRepl.getValue()); } return (noUnresolved == 0); } // // Get parse token // static protected Token getParseToken(String image) { Token parseToken= new Token(-1, image); parseToken.beginColumn= -1; parseToken.beginLine= -1; return parseToken; } // // Get hidden symbol // protected Symbol getHiddenSymbol(DVStatements.Statement statement) { Symbol symbol= new Symbol(getParseToken("#" + statement.lines[0].lineNo.trim())); symbol.owner= statement; return symbol; } // // Create symbol section // protected void fillElfSymbolSection(DVSectionTable.SymbolSection symbolSection, String inputFileName) { if (inputFileName != null) { symbolSection.addSymbol(inputFileName, BigInteger.ZERO, BigInteger.ZERO, DVUtil.symbolBindLocal, DVUtil.symbolTypeFile, DVUtil.specialSectionIndexAbsolute); } for (Map.Entry e : this.symbolMap.entrySet()) { Symbol s= e.getValue(); if (! s.isLocalExported) continue; BigInteger sectionIndex; if (DVExpression.INT_VALUE.contains(s.resultValue.type)) sectionIndex= DVUtil.specialSectionIndexAbsolute; else sectionIndex= s.owner.ownerSection.elfSection.getIndex(); s.index= symbolSection.addSymbol(s.exportName, s.resultValue.intConstant, s.exportSize == null ? s.length : s.exportSize, DVUtil.symbolBindLocal, DVUtil.symbolTypeObject, sectionIndex); } symbolSection.markLocal(); for (Map.Entry e : this.symbolMap.entrySet()) { Symbol s= e.getValue(); String name= null; BigInteger value= BigInteger.ZERO; BigInteger size= BigInteger.ZERO; BigInteger bind= null; BigInteger type= null; BigInteger sectionIndex= null; if (s.isExternal || s.isCommon) { name= s.externalName; bind= s.externalBind; type= DVUtil.symbolTypeNoType; if (s.isExternal) sectionIndex= DVUtil.specialSectionIndexUndefined; else sectionIndex= DVUtil.specialSectionIndexCommon; } else if (s.isExported) { name= s.exportName; value= s.resultValue.intConstant; size= s.exportSize; bind= s.exportBind; type= s.exportType; if (DVExpression.INT_VALUE.contains(s.resultValue.type)) sectionIndex= DVUtil.specialSectionIndexAbsolute; else sectionIndex= s.owner.ownerSection.elfSection.getIndex(); } else continue; s.index= symbolSection.addSymbol(name, value, size, bind, type, sectionIndex); } } // // Class fields // protected final DVStatements statements; protected final TreeMap symbolMap= new TreeMap(); // // Symbol component // protected enum SymbolComponent { VALUE, LENGTH, REPL, SIZE } }