mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-04-21 11:42:30 +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:
parent
2f2028f3a1
commit
1ef785a254
@ -76,6 +76,7 @@ ADDRESS: '__address' ;
|
||||
ADDRESS_ZEROPAGE: '__zp' ;
|
||||
ADDRESS_MAINMEM: '__mem' ;
|
||||
FAR: '__far' ;
|
||||
NEAR: '__near' ;
|
||||
FORM_SSA: '__ssa' ;
|
||||
FORM_MA: '__ma' ;
|
||||
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";
|
||||
/** The default data segment. */
|
||||
public static final String SEGMENT_DATA_DEFAULT = "Data";
|
||||
/** The default far segment. */
|
||||
public static final String SEGMENT_FAR_DEFAULT = "";
|
||||
|
||||
private String name;
|
||||
private HashMap<String, Symbol> symbols;
|
||||
|
@ -106,6 +106,14 @@ public class CParser {
|
||||
* The resource-file is copied to the output directory when compiling.
|
||||
*/
|
||||
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.
|
||||
|
@ -43,6 +43,10 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
private final Stack<Scope> scopeStack;
|
||||
/** All #pragma constructor_for() statements. Collected during parsing and handled by {@link #generate()} before returning. */
|
||||
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) {
|
||||
@ -53,6 +57,8 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
this.currentCallingConvention = initialCallingConvention;
|
||||
this.currentEncoding = defaultEncoding;
|
||||
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;
|
||||
scopeStack.push(program.getScope());
|
||||
}
|
||||
@ -290,10 +296,35 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
break;
|
||||
case CParser.PRAGMA_CODE_SEG:
|
||||
this.currentCodeSegment = pragmaParamName(pragmaParamSingle(ctx));
|
||||
this.pragmaCodeSegs.put(this.currentCodeSegment, ctx);
|
||||
break;
|
||||
case CParser.PRAGMA_DATA_SEG:
|
||||
this.currentDataSegment = pragmaParamName(pragmaParamSingle(ctx));
|
||||
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:
|
||||
String resourceFileName = pragmaParamString(pragmaParamSingle(ctx));
|
||||
addResourceFile(ctx, resourceFileName);
|
||||
@ -367,6 +398,24 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
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
|
||||
@ -436,6 +485,9 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
/** The current data segment. */
|
||||
private String currentDataSegment = Scope.SEGMENT_DATA_DEFAULT;
|
||||
|
||||
/** The current code segment. */
|
||||
private String currentFarSegment = Scope.SEGMENT_FAR_DEFAULT;
|
||||
|
||||
/** The current default interrupt type. */
|
||||
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
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user