mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-08-08 13:25:12 +00:00
Parsing implementation of
#pragma far_seg(segment, bank, call_prepare, call_execute, call_finalize) with variable parameters, other option is: #pragma far_seg(segment, bank) After parsing a FarSegment HashMap is created that is later used for the far or near call determination. Added currentFarSegment variable. Added near in KickCLexer for __near directive. Added far_seg and near_seg #pragma keywords. near_seg is to be parsed in the next commit.
This commit is contained in:
@@ -76,6 +76,7 @@ ADDRESS: '__address' ;
|
|||||||
ADDRESS_ZEROPAGE: '__zp' ;
|
ADDRESS_ZEROPAGE: '__zp' ;
|
||||||
ADDRESS_MAINMEM: '__mem' ;
|
ADDRESS_MAINMEM: '__mem' ;
|
||||||
FAR: '__far' ;
|
FAR: '__far' ;
|
||||||
|
NEAR: '__near' ;
|
||||||
FORM_SSA: '__ssa' ;
|
FORM_SSA: '__ssa' ;
|
||||||
FORM_MA: '__ma' ;
|
FORM_MA: '__ma' ;
|
||||||
INTRINSIC: '__intrinsic' ;
|
INTRINSIC: '__intrinsic' ;
|
||||||
|
32
src/main/java/dk/camelot64/kickc/model/FarSegment.java
Normal file
32
src/main/java/dk/camelot64/kickc/model/FarSegment.java
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
package dk.camelot64.kickc.model;
|
||||||
|
|
||||||
|
import dk.camelot64.kickc.model.symbols.Procedure;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/** A far segment. */
|
||||||
|
public class FarSegment {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
private Integer bank;
|
||||||
|
private String call_prepare;
|
||||||
|
private String call_execute;
|
||||||
|
private String call_finalize;
|
||||||
|
|
||||||
|
public FarSegment(String name, Integer bank, String call_prepare, String call_execute, String call_finalize) {
|
||||||
|
this.name = name;
|
||||||
|
this.bank = bank;
|
||||||
|
this.call_prepare = call_prepare;
|
||||||
|
this.call_execute = call_execute;
|
||||||
|
this.call_finalize = call_finalize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Integer getBank() {
|
||||||
|
return bank;
|
||||||
|
}
|
||||||
|
}
|
@@ -16,6 +16,8 @@ public abstract class Scope implements Symbol {
|
|||||||
public static final String SEGMENT_CODE_DEFAULT = "Code";
|
public static final String SEGMENT_CODE_DEFAULT = "Code";
|
||||||
/** The default data segment. */
|
/** The default data segment. */
|
||||||
public static final String SEGMENT_DATA_DEFAULT = "Data";
|
public static final String SEGMENT_DATA_DEFAULT = "Data";
|
||||||
|
/** The default far segment. */
|
||||||
|
public static final String SEGMENT_FAR_DEFAULT = "";
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
private HashMap<String, Symbol> symbols;
|
private HashMap<String, Symbol> symbols;
|
||||||
|
@@ -106,6 +106,14 @@ public class CParser {
|
|||||||
* The resource-file is copied to the output directory when compiling.
|
* The resource-file is copied to the output directory when compiling.
|
||||||
*/
|
*/
|
||||||
public static final String PRAGMA_RESOURCE = "resource";
|
public static final String PRAGMA_RESOURCE = "resource";
|
||||||
|
/**
|
||||||
|
* #pragma far_seg(...) specifies the scope of the sequent functions to be far. Segments are defined in the linker file.
|
||||||
|
*/
|
||||||
|
public static final String PRAGMA_FAR_SEG = "far_seg";
|
||||||
|
/**
|
||||||
|
* #pragma near_seg specifies the scope of the sequent functions to be near. Segments are defined in the linker file.
|
||||||
|
*/
|
||||||
|
public static final String PRAGMA_NEAR_SEG = "near_seg";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Program.
|
* The Program.
|
||||||
|
@@ -43,6 +43,10 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||||||
private final Stack<Scope> scopeStack;
|
private final Stack<Scope> scopeStack;
|
||||||
/** All #pragma constructor_for() statements. Collected during parsing and handled by {@link #generate()} before returning. */
|
/** All #pragma constructor_for() statements. Collected during parsing and handled by {@link #generate()} before returning. */
|
||||||
private final List<KickCParser.PragmaContext> pragmaConstructorFors;
|
private final List<KickCParser.PragmaContext> pragmaConstructorFors;
|
||||||
|
/** All #pragma code segments. Collected during parsing. These are used by the far_seg pragmas to validate if the code segment exists during compilation.*/
|
||||||
|
private final Map<String, KickCParser.PragmaContext> pragmaCodeSegs;
|
||||||
|
/** All #pragma far segments. Collected during parsing. These are used to compare with the current currentFarSegment to decide a near or a far call, and to keep inline calling routines.*/
|
||||||
|
private final Map<String, FarSegment> pragmaFarSegs;
|
||||||
|
|
||||||
|
|
||||||
public Pass0GenerateStatementSequence(CParser cParser, KickCParser.FileContext fileCtx, Program program, Procedure.CallingConvention initialCallingConvention, StringEncoding defaultEncoding, String defaultInterruptType) {
|
public Pass0GenerateStatementSequence(CParser cParser, KickCParser.FileContext fileCtx, Program program, Procedure.CallingConvention initialCallingConvention, StringEncoding defaultEncoding, String defaultInterruptType) {
|
||||||
@@ -53,6 +57,8 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||||||
this.currentCallingConvention = initialCallingConvention;
|
this.currentCallingConvention = initialCallingConvention;
|
||||||
this.currentEncoding = defaultEncoding;
|
this.currentEncoding = defaultEncoding;
|
||||||
this.pragmaConstructorFors = new ArrayList();
|
this.pragmaConstructorFors = new ArrayList();
|
||||||
|
this.pragmaCodeSegs = new HashMap<>(); // Used to collect all pragma code segments.
|
||||||
|
this.pragmaFarSegs = new HashMap<>(); // Used to collect all pragma far segments.
|
||||||
this.currentInterruptType = defaultInterruptType;
|
this.currentInterruptType = defaultInterruptType;
|
||||||
scopeStack.push(program.getScope());
|
scopeStack.push(program.getScope());
|
||||||
}
|
}
|
||||||
@@ -290,10 +296,35 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||||||
break;
|
break;
|
||||||
case CParser.PRAGMA_CODE_SEG:
|
case CParser.PRAGMA_CODE_SEG:
|
||||||
this.currentCodeSegment = pragmaParamName(pragmaParamSingle(ctx));
|
this.currentCodeSegment = pragmaParamName(pragmaParamSingle(ctx));
|
||||||
|
this.pragmaCodeSegs.put(this.currentCodeSegment, ctx);
|
||||||
break;
|
break;
|
||||||
case CParser.PRAGMA_DATA_SEG:
|
case CParser.PRAGMA_DATA_SEG:
|
||||||
this.currentDataSegment = pragmaParamName(pragmaParamSingle(ctx));
|
this.currentDataSegment = pragmaParamName(pragmaParamSingle(ctx));
|
||||||
break;
|
break;
|
||||||
|
case CParser.PRAGMA_FAR_SEG:
|
||||||
|
try {
|
||||||
|
final int size = ctx.getChildCount();
|
||||||
|
if(size==7) {
|
||||||
|
final String pragmaFarSegment = pragmaParamFarSegment(ctx.pragmaParam(0));
|
||||||
|
final Number pragmaFarBank = pragmaParamNumber(ctx.pragmaParam(1));
|
||||||
|
if (this.pragmaCodeSegs.get(pragmaFarSegment) != null) {
|
||||||
|
this.currentFarSegment = pragmaFarSegment;
|
||||||
|
if (size > 7) {
|
||||||
|
final String call_prepare = pragmaParamName(ctx.pragmaParam(2));
|
||||||
|
final String call_execute = pragmaParamName(ctx.pragmaParam(3));
|
||||||
|
final String call_finalize = pragmaParamName(ctx.pragmaParam(4));
|
||||||
|
this.pragmaFarSegs.put(this.currentFarSegment, new FarSegment(pragmaFarSegment, pragmaFarBank.intValue(), call_prepare, call_execute, call_finalize));
|
||||||
|
} else {
|
||||||
|
this.pragmaFarSegs.put(this.currentFarSegment, new FarSegment(pragmaFarSegment, pragmaFarBank.intValue(), "", "", ""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new CompileError("Expected at least 2 pragma parameters. Found '" + ctx.getText() + "'.", new StatementSource(ctx));
|
||||||
|
}
|
||||||
|
} catch(IllegalArgumentException e) {
|
||||||
|
throw new CompileError("Illegal parameter " + ctx.getText(), new StatementSource(ctx));
|
||||||
|
}
|
||||||
|
break;
|
||||||
case CParser.PRAGMA_RESOURCE:
|
case CParser.PRAGMA_RESOURCE:
|
||||||
String resourceFileName = pragmaParamString(pragmaParamSingle(ctx));
|
String resourceFileName = pragmaParamString(pragmaParamSingle(ctx));
|
||||||
addResourceFile(ctx, resourceFileName);
|
addResourceFile(ctx, resourceFileName);
|
||||||
@@ -367,6 +398,24 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||||||
return callingConvention;
|
return callingConvention;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the FAR_SEG parameter of a #pragma
|
||||||
|
* If the parameter is not a FAR_SEG the compiler will fail out
|
||||||
|
*
|
||||||
|
* @param paramCtx The parameter to parse
|
||||||
|
* @return The name
|
||||||
|
*/
|
||||||
|
private String pragmaParamFarSegment(KickCParser.PragmaParamContext paramCtx) {
|
||||||
|
if(!(paramCtx instanceof KickCParser.PragmaParamNameContext))
|
||||||
|
throw new CompileError("Expected a FAR_SEG parameter. Found '" + paramCtx.getText() + "'.", new StatementSource(paramCtx.getParent()));
|
||||||
|
final String pragmaFarSegment = ((KickCParser.PragmaParamNameContext) paramCtx).NAME().getText();
|
||||||
|
if(this.pragmaCodeSegs.get(pragmaFarSegment) != null) {
|
||||||
|
return pragmaFarSegment;
|
||||||
|
} else {
|
||||||
|
throw new CompileError("Expected a previously declared CODE_SEG parameter. Found '" + paramCtx.getText() + "'.", new StatementSource(paramCtx.getParent()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse a single NAME parameter of a #pragma
|
* Parse a single NAME parameter of a #pragma
|
||||||
@@ -436,6 +485,9 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||||||
/** The current data segment. */
|
/** The current data segment. */
|
||||||
private String currentDataSegment = Scope.SEGMENT_DATA_DEFAULT;
|
private String currentDataSegment = Scope.SEGMENT_DATA_DEFAULT;
|
||||||
|
|
||||||
|
/** The current code segment. */
|
||||||
|
private String currentFarSegment = Scope.SEGMENT_FAR_DEFAULT;
|
||||||
|
|
||||||
/** The current default interrupt type. */
|
/** The current default interrupt type. */
|
||||||
private String currentInterruptType;
|
private String currentInterruptType;
|
||||||
|
|
||||||
|
30
src/test/kc/procedure-callingconvention-phi-far-1.c
Normal file
30
src/test/kc/procedure-callingconvention-phi-far-1.c
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
// Test a far call procedure with a calling convention sp
|
||||||
|
|
||||||
|
char* const SCREEN = (char*)0x0400;
|
||||||
|
|
||||||
|
void main(void) {
|
||||||
|
SCREEN[0] = plus('0', 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma code_seg(stage)
|
||||||
|
#pragma far_seg(stage, 1)
|
||||||
|
|
||||||
|
char plus(char a, char b) {
|
||||||
|
return a+b;
|
||||||
|
}
|
||||||
|
|
||||||
|
void stage_entry() {
|
||||||
|
asm {
|
||||||
|
lda 0
|
||||||
|
pha
|
||||||
|
lda #1
|
||||||
|
sta 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void stage_exit() {
|
||||||
|
asm {
|
||||||
|
pla
|
||||||
|
sta 0
|
||||||
|
}
|
||||||
|
}
|
30
src/test/kc/procedure-callingconvention-phi-far-2.c
Normal file
30
src/test/kc/procedure-callingconvention-phi-far-2.c
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
// Test a far call procedure with a calling convention sp
|
||||||
|
|
||||||
|
char* const SCREEN = (char*)0x0400;
|
||||||
|
|
||||||
|
void main(void) {
|
||||||
|
SCREEN[0] = plus('0', 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma code_seg(stage)
|
||||||
|
#pragma far_seg(rubbish, 1, stage_prepare, stage_execution, stage_exit)
|
||||||
|
|
||||||
|
char plus(char a, char b) {
|
||||||
|
return a+b;
|
||||||
|
}
|
||||||
|
|
||||||
|
void stage_entry() {
|
||||||
|
asm {
|
||||||
|
lda 0
|
||||||
|
pha
|
||||||
|
lda #1
|
||||||
|
sta 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void stage_exit() {
|
||||||
|
asm {
|
||||||
|
pla
|
||||||
|
sta 0
|
||||||
|
}
|
||||||
|
}
|
30
src/test/kc/procedure-callingconvention-phi-far-3.c
Normal file
30
src/test/kc/procedure-callingconvention-phi-far-3.c
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
// Test a far call procedure with a calling convention sp
|
||||||
|
|
||||||
|
char* const SCREEN = (char*)0x0400;
|
||||||
|
|
||||||
|
void main(void) {
|
||||||
|
SCREEN[0] = plus('0', 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma code_seg(stage)
|
||||||
|
#pragma far_seg(stage)
|
||||||
|
|
||||||
|
char plus(char a, char b) {
|
||||||
|
return a+b;
|
||||||
|
}
|
||||||
|
|
||||||
|
void stage_entry() {
|
||||||
|
asm {
|
||||||
|
lda 0
|
||||||
|
pha
|
||||||
|
lda #1
|
||||||
|
sta 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void stage_exit() {
|
||||||
|
asm {
|
||||||
|
pla
|
||||||
|
sta 0
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user