package parsing.C.Functions.builder;
import java.util.EmptyStackException;
import org.antlr.v4.runtime.ParserRuleContext;
import parsing.C.Shared.InitDeclContextWrapper;
import parsing.C.Shared.builders.ClassDefBuilder;
import parsing.C.Shared.builders.IdentifierDeclBuilder;
import antlr.C.FunctionParser.Additive_expressionContext;
import antlr.C.FunctionParser.And_expressionContext;
import antlr.C.FunctionParser.ArrayIndexingContext;
import antlr.C.FunctionParser.Assign_exprContext;
import antlr.C.FunctionParser.Bit_and_expressionContext;
import antlr.C.FunctionParser.Block_starterContext;
import antlr.C.FunctionParser.BreakStatementContext;
import antlr.C.FunctionParser.Cast_expressionContext;
import antlr.C.FunctionParser.Cast_targetContext;
import antlr.C.FunctionParser.Closing_curlyContext;
import antlr.C.FunctionParser.ConditionContext;
import antlr.C.FunctionParser.Conditional_expressionContext;
import antlr.C.FunctionParser.ContinueStatementContext;
import antlr.C.FunctionParser.DeclByClassContext;
import antlr.C.FunctionParser.Do_statementContext;
import antlr.C.FunctionParser.Else_statementContext;
import antlr.C.FunctionParser.Equality_expressionContext;
import antlr.C.FunctionParser.Exclusive_or_expressionContext;
import antlr.C.FunctionParser.ExprContext;
import antlr.C.FunctionParser.Expr_statementContext;
import antlr.C.FunctionParser.For_init_statementContext;
import antlr.C.FunctionParser.For_statementContext;
import antlr.C.FunctionParser.FuncCallContext;
import antlr.C.FunctionParser.Function_argumentContext;
import antlr.C.FunctionParser.Function_argument_listContext;
import antlr.C.FunctionParser.GotoStatementContext;
import antlr.C.FunctionParser.IdentifierContext;
import antlr.C.FunctionParser.If_statementContext;
import antlr.C.FunctionParser.IncDecOpContext;
import antlr.C.FunctionParser.Inc_decContext;
import antlr.C.FunctionParser.Inclusive_or_expressionContext;
import antlr.C.FunctionParser.InitDeclSimpleContext;
import antlr.C.FunctionParser.InitDeclWithAssignContext;
import antlr.C.FunctionParser.InitDeclWithCallContext;
import antlr.C.FunctionParser.Initializer_listContext;
import antlr.C.FunctionParser.LabelContext;
import antlr.C.FunctionParser.MemberAccessContext;
import antlr.C.FunctionParser.Multiplicative_expressionContext;
import antlr.C.FunctionParser.Opening_curlyContext;
import antlr.C.FunctionParser.Or_expressionContext;
import antlr.C.FunctionParser.Primary_expressionContext;
import antlr.C.FunctionParser.PtrMemberAccessContext;
import antlr.C.FunctionParser.Relational_expressionContext;
import antlr.C.FunctionParser.ReturnStatementContext;
import antlr.C.FunctionParser.Shift_expressionContext;
import antlr.C.FunctionParser.SizeofContext;
import antlr.C.FunctionParser.Sizeof_expressionContext;
import antlr.C.FunctionParser.Sizeof_operand2Context;
import antlr.C.FunctionParser.Sizeof_operandContext;
import antlr.C.FunctionParser.StatementContext;
import antlr.C.FunctionParser.StatementsContext;
import antlr.C.FunctionParser.Switch_statementContext;
import antlr.C.FunctionParser.Type_nameContext;
import antlr.C.FunctionParser.Unary_expressionContext;
import antlr.C.FunctionParser.Unary_op_and_cast_exprContext;
import antlr.C.FunctionParser.Unary_operatorContext;
import antlr.C.FunctionParser.While_statementContext;
import ast.ASTNode;
import ast.ASTNodeBuilder;
import ast.declarations.ClassDefStatement;
import ast.declarations.IdentifierDecl;
import ast.expressions.AdditiveExpression;
import ast.expressions.AndExpression;
import ast.expressions.Argument;
import ast.expressions.ArgumentList;
import ast.expressions.ArrayIndexing;
import ast.expressions.AssignmentExpr;
import ast.expressions.BitAndExpression;
import ast.expressions.CallExpression;
import ast.expressions.Callee;
import ast.expressions.CastExpression;
import ast.expressions.CastTarget;
import ast.expressions.ConditionalExpression;
import ast.expressions.EqualityExpression;
import ast.expressions.ExclusiveOrExpression;
import ast.expressions.Expression;
import ast.expressions.Identifier;
import ast.expressions.IncDec;
import ast.expressions.IncDecOp;
import ast.expressions.InclusiveOrExpression;
import ast.expressions.InitializerList;
import ast.expressions.MemberAccess;
import ast.expressions.MultiplicativeExpression;
import ast.expressions.OrExpression;
import ast.expressions.PrimaryExpression;
import ast.expressions.PtrMemberAccess;
import ast.expressions.RelationalExpression;
import ast.expressions.ShiftExpression;
import ast.expressions.Sizeof;
import ast.expressions.SizeofExpr;
import ast.expressions.SizeofOperand;
import ast.expressions.UnaryExpression;
import ast.expressions.UnaryOp;
import ast.expressions.UnaryOperator;
import ast.statements.BlockCloser;
import ast.statements.BlockStarter;
import ast.statements.BreakStatement;
import ast.statements.CompoundStatement;
import ast.statements.Condition;
import ast.statements.ContinueStatement;
import ast.statements.DoStatement;
import ast.statements.ElseStatement;
import ast.statements.ExpressionStatement;
import ast.statements.ForInit;
import ast.statements.ForStatement;
import ast.statements.GotoStatement;
import ast.statements.IdentifierDeclStatement;
import ast.statements.IfStatement;
import ast.statements.Label;
import ast.statements.ReturnStatement;
import ast.statements.Statement;
import ast.statements.SwitchStatement;
import ast.statements.WhileStatement;
/**
* The FunctionContentBuilder is invoked while walking the parse tree to create
* ASTs for the contents of functions, i.e., the first-level compound statements
* of functions.
*
* Since the fuzzy parser avoids using nested grammar rules as these rules often
* require reading all tokens of a file only to realize that the default rule
* must be taken, the most difficult task this code fulfills is to produce a
* correctly nested AST.
*/
public class FunctionContentBuilder extends ASTNodeBuilder
{
ContentBuilderStack stack = new ContentBuilderStack();
NestingReconstructor nesting = new NestingReconstructor(stack);
// exitStatements is called when the entire
// function-content has been walked
public void exitStatements(StatementsContext ctx)
{
if (stack.size() != 1)
throw new RuntimeException("Broken stack while parsing");
}
// For all statements, begin by pushing a Statement Object
// onto the stack.
public void enterStatement(StatementContext ctx)
{
ASTNode statementItem = new Statement();
statementItem.initializeFromContext(ctx);
stack.push(statementItem);
}
// Mapping of grammar-rules to CodeItems.
public void enterOpeningCurly(Opening_curlyContext ctx)
{
replaceTopOfStack(new CompoundStatement());
}
public void enterClosingCurly(Closing_curlyContext ctx)
{
replaceTopOfStack(new BlockCloser());
}
public void enterBlockStarter(Block_starterContext ctx)
{
replaceTopOfStack(new BlockStarter());
}
public void enterExprStatement(Expr_statementContext ctx)
{
replaceTopOfStack(new ExpressionStatement());
}
public void enterIf(If_statementContext ctx)
{
replaceTopOfStack(new IfStatement());
}
public void enterFor(For_statementContext ctx)
{
replaceTopOfStack(new ForStatement());
}
public void enterWhile(While_statementContext ctx)
{
replaceTopOfStack(new WhileStatement());
}
public void enterDo(Do_statementContext ctx)
{
replaceTopOfStack(new DoStatement());
}
public void enterElse(Else_statementContext ctx)
{
replaceTopOfStack(new ElseStatement());
}
public void exitStatement(StatementContext ctx)
{
if (stack.size() == 0)
throw new RuntimeException();
ASTNode itemToRemove = stack.peek();
itemToRemove.initializeFromContext(ctx);
if (itemToRemove instanceof BlockCloser)
{
closeCompoundStatement();
return;
}
// We keep Block-starters and compound items
// on the stack. They are removed by following
// statements.
if (itemToRemove instanceof BlockStarter
|| itemToRemove instanceof CompoundStatement)
return;
nesting.consolidate();
}
private void closeCompoundStatement()
{
stack.pop(); // remove 'CloseBlock'
CompoundStatement compoundItem = (CompoundStatement) stack.pop();
nesting.consolidateBlockStarters(compoundItem);
}
// Expression handling
public void enterExpression(ExprContext ctx)
{
Expression expression = new Expression();
stack.push(expression);
}
public void exitExpression(ExprContext ctx)
{
nesting.consolidateSubExpression(ctx);
}
public void enterAssignment(Assign_exprContext ctx)
{
AssignmentExpr expr = new AssignmentExpr();
stack.push(expr);
}
public void exitAssignment(Assign_exprContext ctx)
{
nesting.consolidateSubExpression(ctx);
}
public void enterConditionalExpr(Conditional_expressionContext ctx)
{
ConditionalExpression expr = new ConditionalExpression();
stack.push(expr);
}
public void exitConditionalExpr(Conditional_expressionContext ctx)
{
introduceCndNodeForCndExpr();
nesting.consolidateSubExpression(ctx);
}
public void enterOrExpression(Or_expressionContext ctx)
{
OrExpression expr = new OrExpression();
stack.push(expr);
}
public void exitrOrExpression(Or_expressionContext ctx)
{
nesting.consolidateSubExpression(ctx);
}
public void enterAndExpression(And_expressionContext ctx)
{
AndExpression expr = new AndExpression();
stack.push(expr);
}
public void exitAndExpression(And_expressionContext ctx)
{
nesting.consolidateSubExpression(ctx);
}
public void enterInclusiveOrExpression(Inclusive_or_expressionContext ctx)
{
InclusiveOrExpression expr = new InclusiveOrExpression();
stack.push(expr);
}
public void exitInclusiveOrExpression(Inclusive_or_expressionContext ctx)
{
nesting.consolidateSubExpression(ctx);
}
public void enterExclusiveOrExpression(Exclusive_or_expressionContext ctx)
{
ExclusiveOrExpression expr = new ExclusiveOrExpression();
stack.push(expr);
}
public void exitExclusiveOrExpression(Exclusive_or_expressionContext ctx)
{
nesting.consolidateSubExpression(ctx);
}
public void enterBitAndExpression(Bit_and_expressionContext ctx)
{
BitAndExpression expr = new BitAndExpression();
stack.push(expr);
}
public void enterEqualityExpression(Equality_expressionContext ctx)
{
EqualityExpression expr = new EqualityExpression();
stack.push(expr);
}
public void exitEqualityExpression(Equality_expressionContext ctx)
{
nesting.consolidateSubExpression(ctx);
}
public void exitBitAndExpression(Bit_and_expressionContext ctx)
{
nesting.consolidateSubExpression(ctx);
}
public void enterRelationalExpression(Relational_expressionContext ctx)
{
RelationalExpression expr = new RelationalExpression();
stack.push(expr);
}
public void exitRelationalExpression(Relational_expressionContext ctx)
{
nesting.consolidateSubExpression(ctx);
}
public void enterShiftExpression(Shift_expressionContext ctx)
{
ShiftExpression expr = new ShiftExpression();
stack.push(expr);
}
public void exitShiftExpression(Shift_expressionContext ctx)
{
nesting.consolidateSubExpression(ctx);
}
public void enterAdditiveExpression(Additive_expressionContext ctx)
{
AdditiveExpression expr = new AdditiveExpression();
stack.push(expr);
}
public void exitAdditiveExpression(Additive_expressionContext ctx)
{
nesting.consolidateSubExpression(ctx);
}
public void enterMultiplicativeExpression(
Multiplicative_expressionContext ctx)
{
MultiplicativeExpression expr = new MultiplicativeExpression();
stack.push(expr);
}
public void exitMultiplicativeExpression(
Multiplicative_expressionContext ctx)
{
nesting.consolidateSubExpression(ctx);
}
public void enterCastExpression(Cast_expressionContext ctx)
{
CastExpression expr = new CastExpression();
stack.push(expr);
}
public void exitCastExpression(Cast_expressionContext ctx)
{
nesting.consolidateSubExpression(ctx);
}
public void enterCast_target(Cast_targetContext ctx)
{
CastTarget expr = new CastTarget();
stack.push(expr);
}
public void exitCast_target(Cast_targetContext ctx)
{
nesting.consolidateSubExpression(ctx);
}
public void enterFuncCall(FuncCallContext ctx)
{
CallExpression expr = new CallExpression();
stack.push(expr);
}
public void exitFuncCall(FuncCallContext ctx)
{
introduceCalleeNode();
nesting.consolidateSubExpression(ctx);
}
public void enterSizeof(SizeofContext ctx)
{
Sizeof expr = new Sizeof();
stack.push(expr);
}
public void exitSizeof(SizeofContext ctx)
{
nesting.consolidateSubExpression(ctx);
}
private void introduceCalleeNode()
{
CallExpression expr;
try
{
expr = (CallExpression) stack.peek();
}
catch (EmptyStackException ex)
{
return;
}
ASTNode child = expr.getChild(0);
if (child == null)
return;
Callee callee = new Callee();
callee.addChild(child);
expr.replaceFirstChild(callee);
}
private void introduceCndNodeForCndExpr()
{
ConditionalExpression expr;
try
{
expr = (ConditionalExpression) stack.peek();
}
catch (EmptyStackException ex)
{
return;
}
ASTNode child = expr.getChild(0);
if (child == null)
return;
Condition cnd = new Condition();
cnd.addChild(child);
expr.replaceFirstChild(cnd);
}
public void enterArgumentList(Function_argument_listContext ctx)
{
ArgumentList expr = new ArgumentList();
stack.push(expr);
}
public void exitArgumentList(Function_argument_listContext ctx)
{
nesting.consolidateSubExpression(ctx);
}
public void enterCondition(ConditionContext ctx)
{
Condition expr = new Condition();
stack.push(expr);
}
public void exitCondition(ConditionContext ctx)
{
Condition cond = (Condition) stack.pop();
cond.initializeFromContext(ctx);
nesting.addItemToParent(cond);
}
public void enterDeclByClass(DeclByClassContext ctx)
{
ClassDefBuilder classDefBuilder = new ClassDefBuilder();
classDefBuilder.createNew(ctx);
classDefBuilder.setName(ctx.class_def().class_name());
replaceTopOfStack(classDefBuilder.getItem());
}
public void exitDeclByClass()
{
nesting.consolidate();
}
public void enterInitDeclSimple(InitDeclSimpleContext ctx)
{
ASTNode identifierDecl = buildDeclarator(ctx);
stack.push(identifierDecl);
}
public void exitInitDeclSimple()
{
IdentifierDecl identifierDecl = (IdentifierDecl) stack.pop();
ASTNode stmt = stack.peek();
stmt.addChild(identifierDecl);
}
public void enterInitDeclWithAssign(InitDeclWithAssignContext ctx)
{
IdentifierDecl identifierDecl = buildDeclarator(ctx);
stack.push(identifierDecl);
}
public void exitInitDeclWithAssign(InitDeclWithAssignContext ctx)
{
IdentifierDecl identifierDecl = (IdentifierDecl) stack.pop();
Expression lastChild = (Expression) identifierDecl.popLastChild();
AssignmentExpr assign = new AssignmentExpr();
assign.initializeFromContext(ctx);
// watchout here, we're not making a copy.
// This is also a bit of a hack. As we go up,
// we introduce an artificial assignment-node.
assign.addChild(identifierDecl.getName());
assign.addChild(lastChild);
identifierDecl.addChild(assign);
ASTNode stmt = stack.peek();
stmt.addChild(identifierDecl);
}
public void enterInitDeclWithCall(InitDeclWithCallContext ctx)
{
ASTNode identifierDecl = buildDeclarator(ctx);
stack.push(identifierDecl);
}
public void exitInitDeclWithCall()
{
IdentifierDecl identifierDecl = (IdentifierDecl) stack.pop();
ASTNode stmt = stack.peek();
stmt.addChild(identifierDecl);
}
private IdentifierDecl buildDeclarator(ParserRuleContext ctx)
{
InitDeclContextWrapper wrappedContext = new InitDeclContextWrapper(ctx);
ParserRuleContext typeName = getTypeFromParent();
IdentifierDeclBuilder declBuilder = new IdentifierDeclBuilder();
declBuilder.createNew(ctx);
declBuilder.setType(wrappedContext, typeName);
IdentifierDecl identifierDecl = (IdentifierDecl) declBuilder.getItem();
return identifierDecl;
}
private ParserRuleContext getTypeFromParent()
{
ASTNode parentItem = stack.peek();
ParserRuleContext typeName;
if (parentItem instanceof IdentifierDeclStatement)
typeName = ((IdentifierDeclStatement) parentItem)
.getTypeNameContext();
else if (parentItem instanceof ClassDefStatement)
typeName = ((ClassDefStatement) parentItem).getName()
.getParseTreeNodeContext();
else
throw new RuntimeException(
"No matching declaration statement/class definiton for init declarator");
return typeName;
}
public void enterIncDec(Inc_decContext ctx)
{
IncDec expr = new IncDec();
stack.push(expr);
}
public void exitIncDec(Inc_decContext ctx)
{
nesting.consolidateSubExpression(ctx);
}
public void enterArrayIndexing(ArrayIndexingContext ctx)
{
ArrayIndexing expr = new ArrayIndexing();
stack.push(expr);
}
public void exitArrayIndexing(ArrayIndexingContext ctx)
{
nesting.consolidateSubExpression(ctx);
}
public void enterMemberAccess(MemberAccessContext ctx)
{
MemberAccess expr = new MemberAccess();
stack.push(expr);
}
public void exitMemberAccess(MemberAccessContext ctx)
{
nesting.consolidateSubExpression(ctx);
}
public void enterIncDecOp(IncDecOpContext ctx)
{
IncDecOp expr = new IncDecOp();
stack.push(expr);
}
public void exitIncDecOp(IncDecOpContext ctx)
{
nesting.consolidateSubExpression(ctx);
}
public void enterPrimary(Primary_expressionContext ctx)
{
PrimaryExpression expr = new PrimaryExpression();
stack.push(expr);
}
public void exitPrimary(Primary_expressionContext ctx)
{
nesting.consolidateSubExpression(ctx);
}
public void enterUnaryExpression(Unary_expressionContext ctx)
{
UnaryExpression expr = new UnaryExpression();
stack.push(expr);
}
public void exitUnaryExpression(Unary_expressionContext ctx)
{
nesting.consolidateSubExpression(ctx);
}
public void enterIdentifier(IdentifierContext ctx)
{
Identifier expr = new Identifier();
stack.push(expr);
}
public void exitIdentifier(IdentifierContext ctx)
{
nesting.consolidateSubExpression(ctx);
}
public void enterArgument(Function_argumentContext ctx)
{
Argument expr = new Argument();
stack.push(expr);
}
public void exitArgument(Function_argumentContext ctx)
{
nesting.consolidateSubExpression(ctx);
}
public void enterInitializerList(Initializer_listContext ctx)
{
InitializerList expr = new InitializerList();
stack.push(expr);
}
public void exitInitializerList(Initializer_listContext ctx)
{
nesting.consolidateSubExpression(ctx);
}
public void enterPtrMemberAccess(PtrMemberAccessContext ctx)
{
PtrMemberAccess expr = new PtrMemberAccess();
stack.push(expr);
}
public void exitPtrMemberAccess(PtrMemberAccessContext ctx)
{
nesting.consolidateSubExpression(ctx);
}
public void enterInitFor(For_init_statementContext ctx)
{
ForInit expr = new ForInit();
stack.push(expr);
}
public void exitInitFor(For_init_statementContext ctx)
{
ASTNode node = stack.pop();
node.initializeFromContext(ctx);
ForStatement forStatement = (ForStatement) stack.peek();
forStatement.addChild(node);
}
public void enterSwitchStatement(Switch_statementContext ctx)
{
replaceTopOfStack(new SwitchStatement());
}
public void enterLabel(LabelContext ctx)
{
replaceTopOfStack(new Label());
}
public void enterReturnStatement(ReturnStatementContext ctx)
{
replaceTopOfStack(new ReturnStatement());
}
public void enterBreakStatement(BreakStatementContext ctx)
{
replaceTopOfStack(new BreakStatement());
}
public void enterContinueStatement(ContinueStatementContext ctx)
{
replaceTopOfStack(new ContinueStatement());
}
public void enterGotoStatement(GotoStatementContext ctx)
{
replaceTopOfStack(new GotoStatement());
}
@Override
public void createNew(ParserRuleContext ctx)
{
item = new CompoundStatement();
CompoundStatement rootItem = (CompoundStatement) item;
item.initializeFromContext(ctx);
stack.push(rootItem);
}
public void addLocalDecl(IdentifierDecl decl)
{
IdentifierDeclStatement declStmt = (IdentifierDeclStatement) stack
.peek();
declStmt.addChild(decl);
}
public void enterDeclByType(ParserRuleContext ctx,
Type_nameContext type_nameContext)
{
IdentifierDeclStatement declStmt = new IdentifierDeclStatement();
declStmt.initializeFromContext(ctx);
declStmt.setTypeNameContext(type_nameContext);
if (stack.peek() instanceof Statement)
replaceTopOfStack(declStmt);
else
stack.push(declStmt);
}
public void exitDeclByType()
{
nesting.consolidate();
}
protected void replaceTopOfStack(ASTNode item)
{
stack.pop();
stack.push(item);
}
public void enterSizeofExpr(Sizeof_expressionContext ctx)
{
SizeofExpr expr = new SizeofExpr();
stack.push(expr);
}
public void exitSizeofExpr(Sizeof_expressionContext ctx)
{
nesting.consolidateSubExpression(ctx);
}
public void enterSizeofOperand2(Sizeof_operand2Context ctx)
{
SizeofOperand expr = new SizeofOperand();
stack.push(expr);
}
public void enterSizeofOperand(Sizeof_operandContext ctx)
{
SizeofOperand expr = new SizeofOperand();
stack.push(expr);
}
public void exitSizeofOperand2(Sizeof_operand2Context ctx)
{
nesting.consolidateSubExpression(ctx);
}
public void exitSizeofOperand(Sizeof_operandContext ctx)
{
nesting.consolidateSubExpression(ctx);
}
public void enterUnaryOpAndCastExpr(Unary_op_and_cast_exprContext ctx)
{
UnaryOp expr = new UnaryOp();
stack.push(expr);
}
public void exitUnaryOpAndCastExpr(Unary_op_and_cast_exprContext ctx)
{
nesting.consolidateSubExpression(ctx);
}
public void enterUnaryOperator(Unary_operatorContext ctx)
{
UnaryOperator expr = new UnaryOperator();
stack.push(expr);
}
public void exitUnaryOperator(Unary_operatorContext ctx)
{
nesting.consolidateSubExpression(ctx);
}
}