/** * {@inheritDoc} * * <p>Determine the result type of a unary operator. * * @param ctx The UnaryOpContext parse tree node * @return The result type of VOID if not valid. */ @Override public Type visitUnaryop(UnaryopContext ctx) { String op = ctx.op.getText(); Type rhsType = visit(ctx.expr()); if (rhsType instanceof PrimitiveType) { switch ((PrimitiveType) rhsType) { case REAL: if (op.equals("-") || op.equals("+")) { typeMap.put(ctx, REAL); return REAL; } error(ctx, op + " cannot be applied to REAL"); break; case INT: if (op.equals("-") || op.equals("+") || op.equals("~")) { typeMap.put(ctx, INT); return INT; } error(ctx, op + " cannot be applied to INT"); break; case BOOL: if (op.equals("\00ac")) { typeMap.put(ctx, BOOL); return BOOL; } error(ctx, op + " cannot be applied to BOOL"); break; default: error(ctx, op + " cannot be applied to " + rhsType); break; } } typeMap.put(ctx, VOID); return VOID; }
@Override public Type visitRecordAccess(MicroParser.RecordAccessContext ctx) { Type recordType = visit(ctx.expr()); if (recordType instanceof RecordType) { Scope recordScope = ((RecordType) recordType).getContainedScope(); Identifier id = recordScope.resolve(ctx.ID().getText()); if (id != null) { Type exprType = id.getType(); typeMap.put(ctx, exprType); return exprType; } else { MicroCompilerV1.error( ctx, ctx.ID().getText() + " is not a member of " + ((RecordType) recordType).getRecordTypeName()); return VOID; } } else if (recordType instanceof ArrayType && ctx.ID().getText().equals("length")) { typeMap.put(ctx, INT); return INT; } else { MicroCompilerV1.error(ctx, "Not a record type"); return VOID; } }
/** * {@inheritDoc} * * <p>Determine if the assignment is valid. BOOL and only be assigned to BOOL. INT or REAL can be * assigned to INT or REAL. * * @param ctx The Assignment_Statement Context parse tree node * @return VOID */ @Override public Type visitAssignment_statement(Assignment_statementContext ctx) { Type lhsType = visit(ctx.lvalue()); Type rhsType = visit(ctx.expr()); if (!assignmentValid(lhsType, rhsType)) { MicroCompilerV1.error(ctx, rhsType + " cannot be assigned to " + lhsType); } typeMap.put(ctx, VOID); return VOID; }
@Override public Type visitFcnCall(FcnCallContext ctx) { ctx.expr_list().expr().forEach(expr -> visit(expr)); Identifier fcnId = currentScope.resolve(ctx.ID().getText()); if (fcnId != null) { Type fcnType = fcnId.getType(); if (fcnType instanceof ProcedureOrFunction) { Type returnType = ((ProcedureOrFunction) fcnType).getReturnType(); typeMap.put(ctx, returnType); return returnType; } else { MicroCompilerV1.error(ctx, ctx.ID().getText() + " is not a function"); } } else { MicroCompilerV1.error(ctx, ctx.ID().getText() + " is not a defined"); } typeMap.put(ctx, VOID); return VOID; }
/** * {@inheritDoc} * * <p>Determine if the while_statement part is valid. The guard expression must be of type BOOL. * * @param ctx The If_statement context parse tree node. * @return VOID */ @Override public Type visitWhile_statement(While_statementContext ctx) { Type guardType = visit(ctx.expr()); if (guardType != BOOL) { error(ctx, "While statement guard is not a boolean type"); } visit(ctx.statement_list()); typeMap.put(ctx, VOID); return VOID; }
/** * {@inheritDoc} * * <p>The default implementation returns the result of calling {@link #visitChildren} on {@code * ctx}. */ @Override public Type visitIdLvalue(IdLvalueContext ctx) { Identifier id = currentScope.resolve(ctx.ID().getText()); if (id == null) { MicroCompilerV1.error(ctx, ctx.ID().getText() + " is not defined"); return VOID; } Type lhsType = id.getType(); typeMap.put(ctx, lhsType); return lhsType; }
/** * {@inheritDoc} * * <p>Determine the type of an ID * * @param ctx The parse tree node. * @return The type of the identifier. */ @Override public Type visitId(IdContext ctx) { String idName = ctx.ID().getText(); Identifier id = currentScope.resolve(idName); if (id != null) { typeMap.put(ctx, id.getType()); return id.getType(); } error(ctx, "Undefined identifier " + idName); typeMap.put(ctx, VOID); return VOID; }
/** * {@inheritDoc} * * <p>Determine result type of logical op. Both operands must be BOOL * * @param ctx LogicalopContext node. * @return BOOL if valid, VOID otherwise */ @Override public Type visitLogicalop(LogicalopContext ctx) { Type lhsType = visit(ctx.expr(0)); Type rhsType = visit(ctx.expr(1)); if (BOOL == lhsType && BOOL == rhsType) { typeMap.put(ctx, BOOL); return BOOL; } error(ctx, lhsType + " cannot be combined using a logical operator with " + rhsType); typeMap.put(ctx, VOID); return VOID; }
/** * {@inheritDoc} * * <p>The default implementation returns the result of calling {@link #visitChildren} on {@code * ctx}. */ @Override public Type visitArrayAccess(MicroParser.ArrayAccessContext ctx) { Type arrayType = visit(ctx.expr(0)); if (arrayType instanceof ArrayType) { Type exprType = ((ArrayType) arrayType).getComponentType(); typeMap.put(ctx, exprType); return exprType; } else { MicroCompilerV1.error(ctx, "Not an array type"); return VOID; } }
/** * {@inheritDoc} * * <p>Determine if the if statement is valid. The guard expression must be of type BOOL. * * @param ctx The If_statement context parse tree node. * @return VOID */ @Override public Type visitIf_statement(If_statementContext ctx) { Type guardType = visit(ctx.expr()); if (guardType != BOOL) { error(ctx, "If statement guard is not a boolean type"); } visit(ctx.statement_list()); ctx.elsif_part().forEach(elsif_part -> visit(elsif_part)); if (ctx.else_part() != null) { visit(ctx.else_part()); } typeMap.put(ctx, VOID); return VOID; }
/** * {@inheritDoc} * * <p>Determine the result type of a POW expression. * * @param ctx The POW op context parse tree node * @return The result type or VOID if invalid. */ @Override public Type visitPowop(PowopContext ctx) { Type lhsType = visit(ctx.expr(0)); Type rhsType = visit(ctx.expr(1)); Type resultType; if (lhsType == CHAR || rhsType == CHAR) { resultType = VOID; } else { resultType = determineExpressionResult(lhsType, rhsType); } if (VOID == resultType) { error(ctx, lhsType + " ** " + rhsType + " is not valid"); } typeMap.put(ctx, resultType); return resultType; }
/** * {@inheritDoc} * * <p>Determine the result type of an arithmetic expression. * * @param ctx The parse tree node. * @return The result type or VOID if invalid. */ @Override public Type visitArithop(ArithopContext ctx) { Type lhsType = visit(ctx.expr(0)); Type rhsType = visit(ctx.expr(1)); Type resultType; String op = ctx.op.getText(); if (lhsType == CHAR || rhsType == CHAR) { switch (op) { case "+": if ((lhsType == CHAR && rhsType == INT) || (rhsType == CHAR && lhsType == INT)) { resultType = CHAR; } else { resultType = VOID; } break; case "-": if (lhsType == CHAR && rhsType == CHAR) { resultType = INT; } else if (lhsType == CHAR && rhsType == INT) { resultType = CHAR; } else { resultType = VOID; } break; default: resultType = VOID; break; } } else { resultType = determineExpressionResult(lhsType, rhsType); } if (VOID == resultType) { error(ctx, lhsType + " " + op + " " + rhsType + " is not a valid combination"); } typeMap.put(ctx, resultType); return resultType; }