1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-06-03 07:29:37 +00:00

Working on type parser rewrite

This commit is contained in:
jespergravgaard 2021-05-08 13:12:04 +02:00
parent 09d11f220b
commit 823f2d7804
22 changed files with 1438 additions and 1382 deletions

View File

@ -150,17 +150,23 @@ public class StatementSource implements Serializable {
}
public static StatementSource procedureBegin(KickCParser.DeclFunctionContext ctx) {
return new StatementSource(ctx);
/*
final KickCParser.DeclFunctionBodyContext bodyCtx = ctx.declFunctionBody();
ParseTree nodeStart = bodyCtx;
ParseTree nodeStop = bodyCtx.getChild(bodyCtx.getChildCount() - 4);
return new StatementSource(nodeStart, nodeStop);
*/
}
public static StatementSource procedureEnd(KickCParser.DeclFunctionContext ctx) {
return new StatementSource(ctx);
/*
final KickCParser.DeclFunctionBodyContext bodyCtx = ctx.declFunctionBody();
ParseTree nodeStart = bodyCtx.getChild(bodyCtx.getChildCount() - 1);
ParseTree nodeStop = bodyCtx;
return new StatementSource(nodeStart, nodeStop);
*/
}
public static StatementSource asm(KickCParser.StmtAsmContext ctx) {

View File

@ -8,13 +8,16 @@ import dk.camelot64.kickc.model.values.ProcedureRef;
import dk.camelot64.kickc.passes.Pass1ByteXIntrinsicRewrite;
import dk.camelot64.kickc.passes.Pass1PrintfIntrinsicRewrite;
import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
/** Symbol describing a procedure/function */
public class Procedure extends Scope {
/** The return type. {@link SymbolType#VOID} if the procedure does not return a value. */
private final SymbolType returnType;
private final SymbolTypeProcedure procedureType;
/** The names of the parameters of the procedure. */
private List<String> parameterNames;
/** True if the parameter list ends with a variable length parameter list "..." */
@ -78,9 +81,9 @@ public class Procedure extends Scope {
/** The calling convention used for this procedure. */
private CallingConvention callingConvention;
public Procedure(String name, SymbolType returnType, Scope parentScope, String codeSegment, String dataSegment, CallingConvention callingConvention) {
public Procedure(String name, SymbolTypeProcedure procedureType, Scope parentScope, String codeSegment, String dataSegment, CallingConvention callingConvention) {
super(name, parentScope, dataSegment);
this.returnType = returnType;
this.procedureType = procedureType;
this.declaredInline = false;
this.interruptType = null;
this.comments = new ArrayList<>();
@ -127,7 +130,7 @@ public class Procedure extends Scope {
}
public SymbolType getReturnType() {
return returnType;
return procedureType.getReturnType();
}
public List<Variable> getParameters() {
@ -172,7 +175,7 @@ public class Procedure extends Scope {
@Override
public SymbolType getType() {
return new SymbolTypeProcedure(returnType);
return procedureType;
}
public boolean isDeclaredInline() {
@ -245,7 +248,7 @@ public class Procedure extends Scope {
if(interruptType != null) {
res.append("__interrupt(").append(interruptType).append(") ");
}
res.append(returnType.getTypeName()).append(" ").append(getFullName()).append("(");
res.append(getReturnType().getTypeName()).append(" ").append(getFullName()).append("(");
boolean first = true;
if(parameterNames != null) {
for(Variable parameter : getParameters()) {
@ -271,18 +274,22 @@ public class Procedure extends Scope {
if(o == null || getClass() != o.getClass()) return false;
if(!super.equals(o)) return false;
Procedure procedure = (Procedure) o;
return declaredInline == procedure.declaredInline &&
Objects.equals(returnType, procedure.returnType) &&
return variableLengthParameterList == procedure.variableLengthParameterList &&
declaredInline == procedure.declaredInline &&
declaredIntrinsic == procedure.declaredIntrinsic &&
isConstructor == procedure.isConstructor &&
Objects.equals(procedureType, procedure.procedureType) &&
Objects.equals(parameterNames, procedure.parameterNames) &&
Objects.equals(interruptType, procedure.interruptType) &&
Objects.equals(comments, procedure.comments) &&
Objects.equals(reservedZps, procedure.reservedZps) &&
Objects.equals(codeSegment, procedure.codeSegment) &&
Objects.equals(constructorRefs, procedure.constructorRefs) &&
callingConvention == procedure.callingConvention;
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), returnType, parameterNames, declaredInline, interruptType, comments, reservedZps, codeSegment, callingConvention);
return Objects.hash(super.hashCode(), procedureType, parameterNames, variableLengthParameterList, declaredInline, declaredIntrinsic, interruptType, comments, reservedZps, codeSegment, constructorRefs, isConstructor, callingConvention);
}
}

View File

@ -45,6 +45,8 @@ public interface SymbolType extends Serializable {
SymbolTypeNamed LABEL = new SymbolTypeNamed("label", 1, false, false);
/** Void type representing no value. */
SymbolTypeNamed VOID = new SymbolTypeNamed("void", 0, false, false);
/** Value List type representing a "..." parameter list. */
SymbolTypeNamed PARAM_LIST = new SymbolTypeNamed("param_list", 0, false, false);
/** An unresolved type. Will be infered later. */
SymbolTypeNamed VAR = new SymbolTypeNamed("var", -1, false, false);

View File

@ -1,14 +1,17 @@
package dk.camelot64.kickc.model.types;
import java.util.List;
import java.util.Objects;
/** A function returning another type */
public class SymbolTypeProcedure implements SymbolType {
private SymbolType returnType;
private List<SymbolType> paramTypes;
public SymbolTypeProcedure(SymbolType returnType) {
public SymbolTypeProcedure(SymbolType returnType, List<SymbolType> paramTypes) {
this.returnType = returnType;
this.paramTypes = paramTypes;
}
@Override
@ -35,9 +38,28 @@ public class SymbolTypeProcedure implements SymbolType {
return returnType;
}
public List<SymbolType> getParamTypes() {
return paramTypes;
}
public void setParamTypes(List<SymbolType> paramTypes) {
this.paramTypes = paramTypes;
}
@Override
public String getTypeBaseName() {
return returnType.getTypeName() + "()";
final StringBuilder typeBaseName = new StringBuilder();
typeBaseName.append(returnType.getTypeBaseName());
typeBaseName.append("(");
boolean first = true;
for(SymbolType paramType : paramTypes) {
if(!first)
typeBaseName.append(",");
first = false;
typeBaseName.append(paramType.getTypeBaseName());
}
typeBaseName.append(")");
return typeBaseName.toString();
}
@Override
@ -50,11 +72,13 @@ public class SymbolTypeProcedure implements SymbolType {
if(this == o) return true;
if(o == null || getClass() != o.getClass()) return false;
SymbolTypeProcedure that = (SymbolTypeProcedure) o;
return Objects.equals(returnType, that.returnType);
return Objects.equals(returnType, that.returnType) &&
Objects.equals(paramTypes, that.paramTypes);
}
@Override
public int hashCode() {
return Objects.hash(returnType);
return Objects.hash(returnType, paramTypes);
}
}

View File

@ -72,6 +72,7 @@ typeSpecifier
declarator
: NAME {if(isTypedef) { cParser.addTypedef($NAME.text); isTypedef=false; } } #declaratorName
| declarator PAR_BEGIN parameterListDecl? PAR_END #declaratorProcedure
| declarator BRACKET_BEGIN (expr)? BRACKET_END #declaratorArray
| ASTERISK directive* declarator #declaratorPointer
| PAR_BEGIN declarator PAR_END #declaratorPar
@ -80,7 +81,6 @@ declarator
type
: SIMPLETYPE #typeSimple
| SIGNEDNESS SIMPLETYPE? #typeSignedSimple
| type PAR_BEGIN PAR_END #typeProcedure // TODO: Move to declarator
| structDef #typeStructDef
| structRef #typeStructRef
| enumDef #typeEnumDef
@ -118,11 +118,7 @@ enumMember
;
declFunction
: declType declarator PAR_BEGIN parameterListDecl? PAR_END (declFunctionBody | ';' )
;
declFunctionBody
: CURLY_BEGIN stmtSeq? CURLY_END
: declType declarator CURLY_BEGIN stmtSeq? CURLY_END
;
parameterListDecl

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -222,25 +222,13 @@ public class KickCParserBaseListener implements KickCParserListener {
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterTypeProcedure(KickCParser.TypeProcedureContext ctx) { }
@Override public void enterDeclaratorProcedure(KickCParser.DeclaratorProcedureContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitTypeProcedure(KickCParser.TypeProcedureContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterTypeStructRef(KickCParser.TypeStructRefContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitTypeStructRef(KickCParser.TypeStructRefContext ctx) { }
@Override public void exitDeclaratorProcedure(KickCParser.DeclaratorProcedureContext ctx) { }
/**
* {@inheritDoc}
*
@ -253,6 +241,18 @@ public class KickCParserBaseListener implements KickCParserListener {
* <p>The default implementation does nothing.</p>
*/
@Override public void exitTypeSimple(KickCParser.TypeSimpleContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterTypeSignedSimple(KickCParser.TypeSignedSimpleContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitTypeSignedSimple(KickCParser.TypeSignedSimpleContext ctx) { }
/**
* {@inheritDoc}
*
@ -270,25 +270,25 @@ public class KickCParserBaseListener implements KickCParserListener {
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterTypeNamedRef(KickCParser.TypeNamedRefContext ctx) { }
@Override public void enterTypeStructRef(KickCParser.TypeStructRefContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitTypeNamedRef(KickCParser.TypeNamedRefContext ctx) { }
@Override public void exitTypeStructRef(KickCParser.TypeStructRefContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterTypeSignedSimple(KickCParser.TypeSignedSimpleContext ctx) { }
@Override public void enterTypeEnumDef(KickCParser.TypeEnumDefContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitTypeSignedSimple(KickCParser.TypeSignedSimpleContext ctx) { }
@Override public void exitTypeEnumDef(KickCParser.TypeEnumDefContext ctx) { }
/**
* {@inheritDoc}
*
@ -306,13 +306,13 @@ public class KickCParserBaseListener implements KickCParserListener {
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterTypeEnumDef(KickCParser.TypeEnumDefContext ctx) { }
@Override public void enterTypeNamedRef(KickCParser.TypeNamedRefContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitTypeEnumDef(KickCParser.TypeEnumDefContext ctx) { }
@Override public void exitTypeNamedRef(KickCParser.TypeNamedRefContext ctx) { }
/**
* {@inheritDoc}
*
@ -409,18 +409,6 @@ public class KickCParserBaseListener implements KickCParserListener {
* <p>The default implementation does nothing.</p>
*/
@Override public void exitDeclFunction(KickCParser.DeclFunctionContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterDeclFunctionBody(KickCParser.DeclFunctionBodyContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitDeclFunctionBody(KickCParser.DeclFunctionBodyContext ctx) { }
/**
* {@inheritDoc}
*

View File

@ -138,14 +138,7 @@ public class KickCParserBaseVisitor<T> extends AbstractParseTreeVisitor<T> imple
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitTypeProcedure(KickCParser.TypeProcedureContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitTypeStructRef(KickCParser.TypeStructRefContext ctx) { return visitChildren(ctx); }
@Override public T visitDeclaratorProcedure(KickCParser.DeclaratorProcedureContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
@ -153,6 +146,13 @@ public class KickCParserBaseVisitor<T> extends AbstractParseTreeVisitor<T> imple
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitTypeSimple(KickCParser.TypeSimpleContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitTypeSignedSimple(KickCParser.TypeSignedSimpleContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
@ -166,14 +166,14 @@ public class KickCParserBaseVisitor<T> extends AbstractParseTreeVisitor<T> imple
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitTypeNamedRef(KickCParser.TypeNamedRefContext ctx) { return visitChildren(ctx); }
@Override public T visitTypeStructRef(KickCParser.TypeStructRefContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitTypeSignedSimple(KickCParser.TypeSignedSimpleContext ctx) { return visitChildren(ctx); }
@Override public T visitTypeEnumDef(KickCParser.TypeEnumDefContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
@ -187,7 +187,7 @@ public class KickCParserBaseVisitor<T> extends AbstractParseTreeVisitor<T> imple
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitTypeEnumDef(KickCParser.TypeEnumDefContext ctx) { return visitChildren(ctx); }
@Override public T visitTypeNamedRef(KickCParser.TypeNamedRefContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
@ -244,13 +244,6 @@ public class KickCParserBaseVisitor<T> extends AbstractParseTreeVisitor<T> imple
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitDeclFunction(KickCParser.DeclFunctionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitDeclFunctionBody(KickCParser.DeclFunctionBodyContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*

View File

@ -198,29 +198,17 @@ public interface KickCParserListener extends ParseTreeListener {
*/
void exitDeclaratorName(KickCParser.DeclaratorNameContext ctx);
/**
* Enter a parse tree produced by the {@code typeProcedure}
* labeled alternative in {@link KickCParser#type}.
* Enter a parse tree produced by the {@code declaratorProcedure}
* labeled alternative in {@link KickCParser#declarator}.
* @param ctx the parse tree
*/
void enterTypeProcedure(KickCParser.TypeProcedureContext ctx);
void enterDeclaratorProcedure(KickCParser.DeclaratorProcedureContext ctx);
/**
* Exit a parse tree produced by the {@code typeProcedure}
* labeled alternative in {@link KickCParser#type}.
* Exit a parse tree produced by the {@code declaratorProcedure}
* labeled alternative in {@link KickCParser#declarator}.
* @param ctx the parse tree
*/
void exitTypeProcedure(KickCParser.TypeProcedureContext ctx);
/**
* Enter a parse tree produced by the {@code typeStructRef}
* labeled alternative in {@link KickCParser#type}.
* @param ctx the parse tree
*/
void enterTypeStructRef(KickCParser.TypeStructRefContext ctx);
/**
* Exit a parse tree produced by the {@code typeStructRef}
* labeled alternative in {@link KickCParser#type}.
* @param ctx the parse tree
*/
void exitTypeStructRef(KickCParser.TypeStructRefContext ctx);
void exitDeclaratorProcedure(KickCParser.DeclaratorProcedureContext ctx);
/**
* Enter a parse tree produced by the {@code typeSimple}
* labeled alternative in {@link KickCParser#type}.
@ -233,6 +221,18 @@ public interface KickCParserListener extends ParseTreeListener {
* @param ctx the parse tree
*/
void exitTypeSimple(KickCParser.TypeSimpleContext ctx);
/**
* Enter a parse tree produced by the {@code typeSignedSimple}
* labeled alternative in {@link KickCParser#type}.
* @param ctx the parse tree
*/
void enterTypeSignedSimple(KickCParser.TypeSignedSimpleContext ctx);
/**
* Exit a parse tree produced by the {@code typeSignedSimple}
* labeled alternative in {@link KickCParser#type}.
* @param ctx the parse tree
*/
void exitTypeSignedSimple(KickCParser.TypeSignedSimpleContext ctx);
/**
* Enter a parse tree produced by the {@code typeStructDef}
* labeled alternative in {@link KickCParser#type}.
@ -246,29 +246,29 @@ public interface KickCParserListener extends ParseTreeListener {
*/
void exitTypeStructDef(KickCParser.TypeStructDefContext ctx);
/**
* Enter a parse tree produced by the {@code typeNamedRef}
* Enter a parse tree produced by the {@code typeStructRef}
* labeled alternative in {@link KickCParser#type}.
* @param ctx the parse tree
*/
void enterTypeNamedRef(KickCParser.TypeNamedRefContext ctx);
void enterTypeStructRef(KickCParser.TypeStructRefContext ctx);
/**
* Exit a parse tree produced by the {@code typeNamedRef}
* Exit a parse tree produced by the {@code typeStructRef}
* labeled alternative in {@link KickCParser#type}.
* @param ctx the parse tree
*/
void exitTypeNamedRef(KickCParser.TypeNamedRefContext ctx);
void exitTypeStructRef(KickCParser.TypeStructRefContext ctx);
/**
* Enter a parse tree produced by the {@code typeSignedSimple}
* Enter a parse tree produced by the {@code typeEnumDef}
* labeled alternative in {@link KickCParser#type}.
* @param ctx the parse tree
*/
void enterTypeSignedSimple(KickCParser.TypeSignedSimpleContext ctx);
void enterTypeEnumDef(KickCParser.TypeEnumDefContext ctx);
/**
* Exit a parse tree produced by the {@code typeSignedSimple}
* Exit a parse tree produced by the {@code typeEnumDef}
* labeled alternative in {@link KickCParser#type}.
* @param ctx the parse tree
*/
void exitTypeSignedSimple(KickCParser.TypeSignedSimpleContext ctx);
void exitTypeEnumDef(KickCParser.TypeEnumDefContext ctx);
/**
* Enter a parse tree produced by the {@code typeEnumRef}
* labeled alternative in {@link KickCParser#type}.
@ -282,17 +282,17 @@ public interface KickCParserListener extends ParseTreeListener {
*/
void exitTypeEnumRef(KickCParser.TypeEnumRefContext ctx);
/**
* Enter a parse tree produced by the {@code typeEnumDef}
* Enter a parse tree produced by the {@code typeNamedRef}
* labeled alternative in {@link KickCParser#type}.
* @param ctx the parse tree
*/
void enterTypeEnumDef(KickCParser.TypeEnumDefContext ctx);
void enterTypeNamedRef(KickCParser.TypeNamedRefContext ctx);
/**
* Exit a parse tree produced by the {@code typeEnumDef}
* Exit a parse tree produced by the {@code typeNamedRef}
* labeled alternative in {@link KickCParser#type}.
* @param ctx the parse tree
*/
void exitTypeEnumDef(KickCParser.TypeEnumDefContext ctx);
void exitTypeNamedRef(KickCParser.TypeNamedRefContext ctx);
/**
* Enter a parse tree produced by {@link KickCParser#structRef}.
* @param ctx the parse tree
@ -373,16 +373,6 @@ public interface KickCParserListener extends ParseTreeListener {
* @param ctx the parse tree
*/
void exitDeclFunction(KickCParser.DeclFunctionContext ctx);
/**
* Enter a parse tree produced by {@link KickCParser#declFunctionBody}.
* @param ctx the parse tree
*/
void enterDeclFunctionBody(KickCParser.DeclFunctionBodyContext ctx);
/**
* Exit a parse tree produced by {@link KickCParser#declFunctionBody}.
* @param ctx the parse tree
*/
void exitDeclFunctionBody(KickCParser.DeclFunctionBodyContext ctx);
/**
* Enter a parse tree produced by {@link KickCParser#parameterListDecl}.
* @param ctx the parse tree

View File

@ -124,19 +124,12 @@ public interface KickCParserVisitor<T> extends ParseTreeVisitor<T> {
*/
T visitDeclaratorName(KickCParser.DeclaratorNameContext ctx);
/**
* Visit a parse tree produced by the {@code typeProcedure}
* labeled alternative in {@link KickCParser#type}.
* Visit a parse tree produced by the {@code declaratorProcedure}
* labeled alternative in {@link KickCParser#declarator}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitTypeProcedure(KickCParser.TypeProcedureContext ctx);
/**
* Visit a parse tree produced by the {@code typeStructRef}
* labeled alternative in {@link KickCParser#type}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitTypeStructRef(KickCParser.TypeStructRefContext ctx);
T visitDeclaratorProcedure(KickCParser.DeclaratorProcedureContext ctx);
/**
* Visit a parse tree produced by the {@code typeSimple}
* labeled alternative in {@link KickCParser#type}.
@ -144,6 +137,13 @@ public interface KickCParserVisitor<T> extends ParseTreeVisitor<T> {
* @return the visitor result
*/
T visitTypeSimple(KickCParser.TypeSimpleContext ctx);
/**
* Visit a parse tree produced by the {@code typeSignedSimple}
* labeled alternative in {@link KickCParser#type}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitTypeSignedSimple(KickCParser.TypeSignedSimpleContext ctx);
/**
* Visit a parse tree produced by the {@code typeStructDef}
* labeled alternative in {@link KickCParser#type}.
@ -152,19 +152,19 @@ public interface KickCParserVisitor<T> extends ParseTreeVisitor<T> {
*/
T visitTypeStructDef(KickCParser.TypeStructDefContext ctx);
/**
* Visit a parse tree produced by the {@code typeNamedRef}
* Visit a parse tree produced by the {@code typeStructRef}
* labeled alternative in {@link KickCParser#type}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitTypeNamedRef(KickCParser.TypeNamedRefContext ctx);
T visitTypeStructRef(KickCParser.TypeStructRefContext ctx);
/**
* Visit a parse tree produced by the {@code typeSignedSimple}
* Visit a parse tree produced by the {@code typeEnumDef}
* labeled alternative in {@link KickCParser#type}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitTypeSignedSimple(KickCParser.TypeSignedSimpleContext ctx);
T visitTypeEnumDef(KickCParser.TypeEnumDefContext ctx);
/**
* Visit a parse tree produced by the {@code typeEnumRef}
* labeled alternative in {@link KickCParser#type}.
@ -173,12 +173,12 @@ public interface KickCParserVisitor<T> extends ParseTreeVisitor<T> {
*/
T visitTypeEnumRef(KickCParser.TypeEnumRefContext ctx);
/**
* Visit a parse tree produced by the {@code typeEnumDef}
* Visit a parse tree produced by the {@code typeNamedRef}
* labeled alternative in {@link KickCParser#type}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitTypeEnumDef(KickCParser.TypeEnumDefContext ctx);
T visitTypeNamedRef(KickCParser.TypeNamedRefContext ctx);
/**
* Visit a parse tree produced by {@link KickCParser#structRef}.
* @param ctx the parse tree
@ -227,12 +227,6 @@ public interface KickCParserVisitor<T> extends ParseTreeVisitor<T> {
* @return the visitor result
*/
T visitDeclFunction(KickCParser.DeclFunctionContext ctx);
/**
* Visit a parse tree produced by {@link KickCParser#declFunctionBody}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitDeclFunctionBody(KickCParser.DeclFunctionBodyContext ctx);
/**
* Visit a parse tree produced by {@link KickCParser#parameterListDecl}.
* @param ctx the parse tree

View File

@ -116,7 +116,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
Procedure initProc = program.getScope().getLocalProcedure(SymbolRef.INIT_PROC_NAME);
if(initProc == null) {
// Create the _init() procedure
initProc = new Procedure(SymbolRef.INIT_PROC_NAME, SymbolType.VOID, program.getScope(), Scope.SEGMENT_CODE_DEFAULT, Scope.SEGMENT_DATA_DEFAULT, Procedure.CallingConvention.PHI_CALL);
initProc = new Procedure(SymbolRef.INIT_PROC_NAME, new SymbolTypeProcedure(SymbolType.VOID, new ArrayList<>()), program.getScope(), Scope.SEGMENT_CODE_DEFAULT, Scope.SEGMENT_DATA_DEFAULT, Procedure.CallingConvention.PHI_CALL);
initProc.setDeclaredInline(true);
initProc.setParameters(new ArrayList<>());
program.getScope().add(initProc);
@ -173,7 +173,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
// Add the _start() procedure to the program
{
program.setStartProcedure(new ProcedureRef(SymbolRef.START_PROC_NAME));
final Procedure startProcedure = new Procedure(SymbolRef.START_PROC_NAME, SymbolType.VOID, program.getScope(), Scope.SEGMENT_CODE_DEFAULT, Scope.SEGMENT_DATA_DEFAULT, Procedure.CallingConvention.PHI_CALL);
final Procedure startProcedure = new Procedure(SymbolRef.START_PROC_NAME, new SymbolTypeProcedure(SymbolType.VOID, new ArrayList<>()), program.getScope(), Scope.SEGMENT_CODE_DEFAULT, Scope.SEGMENT_DATA_DEFAULT, Procedure.CallingConvention.PHI_CALL);
startProcedure.setParameters(new ArrayList<>());
program.getScope().add(startProcedure);
final ProcedureCompilation startProcedureCompilation = program.createProcedureCompilation(startProcedure.getRef());
@ -391,83 +391,70 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
public Object visitDeclFunction(KickCParser.DeclFunctionContext ctx) {
this.visit(ctx.declType());
this.visit(ctx.declarator());
SymbolType type = varDecl.getEffectiveType();
List<Directive> directives = varDecl.getDeclDirectives();
String name = varDecl.getVarName();
Procedure procedure = new Procedure(name, type, program.getScope(), currentCodeSegment, currentDataSegment, currentCallingConvention);
addDirectives(procedure, directives, StatementSource.procedureDecl(ctx));
StatementSource declSource = new StatementSource((ParserRuleContext) ctx.parent.parent);
Procedure procedure = new Procedure(varDecl.getVarName(), (SymbolTypeProcedure) varDecl.declType, program.getScope(), currentCodeSegment, currentDataSegment, currentCallingConvention);
addDirectives(procedure, varDecl.getDeclDirectives(), declSource);
procedure.setComments(ensureUnusedComments(getCommentsSymbol(ctx)));
// TODO: Detect existing declarations and check for match!
program.getScope().add(procedure);
program.createProcedureCompilation(procedure.getRef());
// enter the procedure
scopeStack.push(procedure);
// Add return variable
Variable returnVar = null;
if(!SymbolType.VOID.equals(type)) {
final VariableBuilder builder = new VariableBuilder("return", procedure, false, varDecl.getEffectiveType(), varDecl.getDeclDirectives(), currentDataSegment, program.getTargetPlatform().getVariableBuilderConfig());
if(!SymbolType.VOID.equals(procedure.getReturnType())) {
final VariableBuilder builder = new VariableBuilder("return", procedure, false, procedure.getReturnType(), varDecl.getDeclDirectives(), currentDataSegment, program.getTargetPlatform().getVariableBuilderConfig());
returnVar = builder.build();
}
varDecl.exitType();
// Add parameter variables...
List<Variable> parameterList = new ArrayList<>();
if(ctx.parameterListDecl() != null) {
parameterList = (List<Variable>) this.visit(ctx.parameterListDecl());
for(ParameterDecl parameter : varDecl.parameters) {
VariableBuilder varBuilder = new VariableBuilder(parameter.name, getCurrentScope(), true, parameter.type, null, currentDataSegment, program.getTargetPlatform().getVariableBuilderConfig());
final Variable paramVar = varBuilder.build();
parameterList.add(paramVar);
}
procedure.setParameters(parameterList);
varDecl.exitType();
// Check that the body has not already been added
final StatementSequence statementSequence = getCurrentProcedureCompilation().getStatementSequence();
if(statementSequence != null && statementSequence.getStatements().size() > 0)
throw new CompileError("Redefinition of function: " + procedure.getFullName(), StatementSource.procedureBegin(ctx));
// Add the body
addStatement(new StatementProcedureBegin(procedure.getRef(), StatementSource.procedureBegin(ctx), Comment.NO_COMMENTS));
// Add parameter assignments
if(Procedure.CallingConvention.STACK_CALL.equals(procedure.getCallingConvention())) {
for(Variable param : parameterList) {
addStatement(new StatementAssignment((LValue) param.getRef(), new ParamValue((VariableRef) param.getRef()), true, StatementSource.procedureEnd(ctx), Comment.NO_COMMENTS));
}
}
Label procExit = procedure.addLabel(SymbolRef.PROCEXIT_BLOCK_NAME);
if(ctx.stmtSeq() != null) {
this.visit(ctx.stmtSeq());
}
addStatement(new StatementLabel(procExit.getRef(), StatementSource.procedureEnd(ctx), Comment.NO_COMMENTS));
if(Procedure.CallingConvention.PHI_CALL.equals(procedure.getCallingConvention()) && returnVar != null) {
addStatement(new StatementAssignment(returnVar.getVariableRef(), returnVar.getRef(), false, StatementSource.procedureEnd(ctx), Comment.NO_COMMENTS));
}
SymbolVariableRef returnVarRef = null;
if(returnVar != null) {
returnVarRef = returnVar.getRef();
}
addStatement(new StatementReturn(returnVarRef, StatementSource.procedureEnd(ctx), Comment.NO_COMMENTS));
addStatement(new StatementProcedureEnd(procedure.getRef(), StatementSource.procedureEnd(ctx), Comment.NO_COMMENTS));
scopeStack.pop();
// Check that the declaration matches any existing declaration!
final Symbol existingSymbol = program.getScope().getSymbol(procedure.getRef());
if(existingSymbol != null) {
// Already declared - check equality
if(!(existingSymbol instanceof Procedure) || !SymbolTypeConversion.procedureDeclarationMatch((Procedure) existingSymbol, procedure))
throw new CompileError("Conflicting declarations for: " + procedure.getFullName(), new StatementSource(ctx));
} else {
// Not declared before - add it
program.getScope().add(procedure);
program.createProcedureCompilation(procedure.getRef());
}
if(ctx.declFunctionBody() != null || VariableBuilder.hasDirective(Directive.Intrinsic.class, directives)) {
// Make sure directives and more are taken from the procedure with the body / intrinsic declaration!
if(existingSymbol != null) {
program.getScope().remove(existingSymbol);
program.getScope().add(procedure);
}
}
if(ctx.declFunctionBody() != null) {
scopeStack.push(procedure);
// Check that the body has not already been added
final StatementSequence statementSequence = getCurrentProcedureCompilation().getStatementSequence();
if(statementSequence != null && statementSequence.getStatements().size() > 0)
throw new CompileError("Redefinition of function: " + procedure.getFullName(), StatementSource.procedureBegin(ctx));
// Add the body
addStatement(new StatementProcedureBegin(procedure.getRef(), StatementSource.procedureBegin(ctx), Comment.NO_COMMENTS));
// Add parameter assignments
if(Procedure.CallingConvention.STACK_CALL.equals(procedure.getCallingConvention())) {
for(Variable param : parameterList) {
addStatement(new StatementAssignment((LValue) param.getRef(), new ParamValue((VariableRef) param.getRef()), true, StatementSource.procedureEnd(ctx), Comment.NO_COMMENTS));
}
}
Label procExit = procedure.addLabel(SymbolRef.PROCEXIT_BLOCK_NAME);
if(ctx.declFunctionBody().stmtSeq() != null) {
this.visit(ctx.declFunctionBody().stmtSeq());
}
addStatement(new StatementLabel(procExit.getRef(), StatementSource.procedureEnd(ctx), Comment.NO_COMMENTS));
if(Procedure.CallingConvention.PHI_CALL.equals(procedure.getCallingConvention()) && returnVar != null) {
addStatement(new StatementAssignment(returnVar.getVariableRef(), returnVar.getRef(), false, StatementSource.procedureEnd(ctx), Comment.NO_COMMENTS));
}
SymbolVariableRef returnVarRef = null;
if(returnVar != null) {
returnVarRef = returnVar.getRef();
}
addStatement(new StatementReturn(returnVarRef, StatementSource.procedureEnd(ctx), Comment.NO_COMMENTS));
addStatement(new StatementProcedureEnd(procedure.getRef(), StatementSource.procedureEnd(ctx), Comment.NO_COMMENTS));
scopeStack.pop();
}
return null;
}
@Override
public List<Variable> visitParameterListDecl(KickCParser.ParameterListDeclContext ctx) {
/*
ArrayList<Variable> parameterDecls = new ArrayList<>();
boolean encounteredVariableLengthParamList = false;
for(KickCParser.ParameterDeclContext parameterDeclCtx : ctx.parameterDecl()) {
@ -494,17 +481,18 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
}
}
return parameterDecls;
*/
return null;
}
@Override
public Object visitParameterDeclType(KickCParser.ParameterDeclTypeContext ctx) {
this.visit(ctx.declType());
this.visit(ctx.declarator());
String varName = varDecl.getVarName();
VariableBuilder varBuilder = new VariableBuilder(varName, getCurrentScope(), true, varDecl.getEffectiveType(), varDecl.getDeclDirectives(), currentDataSegment, program.getTargetPlatform().getVariableBuilderConfig());
Variable param = varBuilder.build();
ParameterDecl paramDecl = new ParameterDecl(varDecl.getVarName(), varDecl.getEffectiveType());
varDecl.exitType();
return param;
return paramDecl;
}
@Override
@ -512,15 +500,12 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
if(!SymbolType.VOID.getTypeName().equals(ctx.SIMPLETYPE().getText())) {
throw new CompileError("Illegal unnamed parameter " + ctx.SIMPLETYPE().getText(), new StatementSource(ctx));
}
return SymbolType.VOID;
return new ParameterDecl(null, SymbolType.VOID);
}
/** Singleton signalling a "..." parameter list. */
public static Object PARAM_LIST = new Object();
@Override
public Object visitParameterDeclList(KickCParser.ParameterDeclListContext ctx) {
return PARAM_LIST;
return new ParameterDecl(null, SymbolType.PARAM_LIST);
}
@Override
@ -740,13 +725,26 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
return new AsmDirectiveClobber(clobber);
}
/** Information about a declared parameter. */
static class ParameterDecl {
final public String name;
final public SymbolType type;
public ParameterDecl(String name, SymbolType type) {
this.name = name;
this.type = type;
}
}
/**
* Holds type, arrayness, directives, comments etc. while parsing a variable declaration.
* Holds type directives, comments etc. while parsing a variable or procedure declaration.
* Has three levels of information pushed on top of each other:
* <ol>
* <li>Struct Member Declaration (true while inside inside a struct declaration)</li>
* <li>Type information and directives (the type)</li>
* <li>Variable information and declarations (arrayness, pointerness, variable level directives)</li>
* <li>Information about parameters (for procedures)</li>
* </ol>
* <p>
* When parsing a declaration such as <code>volatile char a, * const b, c[]</code> the type level holds <code>volatile char</code>
@ -766,6 +764,8 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
private SymbolType varDeclType;
/** The variable name (variable level) */
private String varName;
/** The declared parameters (if this is a procedure). */
private List<ParameterDecl> parameters;
/**
* Exits the type layer (clears everything except struct information)
@ -776,6 +776,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
this.declType = null;
this.varDeclType = null;
this.varName = null;
this.parameters = new ArrayList<>();
}
/**
@ -784,6 +785,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
void exitVar() {
this.varDeclType = null;
this.varName = null;
this.parameters = new ArrayList<>();
}
SymbolType getEffectiveType() {
@ -862,6 +864,14 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
this.structMember = structMember;
}
public void setParameters(List<ParameterDecl> parameters) {
this.parameters = parameters;
}
public List<ParameterDecl> getParameters() {
return parameters;
}
}
/** The current variable declaration. This is not on the stack. */
@ -923,48 +933,57 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
String varName = varDecl.getVarName();
KickCParser.ExprContext initializer = ctx.expr();
StatementSource declSource = new StatementSource((ParserRuleContext) ctx.parent.parent);
StatementSource statementSource = declSource;
try {
final boolean isStructMember = varDecl.isStructMember();
final SymbolType effectiveType = varDecl.getEffectiveType();
final List<Directive> effectiveDirectives = varDecl.getDeclDirectives();
final List<Comment> declComments = varDecl.getDeclComments();
varDecl.exitVar();
VariableBuilder varBuilder = new VariableBuilder(varName, getCurrentScope(), false, effectiveType, effectiveDirectives, currentDataSegment, program.getTargetPlatform().getVariableBuilderConfig());
Variable variable = varBuilder.build();
if(isStructMember && (initializer != null))
throw new CompileError("Initializer not supported inside structs " + effectiveType.getTypeName(), statementSource);
if(variable.isDeclarationOnly()) {
if(initializer != null) {
throw new CompileError("Initializer not allowed for extern variables " + varName, statementSource);
}
} else {
// Create a proper initializer
if(initializer != null)
PrePostModifierHandler.addPreModifiers(this, initializer, statementSource);
RValue initValue = (initializer == null) ? null : (RValue) visit(initializer);
initValue = Initializers.constantify(initValue, new Initializers.ValueTypeSpec(effectiveType), program, statementSource);
boolean isPermanent = ScopeRef.ROOT.equals(variable.getScope().getRef()) || variable.isPermanent();
if(variable.isKindConstant() || (isPermanent && variable.isKindLoadStore() && Variable.MemoryArea.MAIN_MEMORY.equals(variable.getMemoryArea()) && initValue instanceof ConstantValue && !isStructMember && variable.getRegister() == null)) {
// Set initial value
ConstantValue constInitValue = getConstInitValue(initValue, initializer, statementSource);
variable.setInitValue(constInitValue);
// Add comments to constant
variable.setComments(ensureUnusedComments(declComments));
} else if(!variable.isKindConstant() && !isStructMember) {
Statement initStmt = new StatementAssignment(variable.getVariableRef(), initValue, true, statementSource, Comment.NO_COMMENTS);
addStatement(initStmt);
if(variable.getScope().getRef().equals(ScopeRef.ROOT)) {
// Add comments to variable for global vars
variable.setComments(ensureUnusedComments(declComments));
} else {
// Add comments to statement for local vars
initStmt.setComments(ensureUnusedComments(declComments));
}
if(effectiveType instanceof SymbolTypeProcedure) {
Procedure procedure = new Procedure(varName, (SymbolTypeProcedure) effectiveType, program.getScope(), currentCodeSegment, currentDataSegment, currentCallingConvention);
addDirectives(procedure, effectiveDirectives, declSource);
procedure.setComments(ensureUnusedComments(getCommentsSymbol(ctx)));
// TODO: Detect existing declarations and check for match!
program.getScope().add(procedure);
program.createProcedureCompilation(procedure.getRef());
} else {
VariableBuilder varBuilder = new VariableBuilder(varName, getCurrentScope(), false, effectiveType, effectiveDirectives, currentDataSegment, program.getTargetPlatform().getVariableBuilderConfig());
Variable variable = varBuilder.build();
if(isStructMember && (initializer != null))
throw new CompileError("Initializer not supported inside structs " + effectiveType.getTypeName(), declSource);
if(variable.isDeclarationOnly()) {
if(initializer != null) {
throw new CompileError("Initializer not allowed for extern variables " + varName, declSource);
}
} else {
// Create a proper initializer
if(initializer != null)
PrePostModifierHandler.addPreModifiers(this, initializer, declSource);
RValue initValue = (initializer == null) ? null : (RValue) visit(initializer);
initValue = Initializers.constantify(initValue, new Initializers.ValueTypeSpec(effectiveType), program, declSource);
boolean isPermanent = ScopeRef.ROOT.equals(variable.getScope().getRef()) || variable.isPermanent();
if(variable.isKindConstant() || (isPermanent && variable.isKindLoadStore() && Variable.MemoryArea.MAIN_MEMORY.equals(variable.getMemoryArea()) && initValue instanceof ConstantValue && !isStructMember && variable.getRegister() == null)) {
// Set initial value
ConstantValue constInitValue = getConstInitValue(initValue, initializer, declSource);
variable.setInitValue(constInitValue);
// Add comments to constant
variable.setComments(ensureUnusedComments(declComments));
} else if(!variable.isKindConstant() && !isStructMember) {
Statement initStmt = new StatementAssignment(variable.getVariableRef(), initValue, true, declSource, Comment.NO_COMMENTS);
addStatement(initStmt);
if(variable.getScope().getRef().equals(ScopeRef.ROOT)) {
// Add comments to variable for global vars
variable.setComments(ensureUnusedComments(declComments));
} else {
// Add comments to statement for local vars
initStmt.setComments(ensureUnusedComments(declComments));
}
}
if(initializer != null)
PrePostModifierHandler.addPostModifiers(this, initializer, declSource);
}
if(initializer != null)
PrePostModifierHandler.addPostModifiers(this, initializer, statementSource);
}
} catch(CompileError e) {
throw new CompileError(e.getMessage(), declSource);
@ -1950,16 +1969,24 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
return null;
}
/*
@Override
public Object visitDeclaratorProcedure(KickCParser.DeclaratorProcedureContext ctx) {
visit(ctx.declarator());
// TODO: Handle parameters!
List<ParameterDecl> parameters = new ArrayList<>();
List<SymbolType> paramTypes = new ArrayList<>();
if(ctx.parameterListDecl() != null)
for(KickCParser.ParameterDeclContext parameterDeclContext : ctx.parameterListDecl().parameterDecl()) {
varDeclPush();
ParameterDecl paramDecl = (ParameterDecl) this.visit(parameterDeclContext);
paramTypes.add(paramDecl.type);
parameters.add(paramDecl);
varDeclPop();
}
SymbolType returnType = varDecl.getEffectiveType();
varDecl.setDeclType(new SymbolTypeProcedure(returnType));
varDecl.setDeclType(new SymbolTypeProcedure(returnType, paramTypes));
varDecl.setParameters(parameters);
return null;
}
*/
@Override
public Object visitTypeNamedRef(KickCParser.TypeNamedRefContext ctx) {
@ -2004,14 +2031,6 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
return null;
}
@Override
public Object visitTypeProcedure(KickCParser.TypeProcedureContext ctx) {
visit(ctx.type());
SymbolType returnType = varDecl.getEffectiveType();
varDecl.setDeclType(new SymbolTypeProcedure(returnType));
return null;
}
/**
* RValues that have not yet been output as part of a statement.
* The expression visitor methods updates this so that the surrounding

View File

@ -9,9 +9,44 @@ import java.io.IOException;
*/
public class TestProgramsFast extends TestPrograms {
@Test
public void testProcedureDeclare7() throws IOException {
compileAndCompare("procedure-declare-7.c", log());
}
@Test
public void testProcedureDeclare6() throws IOException {
compileAndCompare("procedure-declare-6.c", log());
}
@Test
public void testProcedureDeclare5() throws IOException {
compileAndCompare("procedure-declare-5.c", log());
}
@Test
public void testProcedureDeclare4() throws IOException {
compileAndCompare("procedure-declare-4.c", log());
}
@Test
public void testProcedureDeclare3() throws IOException {
compileAndCompare("procedure-declare-3.c", log());
}
@Test
public void testProcedureDeclare2() throws IOException {
compileAndCompare("procedure-declare-2.c", log());
}
@Test
public void testProcedureDeclare1() throws IOException {
compileAndCompare("procedure-declare-1.c", log());
}
@Test
public void testProcedureDeclare0() throws IOException {
compileAndCompare("procedure-declare-0.c");
compileAndCompare("procedure-declare-0.c", log());
}
@Test

View File

@ -1,13 +1,7 @@
// Procedure Declaration
char f(char a);
// Procedure Declaration - a single procedure without parameters declared and defined at once
void main() {
char * const SCREEN = 0x0400;
SCREEN[0] = f('a');
SCREEN[1] = f('b');
SCREEN[0] = 'a';
}
char f(char a) {
return a+1;
}

View File

@ -0,0 +1,9 @@
// Procedure Declaration - A single procedure without parameters or return declared and then defined
void main();
void main() {
char * const SCREEN = 0x0400;
SCREEN[0] = 'a';
}

View File

@ -0,0 +1,11 @@
// Procedure Declaration - a procedure with paramters&return defined without declaration
char sum(char a, char b) {
return a+b+1;
}
void main() {
char * const SCREEN = 0x0400;
SCREEN[0] = f('a', 1);
SCREEN[1] = f('b', 2);
}

View File

@ -0,0 +1,14 @@
// Procedure Declaration - a procedure with paramters&return declared & defined
char sum(char a, char b);
void main() {
char * const SCREEN = 0x0400;
SCREEN[0] = f('a', 1);
SCREEN[1] = f('b', 2);
}
char sum(char a, char b) {
return a+b+1;
}

View File

@ -0,0 +1,19 @@
// Procedure Declaration - a procedure with paramters&return declared multiple times & defined
char sum(char a, char b);
void main() {
char * const SCREEN = 0x0400;
SCREEN[0] = f('a', 1);
SCREEN[1] = f('b', 2);
}
char sum(char x, char y);
char sum(char q, char w) {
return q+w+1;
}
char sum(char z, char r);

View File

@ -0,0 +1,13 @@
// Procedure Declaration - a void procedure declared with empty parenthesis
char f(void);
char f() {
return 7;
}
void main() {
char * const SCREEN = 0x0400;
SCREEN[0] = f();
}

View File

@ -0,0 +1,14 @@
// Procedure Declaration - declaration and definition mismatch of a procedure
char f(char a);
int f(char a) {
return a+1;
}
void main() {
int * const SCREEN = 0x0400;
SCREEN[0] = f('a');
SCREEN[1] = f('b');
}

View File

@ -0,0 +1,17 @@
// Procedure Declaration - two declarations mismatch of a procedure
char f(char a);
int f(char a);
void main() {
char * const SCREEN = 0x0400;
SCREEN[0] = f('a');
SCREEN[1] = f('b');
}
char f(char a) {
return a+1;
}

View File

@ -0,0 +1,20 @@
// Procedure Declaration
char f(char a);
void g();
void h(void);
//void i(char a, ...);
char f(char a) {
return a+1;
}
void main() {
char * const SCREEN = 0x0400;
SCREEN[0] = f('a');
SCREEN[1] = f('b');
}