in compiler-jburg-types/src/main/java/jburg/burg/JBurgGenerator.java [354:657]
public JBurgGenerator(AST root, Logger log) throws Exception
{
this.logger = log;
// Walk over the children of the root, each of which
// is a self-contained syntactical construct, and
// find an appropriate action for each.
for (AST currentNode = root; currentNode != null;
currentNode = currentNode.getNextSibling())
{
switch (currentNode.getType())
{
case COST_FUNCTION:
this.costFunctions.add(currentNode);
break;
case HEADER_DECLARATION:
if ( null == this.headerBlock )
{
this.headerBlock = getCodeBlock(currentNode);
}
else
{
throw new IllegalArgumentException("The class header may only be specified once.");
}
break;
case INCLASS_DECLARATION:
{
this.inclassCode.add( stripBrackets(getCodeBlock(currentNode)) );
}
break;
case INODE_ADAPTER_DECLARATION:
if (this.iNodeAdapterClass == null)
{
this.iNodeAdapterClass = getIdentifierText(currentNode.getFirstChild());
}
else
{
throw new IllegalArgumentException("INodeAdapter may only be specified once.");
}
break;
case INODE_TYPE_DECLARATION:
if (this.iNodeClass == null)
{
this.iNodeClass = getIdentifierText(currentNode.getFirstChild());
}
else
{
throw new IllegalArgumentException("INodeType may only be specified once.");
}
break;
case LANGUAGE_DECLARATION:
if ( null == this.emitLanguageName )
{
this.emitLanguageName = currentNode.getFirstChild().getText();
}
else
{
throw new IllegalArgumentException("Language may only be specified once.");
}
break;
case IMPLEMENTS_INTERFACE_SPECIFICATION:
this.interfaceNames.addElement(getIdentifierText( currentNode.getFirstChild()) );
break;
case PACKAGE_SPECIFICATION:
if ( null == this.packageName )
{
this.packageName = getIdentifierText(currentNode.getFirstChild());
}
else
{
throw new IllegalArgumentException("package may only be specified once.");
}
break;
case PROPERTY_SPECIFICATION:
{
String propertyType = getIdentifierText(currentNode.getFirstChild());
String propertyName = currentNode.getFirstChild().getNextSibling().getText();
this.burmProperties.put(propertyName, propertyType);
}
break;
case RETURN_DECLARATION:
if (this.defaultReturnType == null)
this.defaultReturnType = getIdentifierText(currentNode.getFirstChild());
else
throw new IllegalArgumentException( "ReturnType may only be specified once.");
break;
case PATTERN_RULE:
addPatternRule(currentNode);
break;
case SIMPLE_TRANSFORMATION_RULE:
addSimpleTransformationRule(currentNode);
break;
case TRANSFORMATION_RULE:
addComplexTransformationRule(currentNode);
break;
case TYPED_RETURN_DECLARATION:
{
String stateName = currentNode.getFirstChild().getText();
String returnType = getIdentifierText(currentNode.getFirstChild()
.getNextSibling());
// Put the return declaration in the table, but only once per state.
Object typeCollision = this.returnTypeTable.put(stateName, returnType);
if ( null != typeCollision )
{
throw new IllegalArgumentException(
"A state may only specify one ReturnType."
);
}
}
break;
case PATTERN_DECLARATION:
{
String pattern_name = currentNode.getFirstChild().getText();
namedPatterns.addPattern(pattern_name, currentNode);
}
break;
case REDUCTION_DECLARATION:
{
String pattern_name = currentNode.getFirstChild().getNextSibling().getText();
namedPatterns.addReduction(pattern_name, currentNode);
}
break;
case DEFAULT_ERROR_HANDLER:
this.defaultErrorHandler = getCodeBlock(currentNode);
break;
case NODE_TYPE:
{
final String operatorID = currentNode.getFirstChild().getText();
assert !operatorID.isEmpty() : "Parser should never create empty operator!";
final String nodeType = currentNode.getFirstChild().getNextSibling().getText();
assert !nodeType.isEmpty() : "Parser should never create empty node type!";
if (this.opcodeNodeTypes.put(operatorID, nodeType) != null)
{
final String message = "Duplicate node type declaration for '"
+ operatorID
+ "'.";
throw new IllegalArgumentException(message);
}
break;
}
case OPCODE_TYPE:
this.opcodeType = currentNode.getFirstChild().getText();
break;
case MANIFEST_CONSTANT:
manifestConstants.put(currentNode.getFirstChild().getText(), Integer.parseInt(currentNode.getFirstChild().getNextSibling().getText()));
break;
default:
throw new IllegalArgumentException("Unknown specification AST type " +
String.valueOf(currentNode.getType()));
}
}
// Set the language emitter.
codeEmitter = JBurgEmitterFactory.getEmitter(emitLanguageName, getLogger());
if ( codeEmitter == null )
{
throw new IllegalStateException("Unknown language specified: \""+ emitLanguageName +"\"");
}
if ( iNodeClass != null )
{
if ( iNodeAdapterClass != null )
{
try
{
this.iNodeAdapter = (InodeAdapter)Class.forName(iNodeAdapterClass).newInstance();
}
catch ( Exception ex )
{
ex.printStackTrace();
throw new IllegalArgumentException ("Unable to instantiate i-node adapter " + iNodeAdapterClass );
}
}
else
{
this.iNodeAdapter = InodeAdapterFactory.getAdapter(iNodeClass);
}
codeEmitter.setINodeType(this.iNodeClass);
if ( this.iNodeAdapter != null )
{
logger.info("Using i-node adapter " + this.iNodeAdapter.getClass().getName() );
}
else
{
getLogger().warning("using default i-node adapter, no adapter matches " + iNodeClass );
this.iNodeAdapter = new jburg.burg.inode.DefaultAdapter();
}
// See if the adapter is also an InodeAdapter2 implementation.
this.adapter2 = (this.iNodeAdapter instanceof InodeAdapter2)? (InodeAdapter2)this.iNodeAdapter : null;
}
else
{
throw new IllegalStateException("You must specify the i-node type.");
}
codeEmitter.setInodeAdapter(this.iNodeAdapter);
// Default return type is the same as the INode class.
if (this.defaultReturnType == null)
{
this.defaultReturnType = this.iNodeClass;
}
// Mutate pattern/reduction decl pairs into pattern rules.
for ( NamedPattern np: namedPatterns.values() )
{
if ( np.pattern != null && np.reductions.size() > 0 )
{
AST named_pattern = np.pattern.getFirstChild().getNextSibling().getFirstChild();
for ( AST reduction: np.reductions )
{
// Splice the pattern into the reduction AST.
AST nt_state = reduction.getFirstChild();
AST pattern_name = nt_state.getNextSibling();
AST cost_decl = pattern_name.getNextSibling();
// Create a new holder for the pattern
// so the original AST isn't mutated.
AST pattern_holder = new antlr.CommonAST();
pattern_holder.setFirstChild(named_pattern);
nt_state.setNextSibling(pattern_holder);
pattern_holder.setNextSibling(cost_decl);
// Give the composite AST the appropriate type
// for its pattern.
reduction.setType(PATTERN_RULE);
addPatternRule(reduction);
}
}
else if ( np.pattern != null )
{
getLogger().warning("pattern " + np.patternName + " has no reduction - ignored.");
}
else if ( np.reductions.size() > 0 )
{
throw new IllegalStateException("Reduction " + np.patternName + " has no associated pattern.");
}
}
// Add target-specific logic to the simple transformations' rules.
for ( JBurgRule rule: this.simpleTransformationRules.values() )
{
String actionCode = String.format(
"%s%s",
codeEmitter.genReturnValue(
codeEmitter.genPopFromStack(reducedValuesName, getReturnType(rule.getGoalState()))
),
codeEmitter.genEndStmt()
);
JBurgReduceAction action = addAction(actionCode, rule.getGoalState());
action.setAntecedentState(rule.getAntecedentState());
rule.setReduceAction(action);
}
// Compute the closure sets.
computeClosureSets();
}