mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-02-07 20:31:32 +00:00
Added syntax for procedure calling conventions - and a pragma changing the current calling convention. Added two tests. Changed Pass1 procedure-stuff to only handle the PHI calling convention. #316
This commit is contained in:
parent
63dbe9bc5e
commit
95f97d842a
@ -12,7 +12,6 @@ import java.util.List;
|
||||
/** 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;
|
||||
/** The names of the parameters of the procedure. */
|
||||
@ -28,13 +27,53 @@ public class Procedure extends Scope {
|
||||
/** The code segment to put the procedure into. */
|
||||
private String codeSegment;
|
||||
|
||||
public Procedure(String name, SymbolType returnType, Scope parentScope, String codeSegment, String dataSegment) {
|
||||
/** The method for passing parameters and return value to the procedure. */
|
||||
public enum CallingConvension {
|
||||
/** Parameters and return value handled through call PHI-transitions. */
|
||||
PHI_CALL("__phicall"),
|
||||
/** Parameters and return value over the stack. */
|
||||
STACK_CALL("__stackcall");
|
||||
|
||||
private String name;
|
||||
|
||||
CallingConvension(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/** Get a calling convention by name. */
|
||||
public static CallingConvension getCallingConvension(String name) {
|
||||
for(CallingConvension value : CallingConvension.values()) {
|
||||
if(value.getName().equalsIgnoreCase(name)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/** The calling convention used for this procedure. */
|
||||
private CallingConvension callingConvension;
|
||||
|
||||
public Procedure(String name, SymbolType returnType, Scope parentScope, String codeSegment, String dataSegment, CallingConvension callingConvension) {
|
||||
super(name, parentScope, dataSegment);
|
||||
this.returnType = returnType;
|
||||
this.declaredInline = false;
|
||||
this.interruptType = null;
|
||||
this.comments = new ArrayList<>();
|
||||
this.codeSegment = codeSegment;
|
||||
this.callingConvension = callingConvension;
|
||||
}
|
||||
|
||||
public CallingConvension getCallingConvension() {
|
||||
return callingConvension;
|
||||
}
|
||||
|
||||
public void setCallingConvension(CallingConvension callingConvension) {
|
||||
this.callingConvension = callingConvension;
|
||||
}
|
||||
|
||||
public String getCodeSegment() {
|
||||
@ -165,6 +204,9 @@ public class Procedure extends Scope {
|
||||
if(declaredInline) {
|
||||
res.append("inline ");
|
||||
}
|
||||
if(!callingConvension.equals(CallingConvension.PHI_CALL)) {
|
||||
res.append(getCallingConvension().getName()).append(" ");
|
||||
}
|
||||
if(interruptType != null) {
|
||||
res.append("interrupt(" + interruptType + ")");
|
||||
}
|
||||
|
@ -280,8 +280,8 @@ public abstract class Scope implements Symbol, Serializable {
|
||||
return (BlockScope) getSymbol(name);
|
||||
}
|
||||
|
||||
public Procedure addProcedure(String name, SymbolType type, String codeSegment, String dataSegment) {
|
||||
return add(new Procedure(name, type, this, codeSegment, dataSegment));
|
||||
public Procedure addProcedure(String name, SymbolType type, String codeSegment, String dataSegment, Procedure.CallingConvension callingConvension) {
|
||||
return add(new Procedure(name, type, this, codeSegment, dataSegment, callingConvension));
|
||||
}
|
||||
|
||||
public Procedure getProcedure(String name) {
|
||||
|
@ -81,6 +81,8 @@ REGISTER: 'register' ;
|
||||
INLINE: 'inline' ;
|
||||
VOLATILE: 'volatile' ;
|
||||
INTERRUPT: 'interrupt' ;
|
||||
CALLING: 'calling';
|
||||
CALLINGCONVENTION: '__stackcall' | '__phicall' ;
|
||||
IF: 'if' ;
|
||||
ELSE: 'else' ;
|
||||
WHILE: 'while' ;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -54,84 +54,86 @@ REGISTER=53
|
||||
INLINE=54
|
||||
VOLATILE=55
|
||||
INTERRUPT=56
|
||||
IF=57
|
||||
ELSE=58
|
||||
WHILE=59
|
||||
DO=60
|
||||
FOR=61
|
||||
SWITCH=62
|
||||
RETURN=63
|
||||
BREAK=64
|
||||
CONTINUE=65
|
||||
ASM=66
|
||||
DEFAULT=67
|
||||
CASE=68
|
||||
STRUCT=69
|
||||
ENUM=70
|
||||
SIZEOF=71
|
||||
TYPEID=72
|
||||
KICKASM=73
|
||||
RESOURCE=74
|
||||
USES=75
|
||||
CLOBBERS=76
|
||||
BYTES=77
|
||||
CYCLES=78
|
||||
LOGIC_NOT=79
|
||||
SIGNEDNESS=80
|
||||
SIMPLETYPE=81
|
||||
BOOLEAN=82
|
||||
KICKASM_BODY=83
|
||||
STRING=84
|
||||
CHAR=85
|
||||
NUMBER=86
|
||||
NUMFLOAT=87
|
||||
BINFLOAT=88
|
||||
DECFLOAT=89
|
||||
HEXFLOAT=90
|
||||
NUMINT=91
|
||||
BININTEGER=92
|
||||
DECINTEGER=93
|
||||
HEXINTEGER=94
|
||||
NAME=95
|
||||
WS=96
|
||||
COMMENT_LINE=97
|
||||
COMMENT_BLOCK=98
|
||||
ASM_BYTE=99
|
||||
ASM_MNEMONIC=100
|
||||
ASM_IMM=101
|
||||
ASM_COLON=102
|
||||
ASM_COMMA=103
|
||||
ASM_PAR_BEGIN=104
|
||||
ASM_PAR_END=105
|
||||
ASM_BRACKET_BEGIN=106
|
||||
ASM_BRACKET_END=107
|
||||
ASM_DOT=108
|
||||
ASM_SHIFT_LEFT=109
|
||||
ASM_SHIFT_RIGHT=110
|
||||
ASM_PLUS=111
|
||||
ASM_MINUS=112
|
||||
ASM_LESS_THAN=113
|
||||
ASM_GREATER_THAN=114
|
||||
ASM_MULTIPLY=115
|
||||
ASM_DIVIDE=116
|
||||
ASM_CURLY_BEGIN=117
|
||||
ASM_CURLY_END=118
|
||||
ASM_NUMBER=119
|
||||
ASM_NUMFLOAT=120
|
||||
ASM_BINFLOAT=121
|
||||
ASM_DECFLOAT=122
|
||||
ASM_HEXFLOAT=123
|
||||
ASM_NUMINT=124
|
||||
ASM_BININTEGER=125
|
||||
ASM_DECINTEGER=126
|
||||
ASM_HEXINTEGER=127
|
||||
ASM_CHAR=128
|
||||
ASM_MULTI_REL=129
|
||||
ASM_MULTI_NAME=130
|
||||
ASM_NAME=131
|
||||
ASM_WS=132
|
||||
ASM_COMMENT_LINE=133
|
||||
ASM_COMMENT_BLOCK=134
|
||||
CALLING=57
|
||||
CALLINGCONVENTION=58
|
||||
IF=59
|
||||
ELSE=60
|
||||
WHILE=61
|
||||
DO=62
|
||||
FOR=63
|
||||
SWITCH=64
|
||||
RETURN=65
|
||||
BREAK=66
|
||||
CONTINUE=67
|
||||
ASM=68
|
||||
DEFAULT=69
|
||||
CASE=70
|
||||
STRUCT=71
|
||||
ENUM=72
|
||||
SIZEOF=73
|
||||
TYPEID=74
|
||||
KICKASM=75
|
||||
RESOURCE=76
|
||||
USES=77
|
||||
CLOBBERS=78
|
||||
BYTES=79
|
||||
CYCLES=80
|
||||
LOGIC_NOT=81
|
||||
SIGNEDNESS=82
|
||||
SIMPLETYPE=83
|
||||
BOOLEAN=84
|
||||
KICKASM_BODY=85
|
||||
STRING=86
|
||||
CHAR=87
|
||||
NUMBER=88
|
||||
NUMFLOAT=89
|
||||
BINFLOAT=90
|
||||
DECFLOAT=91
|
||||
HEXFLOAT=92
|
||||
NUMINT=93
|
||||
BININTEGER=94
|
||||
DECINTEGER=95
|
||||
HEXINTEGER=96
|
||||
NAME=97
|
||||
WS=98
|
||||
COMMENT_LINE=99
|
||||
COMMENT_BLOCK=100
|
||||
ASM_BYTE=101
|
||||
ASM_MNEMONIC=102
|
||||
ASM_IMM=103
|
||||
ASM_COLON=104
|
||||
ASM_COMMA=105
|
||||
ASM_PAR_BEGIN=106
|
||||
ASM_PAR_END=107
|
||||
ASM_BRACKET_BEGIN=108
|
||||
ASM_BRACKET_END=109
|
||||
ASM_DOT=110
|
||||
ASM_SHIFT_LEFT=111
|
||||
ASM_SHIFT_RIGHT=112
|
||||
ASM_PLUS=113
|
||||
ASM_MINUS=114
|
||||
ASM_LESS_THAN=115
|
||||
ASM_GREATER_THAN=116
|
||||
ASM_MULTIPLY=117
|
||||
ASM_DIVIDE=118
|
||||
ASM_CURLY_BEGIN=119
|
||||
ASM_CURLY_END=120
|
||||
ASM_NUMBER=121
|
||||
ASM_NUMFLOAT=122
|
||||
ASM_BINFLOAT=123
|
||||
ASM_DECFLOAT=124
|
||||
ASM_HEXFLOAT=125
|
||||
ASM_NUMINT=126
|
||||
ASM_BININTEGER=127
|
||||
ASM_DECINTEGER=128
|
||||
ASM_HEXINTEGER=129
|
||||
ASM_CHAR=130
|
||||
ASM_MULTI_REL=131
|
||||
ASM_MULTI_NAME=132
|
||||
ASM_NAME=133
|
||||
ASM_WS=134
|
||||
ASM_COMMENT_LINE=135
|
||||
ASM_COMMENT_BLOCK=136
|
||||
';'=8
|
||||
'..'=11
|
||||
'?'=12
|
||||
@ -169,28 +171,29 @@ ASM_COMMENT_BLOCK=134
|
||||
'inline'=54
|
||||
'volatile'=55
|
||||
'interrupt'=56
|
||||
'if'=57
|
||||
'else'=58
|
||||
'while'=59
|
||||
'do'=60
|
||||
'for'=61
|
||||
'switch'=62
|
||||
'return'=63
|
||||
'break'=64
|
||||
'continue'=65
|
||||
'asm'=66
|
||||
'default'=67
|
||||
'case'=68
|
||||
'struct'=69
|
||||
'enum'=70
|
||||
'sizeof'=71
|
||||
'typeid'=72
|
||||
'kickasm'=73
|
||||
'resource'=74
|
||||
'uses'=75
|
||||
'clobbers'=76
|
||||
'bytes'=77
|
||||
'cycles'=78
|
||||
'!'=79
|
||||
'.byte'=99
|
||||
'#'=101
|
||||
'calling'=57
|
||||
'if'=59
|
||||
'else'=60
|
||||
'while'=61
|
||||
'do'=62
|
||||
'for'=63
|
||||
'switch'=64
|
||||
'return'=65
|
||||
'break'=66
|
||||
'continue'=67
|
||||
'asm'=68
|
||||
'default'=69
|
||||
'case'=70
|
||||
'struct'=71
|
||||
'enum'=72
|
||||
'sizeof'=73
|
||||
'typeid'=74
|
||||
'kickasm'=75
|
||||
'resource'=76
|
||||
'uses'=77
|
||||
'clobbers'=78
|
||||
'bytes'=79
|
||||
'cycles'=80
|
||||
'!'=81
|
||||
'.byte'=101
|
||||
'#'=103
|
||||
|
@ -91,6 +91,7 @@ globalDirective
|
||||
| (PRAGMA CODESEG) PAR_BEGIN NAME PAR_END #globalDirectiveCodeSeg
|
||||
| (PRAGMA DATASEG) PAR_BEGIN NAME PAR_END #globalDirectiveDataSeg
|
||||
| (PRAGMA ENCODING) PAR_BEGIN NAME PAR_END #globalDirectiveEncoding
|
||||
| (PRAGMA CALLING) PAR_BEGIN CALLINGCONVENTION PAR_END #globalDirectiveCalling
|
||||
;
|
||||
|
||||
directive
|
||||
@ -103,6 +104,7 @@ directive
|
||||
| VOLATILE #directiveVolatile
|
||||
| INTERRUPT ( PAR_BEGIN NAME PAR_END )? #directiveInterrupt
|
||||
| RESERVE PAR_BEGIN NUMBER ( COMMA NUMBER )* PAR_END #directiveReserveZp
|
||||
| CALLINGCONVENTION #directiveCallingConvention
|
||||
;
|
||||
|
||||
stmtSeq
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -54,84 +54,86 @@ REGISTER=53
|
||||
INLINE=54
|
||||
VOLATILE=55
|
||||
INTERRUPT=56
|
||||
IF=57
|
||||
ELSE=58
|
||||
WHILE=59
|
||||
DO=60
|
||||
FOR=61
|
||||
SWITCH=62
|
||||
RETURN=63
|
||||
BREAK=64
|
||||
CONTINUE=65
|
||||
ASM=66
|
||||
DEFAULT=67
|
||||
CASE=68
|
||||
STRUCT=69
|
||||
ENUM=70
|
||||
SIZEOF=71
|
||||
TYPEID=72
|
||||
KICKASM=73
|
||||
RESOURCE=74
|
||||
USES=75
|
||||
CLOBBERS=76
|
||||
BYTES=77
|
||||
CYCLES=78
|
||||
LOGIC_NOT=79
|
||||
SIGNEDNESS=80
|
||||
SIMPLETYPE=81
|
||||
BOOLEAN=82
|
||||
KICKASM_BODY=83
|
||||
STRING=84
|
||||
CHAR=85
|
||||
NUMBER=86
|
||||
NUMFLOAT=87
|
||||
BINFLOAT=88
|
||||
DECFLOAT=89
|
||||
HEXFLOAT=90
|
||||
NUMINT=91
|
||||
BININTEGER=92
|
||||
DECINTEGER=93
|
||||
HEXINTEGER=94
|
||||
NAME=95
|
||||
WS=96
|
||||
COMMENT_LINE=97
|
||||
COMMENT_BLOCK=98
|
||||
ASM_BYTE=99
|
||||
ASM_MNEMONIC=100
|
||||
ASM_IMM=101
|
||||
ASM_COLON=102
|
||||
ASM_COMMA=103
|
||||
ASM_PAR_BEGIN=104
|
||||
ASM_PAR_END=105
|
||||
ASM_BRACKET_BEGIN=106
|
||||
ASM_BRACKET_END=107
|
||||
ASM_DOT=108
|
||||
ASM_SHIFT_LEFT=109
|
||||
ASM_SHIFT_RIGHT=110
|
||||
ASM_PLUS=111
|
||||
ASM_MINUS=112
|
||||
ASM_LESS_THAN=113
|
||||
ASM_GREATER_THAN=114
|
||||
ASM_MULTIPLY=115
|
||||
ASM_DIVIDE=116
|
||||
ASM_CURLY_BEGIN=117
|
||||
ASM_CURLY_END=118
|
||||
ASM_NUMBER=119
|
||||
ASM_NUMFLOAT=120
|
||||
ASM_BINFLOAT=121
|
||||
ASM_DECFLOAT=122
|
||||
ASM_HEXFLOAT=123
|
||||
ASM_NUMINT=124
|
||||
ASM_BININTEGER=125
|
||||
ASM_DECINTEGER=126
|
||||
ASM_HEXINTEGER=127
|
||||
ASM_CHAR=128
|
||||
ASM_MULTI_REL=129
|
||||
ASM_MULTI_NAME=130
|
||||
ASM_NAME=131
|
||||
ASM_WS=132
|
||||
ASM_COMMENT_LINE=133
|
||||
ASM_COMMENT_BLOCK=134
|
||||
CALLING=57
|
||||
CALLINGCONVENTION=58
|
||||
IF=59
|
||||
ELSE=60
|
||||
WHILE=61
|
||||
DO=62
|
||||
FOR=63
|
||||
SWITCH=64
|
||||
RETURN=65
|
||||
BREAK=66
|
||||
CONTINUE=67
|
||||
ASM=68
|
||||
DEFAULT=69
|
||||
CASE=70
|
||||
STRUCT=71
|
||||
ENUM=72
|
||||
SIZEOF=73
|
||||
TYPEID=74
|
||||
KICKASM=75
|
||||
RESOURCE=76
|
||||
USES=77
|
||||
CLOBBERS=78
|
||||
BYTES=79
|
||||
CYCLES=80
|
||||
LOGIC_NOT=81
|
||||
SIGNEDNESS=82
|
||||
SIMPLETYPE=83
|
||||
BOOLEAN=84
|
||||
KICKASM_BODY=85
|
||||
STRING=86
|
||||
CHAR=87
|
||||
NUMBER=88
|
||||
NUMFLOAT=89
|
||||
BINFLOAT=90
|
||||
DECFLOAT=91
|
||||
HEXFLOAT=92
|
||||
NUMINT=93
|
||||
BININTEGER=94
|
||||
DECINTEGER=95
|
||||
HEXINTEGER=96
|
||||
NAME=97
|
||||
WS=98
|
||||
COMMENT_LINE=99
|
||||
COMMENT_BLOCK=100
|
||||
ASM_BYTE=101
|
||||
ASM_MNEMONIC=102
|
||||
ASM_IMM=103
|
||||
ASM_COLON=104
|
||||
ASM_COMMA=105
|
||||
ASM_PAR_BEGIN=106
|
||||
ASM_PAR_END=107
|
||||
ASM_BRACKET_BEGIN=108
|
||||
ASM_BRACKET_END=109
|
||||
ASM_DOT=110
|
||||
ASM_SHIFT_LEFT=111
|
||||
ASM_SHIFT_RIGHT=112
|
||||
ASM_PLUS=113
|
||||
ASM_MINUS=114
|
||||
ASM_LESS_THAN=115
|
||||
ASM_GREATER_THAN=116
|
||||
ASM_MULTIPLY=117
|
||||
ASM_DIVIDE=118
|
||||
ASM_CURLY_BEGIN=119
|
||||
ASM_CURLY_END=120
|
||||
ASM_NUMBER=121
|
||||
ASM_NUMFLOAT=122
|
||||
ASM_BINFLOAT=123
|
||||
ASM_DECFLOAT=124
|
||||
ASM_HEXFLOAT=125
|
||||
ASM_NUMINT=126
|
||||
ASM_BININTEGER=127
|
||||
ASM_DECINTEGER=128
|
||||
ASM_HEXINTEGER=129
|
||||
ASM_CHAR=130
|
||||
ASM_MULTI_REL=131
|
||||
ASM_MULTI_NAME=132
|
||||
ASM_NAME=133
|
||||
ASM_WS=134
|
||||
ASM_COMMENT_LINE=135
|
||||
ASM_COMMENT_BLOCK=136
|
||||
';'=8
|
||||
'..'=11
|
||||
'?'=12
|
||||
@ -169,28 +171,29 @@ ASM_COMMENT_BLOCK=134
|
||||
'inline'=54
|
||||
'volatile'=55
|
||||
'interrupt'=56
|
||||
'if'=57
|
||||
'else'=58
|
||||
'while'=59
|
||||
'do'=60
|
||||
'for'=61
|
||||
'switch'=62
|
||||
'return'=63
|
||||
'break'=64
|
||||
'continue'=65
|
||||
'asm'=66
|
||||
'default'=67
|
||||
'case'=68
|
||||
'struct'=69
|
||||
'enum'=70
|
||||
'sizeof'=71
|
||||
'typeid'=72
|
||||
'kickasm'=73
|
||||
'resource'=74
|
||||
'uses'=75
|
||||
'clobbers'=76
|
||||
'bytes'=77
|
||||
'cycles'=78
|
||||
'!'=79
|
||||
'.byte'=99
|
||||
'#'=101
|
||||
'calling'=57
|
||||
'if'=59
|
||||
'else'=60
|
||||
'while'=61
|
||||
'do'=62
|
||||
'for'=63
|
||||
'switch'=64
|
||||
'return'=65
|
||||
'break'=66
|
||||
'continue'=67
|
||||
'asm'=68
|
||||
'default'=69
|
||||
'case'=70
|
||||
'struct'=71
|
||||
'enum'=72
|
||||
'sizeof'=73
|
||||
'typeid'=74
|
||||
'kickasm'=75
|
||||
'resource'=76
|
||||
'uses'=77
|
||||
'clobbers'=78
|
||||
'bytes'=79
|
||||
'cycles'=80
|
||||
'!'=81
|
||||
'.byte'=101
|
||||
'#'=103
|
||||
|
@ -301,6 +301,18 @@ public class KickCParserBaseListener implements KickCParserListener {
|
||||
* <p>The default implementation does nothing.</p>
|
||||
*/
|
||||
@Override public void exitGlobalDirectiveEncoding(KickCParser.GlobalDirectiveEncodingContext ctx) { }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation does nothing.</p>
|
||||
*/
|
||||
@Override public void enterGlobalDirectiveCalling(KickCParser.GlobalDirectiveCallingContext ctx) { }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation does nothing.</p>
|
||||
*/
|
||||
@Override public void exitGlobalDirectiveCalling(KickCParser.GlobalDirectiveCallingContext ctx) { }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
@ -409,6 +421,18 @@ public class KickCParserBaseListener implements KickCParserListener {
|
||||
* <p>The default implementation does nothing.</p>
|
||||
*/
|
||||
@Override public void exitDirectiveReserveZp(KickCParser.DirectiveReserveZpContext ctx) { }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation does nothing.</p>
|
||||
*/
|
||||
@Override public void enterDirectiveCallingConvention(KickCParser.DirectiveCallingConventionContext ctx) { }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation does nothing.</p>
|
||||
*/
|
||||
@Override public void exitDirectiveCallingConvention(KickCParser.DirectiveCallingConventionContext ctx) { }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
|
@ -181,6 +181,13 @@ public class KickCParserBaseVisitor<T> extends AbstractParseTreeVisitor<T> imple
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitGlobalDirectiveEncoding(KickCParser.GlobalDirectiveEncodingContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitGlobalDirectiveCalling(KickCParser.GlobalDirectiveCallingContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
@ -244,6 +251,13 @@ public class KickCParserBaseVisitor<T> extends AbstractParseTreeVisitor<T> imple
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitDirectiveReserveZp(KickCParser.DirectiveReserveZpContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitDirectiveCallingConvention(KickCParser.DirectiveCallingConventionContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
|
@ -273,6 +273,18 @@ public interface KickCParserListener extends ParseTreeListener {
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
void exitGlobalDirectiveEncoding(KickCParser.GlobalDirectiveEncodingContext ctx);
|
||||
/**
|
||||
* Enter a parse tree produced by the {@code globalDirectiveCalling}
|
||||
* labeled alternative in {@link KickCParser#globalDirective}.
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
void enterGlobalDirectiveCalling(KickCParser.GlobalDirectiveCallingContext ctx);
|
||||
/**
|
||||
* Exit a parse tree produced by the {@code globalDirectiveCalling}
|
||||
* labeled alternative in {@link KickCParser#globalDirective}.
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
void exitGlobalDirectiveCalling(KickCParser.GlobalDirectiveCallingContext ctx);
|
||||
/**
|
||||
* Enter a parse tree produced by the {@code directiveConst}
|
||||
* labeled alternative in {@link KickCParser#directive}.
|
||||
@ -381,6 +393,18 @@ public interface KickCParserListener extends ParseTreeListener {
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
void exitDirectiveReserveZp(KickCParser.DirectiveReserveZpContext ctx);
|
||||
/**
|
||||
* Enter a parse tree produced by the {@code directiveCallingConvention}
|
||||
* labeled alternative in {@link KickCParser#directive}.
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
void enterDirectiveCallingConvention(KickCParser.DirectiveCallingConventionContext ctx);
|
||||
/**
|
||||
* Exit a parse tree produced by the {@code directiveCallingConvention}
|
||||
* labeled alternative in {@link KickCParser#directive}.
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
void exitDirectiveCallingConvention(KickCParser.DirectiveCallingConventionContext ctx);
|
||||
/**
|
||||
* Enter a parse tree produced by {@link KickCParser#stmtSeq}.
|
||||
* @param ctx the parse tree
|
||||
|
@ -168,6 +168,13 @@ public interface KickCParserVisitor<T> extends ParseTreeVisitor<T> {
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitGlobalDirectiveEncoding(KickCParser.GlobalDirectiveEncodingContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by the {@code globalDirectiveCalling}
|
||||
* labeled alternative in {@link KickCParser#globalDirective}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitGlobalDirectiveCalling(KickCParser.GlobalDirectiveCallingContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by the {@code directiveConst}
|
||||
* labeled alternative in {@link KickCParser#directive}.
|
||||
@ -231,6 +238,13 @@ public interface KickCParserVisitor<T> extends ParseTreeVisitor<T> {
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitDirectiveReserveZp(KickCParser.DirectiveReserveZpContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by the {@code directiveCallingConvention}
|
||||
* labeled alternative in {@link KickCParser#directive}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitDirectiveCallingConvention(KickCParser.DirectiveCallingConventionContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by {@link KickCParser#stmtSeq}.
|
||||
* @param ctx the parse tree
|
||||
|
@ -3,7 +3,6 @@ package dk.camelot64.kickc.passes;
|
||||
import dk.camelot64.kickc.NumberParser;
|
||||
import dk.camelot64.kickc.SourceLoader;
|
||||
import dk.camelot64.kickc.asm.AsmClobber;
|
||||
import dk.camelot64.kickc.fragment.AsmFragmentTemplateSynthesizer;
|
||||
import dk.camelot64.kickc.model.*;
|
||||
import dk.camelot64.kickc.model.operators.*;
|
||||
import dk.camelot64.kickc.model.statements.*;
|
||||
@ -159,6 +158,18 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
return null;
|
||||
}
|
||||
|
||||
/** The current calling convention for procedures. */
|
||||
Procedure.CallingConvension currentCallingConvention = Procedure.CallingConvension.PHI_CALL;
|
||||
|
||||
@Override
|
||||
public Object visitGlobalDirectiveCalling(KickCParser.GlobalDirectiveCallingContext ctx) {
|
||||
Procedure.CallingConvension callingConvension = Procedure.CallingConvension.getCallingConvension(ctx.CALLINGCONVENTION().getText());
|
||||
if(callingConvension!=null) {
|
||||
currentCallingConvention = callingConvension;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** The current code segment - if null the default segment is used. */
|
||||
String currentCodeSegment = Scope.SEGMENT_CODE_DEFAULT;
|
||||
|
||||
@ -183,7 +194,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
SymbolType type = declVarType;
|
||||
List<Directive> directives = declVarDirectives;
|
||||
String name = ctx.NAME().getText();
|
||||
Procedure procedure = getCurrentScope().addProcedure(name, type, currentCodeSegment, currentDataSegment);
|
||||
Procedure procedure = getCurrentScope().addProcedure(name, type, currentCodeSegment, currentDataSegment, currentCallingConvention);
|
||||
addDirectives(procedure, directives, StatementSource.procedureBegin(ctx));
|
||||
procedure.setComments(ensureUnusedComments(getCommentsSymbol(ctx)));
|
||||
scopeStack.push(procedure);
|
||||
@ -668,24 +679,24 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
lValue.setDeclaredExport(true);
|
||||
} else if(directive instanceof DirectiveAlign) {
|
||||
if(type instanceof SymbolTypeArray || type.equals(SymbolType.STRING)) {
|
||||
lValue.setDeclaredAlignment(((DirectiveAlign) directive).getAlignment());
|
||||
lValue.setDeclaredAlignment(((DirectiveAlign) directive).alignment);
|
||||
} else {
|
||||
throw new CompileError("Error! Cannot align variable that is not a string or an array " + lValue.toString(program), source);
|
||||
}
|
||||
} else if(directive instanceof DirectiveRegister) {
|
||||
DirectiveRegister directiveRegister = (DirectiveRegister) directive;
|
||||
if(directiveRegister.getName() != null) {
|
||||
if(directiveRegister.name != null) {
|
||||
// Ignore register directive without parameter (all variables are placed on ZP and attempted register uplift anyways)
|
||||
Registers.Register register = Registers.getRegister(directiveRegister.getName());
|
||||
Registers.Register register = Registers.getRegister(directiveRegister.name);
|
||||
if(register == null) {
|
||||
throw new CompileError("Error! Unknown register " + directiveRegister.getName(), source);
|
||||
throw new CompileError("Error! Unknown register " + directiveRegister.name, source);
|
||||
}
|
||||
lValue.setDeclaredRegister(register);
|
||||
} else if(directiveRegister.getAddress() != null) {
|
||||
} else if(directiveRegister.address != null) {
|
||||
// Allocate to specific address
|
||||
Long address = ((DirectiveRegister) directive).address;
|
||||
if(address>255) {
|
||||
throw new CompileError("Error! Register not on zeropage " + directiveRegister.getAddress(), source);
|
||||
throw new CompileError("Error! Register not on zeropage " + directiveRegister.address, source);
|
||||
}
|
||||
Registers.Register register = new Registers.RegisterZpDeclared(address.intValue());
|
||||
lValue.setDeclaredRegister(register);
|
||||
@ -720,10 +731,12 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
for(Directive directive : directives) {
|
||||
if(directive instanceof DirectiveInline) {
|
||||
procedure.setDeclaredInline(true);
|
||||
} else if(directive instanceof DirectiveCallingConvention) {
|
||||
procedure.setCallingConvension(((DirectiveCallingConvention) directive).callingConvension);
|
||||
} else if(directive instanceof DirectiveInterrupt) {
|
||||
procedure.setInterruptType(((DirectiveInterrupt) directive).interruptType);
|
||||
} else if(directive instanceof DirectiveReserveZp) {
|
||||
procedure.setReservedZps(((DirectiveReserveZp) directive).getReservedZp());
|
||||
procedure.setReservedZps(((DirectiveReserveZp) directive).reservedZp);
|
||||
} else {
|
||||
throw new CompileError("Unsupported function directive " + directive, source);
|
||||
}
|
||||
@ -771,6 +784,12 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
return new DirectiveInterrupt(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Directive visitDirectiveCallingConvention(KickCParser.DirectiveCallingConventionContext ctx) {
|
||||
Procedure.CallingConvension callingConvension = Procedure.CallingConvension.getCallingConvension(ctx.getText());
|
||||
return new DirectiveCallingConvention(callingConvension);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Directive visitDirectiveAlign(KickCParser.DirectiveAlignContext ctx) {
|
||||
Number alignment = NumberParser.parseLiteral(ctx.NUMBER().getText());
|
||||
@ -2136,6 +2155,16 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
private static class DirectiveConst implements Directive {
|
||||
}
|
||||
|
||||
/** Function with specific declared calling convention. */
|
||||
private static class DirectiveCallingConvention implements Directive {
|
||||
Procedure.CallingConvension callingConvension;
|
||||
|
||||
public DirectiveCallingConvention(Procedure.CallingConvension callingConvension) {
|
||||
this.callingConvension = callingConvension;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Function declared inline. */
|
||||
private static class DirectiveInline implements Directive {
|
||||
}
|
||||
@ -2165,9 +2194,6 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
this.alignment = alignment;
|
||||
}
|
||||
|
||||
public int getAlignment() {
|
||||
return alignment;
|
||||
}
|
||||
}
|
||||
|
||||
/** Variable register allocation. */
|
||||
@ -2185,13 +2211,6 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Long getAddress() {
|
||||
return address;
|
||||
}
|
||||
}
|
||||
|
||||
/** Reservation of zero-page addresses */
|
||||
@ -2202,10 +2221,6 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
this.reservedZp = reservedZp;
|
||||
}
|
||||
|
||||
public List<Integer> getReservedZp() {
|
||||
return reservedZp;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -12,7 +12,7 @@ import dk.camelot64.kickc.model.values.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/** Pass that modifies a control flow graph to call procedures by passing parameters through registers */
|
||||
/** Pass that modifies a control flow graph to call {@link dk.camelot64.kickc.model.symbols.Procedure.CallingConvension#PHI_CALL} procedures by passing parameters through registers */
|
||||
public class Pass1ProcedureCallParameters extends ControlFlowGraphCopyVisitor {
|
||||
|
||||
private Program program;
|
||||
@ -49,10 +49,16 @@ public class Pass1ProcedureCallParameters extends ControlFlowGraphCopyVisitor {
|
||||
|
||||
@Override
|
||||
public StatementCall visitCall(StatementCall origCall) {
|
||||
// Procedure strategy implemented is currently variable-based transfer of parameters/return values
|
||||
// Generate parameter passing assignments
|
||||
ProcedureRef procedureRef = origCall.getProcedure();
|
||||
Procedure procedure = getScope().getProcedure(procedureRef);
|
||||
// If not PHI-call - skip
|
||||
if(!Procedure.CallingConvension.PHI_CALL.equals(procedure.getCallingConvension())) {
|
||||
StatementCall copyCall = super.visitCall(origCall);
|
||||
copyCall.setProcedure(procedureRef);
|
||||
return copyCall;
|
||||
}
|
||||
|
||||
List<Variable> parameterDecls = procedure.getParameters();
|
||||
List<RValue> parameterValues = origCall.getParameters();
|
||||
if(parameterDecls.size()!=parameterValues.size()) {
|
||||
@ -120,6 +126,10 @@ public class Pass1ProcedureCallParameters extends ControlFlowGraphCopyVisitor {
|
||||
ControlFlowBlock currentBlock = getCurrentBlock();
|
||||
String currentProcName = currentBlock.getLabel().getScopeNames();
|
||||
Procedure procedure = program.getScope().getProcedure(currentProcName);
|
||||
// If not PHI-call - skip
|
||||
if(!Procedure.CallingConvension.PHI_CALL.equals(procedure.getCallingConvension()))
|
||||
return super.visitReturn(orig);
|
||||
|
||||
// Add self-assignments for all variables modified in the procedure
|
||||
Set<VariableRef> modifiedVars = program.getProcedureModifiedVars().getModifiedVars(procedure.getRef());
|
||||
for(VariableRef modifiedVar : modifiedVars) {
|
||||
|
@ -12,7 +12,7 @@ import java.util.ArrayList;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Pass that modifies a control flow graph to call procedures by passing return value through registers
|
||||
* Pass that modifies a control flow graph to call procedures by passing return value through registers for {@link dk.camelot64.kickc.model.symbols.Procedure.CallingConvension#PHI_CALL}
|
||||
*/
|
||||
public class Pass1ProcedureCallsReturnValue extends ControlFlowGraphCopyVisitor {
|
||||
|
||||
@ -33,6 +33,13 @@ public class Pass1ProcedureCallsReturnValue extends ControlFlowGraphCopyVisitor
|
||||
// Generate return value assignment
|
||||
ProcedureRef procedureRef = origCall.getProcedure();
|
||||
Procedure procedure = program.getScope().getProcedure(procedureRef);
|
||||
// If not PHI-call - skip
|
||||
if(!Procedure.CallingConvension.PHI_CALL.equals(procedure.getCallingConvension())) {
|
||||
StatementCall copyCall = super.visitCall(origCall);
|
||||
copyCall.setProcedure(procedureRef);
|
||||
return copyCall;
|
||||
}
|
||||
|
||||
String procedureName = origCall.getProcedureName();
|
||||
StatementCall copyCall = new StatementCall(null, procedureName, null, origCall.getSource(), origCall.getComments());
|
||||
copyCall.setProcedure(procedureRef);
|
||||
@ -106,6 +113,13 @@ public class Pass1ProcedureCallsReturnValue extends ControlFlowGraphCopyVisitor
|
||||
|
||||
@Override
|
||||
public StatementReturn visitReturn(StatementReturn orig) {
|
||||
ControlFlowBlock currentBlock = getCurrentBlock();
|
||||
String currentProcName = currentBlock.getLabel().getScopeNames();
|
||||
Procedure procedure = program.getScope().getProcedure(currentProcName);
|
||||
// If not PHI-call - skip
|
||||
if(!Procedure.CallingConvension.PHI_CALL.equals(procedure.getCallingConvension()))
|
||||
return super.visitReturn(orig);
|
||||
|
||||
addStatementToCurrentBlock(new StatementReturn(null, orig.getSource(), orig.getComments()));
|
||||
return null;
|
||||
}
|
||||
|
@ -35,6 +35,18 @@ public class TestPrograms {
|
||||
public TestPrograms() {
|
||||
}
|
||||
|
||||
/*
|
||||
@Test
|
||||
public void testProcedureCallingConventionStack1() throws IOException, URISyntaxException {
|
||||
compileAndCompare("procedure-callingconvention-stack-1", log());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProcedureCallingConventionStack0() throws IOException, URISyntaxException {
|
||||
compileAndCompare("procedure-callingconvention-stack-0", log());
|
||||
}
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testStringPointerProblem() throws IOException, URISyntaxException {
|
||||
compileAndCompare("string-pointer-problem");
|
||||
|
11
src/test/kc/procedure-callingconvention-stack-0.kc
Normal file
11
src/test/kc/procedure-callingconvention-stack-0.kc
Normal file
@ -0,0 +1,11 @@
|
||||
// Test a procedure with calling convention stack
|
||||
|
||||
const char* SCREEN = 0x0400;
|
||||
|
||||
void main(void) {
|
||||
SCREEN[0] = plus('0', 7);
|
||||
}
|
||||
|
||||
char __stackcall plus(char a, char b) {
|
||||
return a+b;
|
||||
}
|
13
src/test/kc/procedure-callingconvention-stack-1.kc
Normal file
13
src/test/kc/procedure-callingconvention-stack-1.kc
Normal file
@ -0,0 +1,13 @@
|
||||
// Test a procedure with calling convention stack
|
||||
|
||||
const char* SCREEN = 0x0400;
|
||||
|
||||
void main(void) {
|
||||
SCREEN[0] = plus('0', 7);
|
||||
}
|
||||
|
||||
#pragma calling(__stackcall)
|
||||
|
||||
char plus(char a, char b) {
|
||||
return a+b;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user