mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-04-08 14:37:40 +00:00
Added support for declaring var-length parameter lists in functions. Added __intrinsic directive for specifying that a function is implemented in the compiler. Added initial tiny implementation of intrinsic printf(), which only handles %s. #410 #415
This commit is contained in:
parent
9c6e67ddc5
commit
9fa2e5d734
@ -255,6 +255,7 @@ public class Compiler {
|
||||
new PassNTypeInference(program).execute();
|
||||
new PassNTypeIdSimplification(program).execute();
|
||||
new Pass1StructTypeSizeFix(program).execute();
|
||||
new Pass1PrintfIntrinsicRewrite(program).execute();
|
||||
new Pass1AssertReturn(program).execute();
|
||||
new Pass1AssertUsedVars(program).execute();
|
||||
new Pass1AssertNoModifyVars(program).execute();
|
||||
|
@ -27,6 +27,10 @@ public interface Directive {
|
||||
class Inline implements Directive {
|
||||
}
|
||||
|
||||
/** Function declared intrinsic. */
|
||||
class Intrinsic implements Directive {
|
||||
}
|
||||
|
||||
/** Variable declared as extern. */
|
||||
class Extern implements Directive {
|
||||
}
|
||||
|
@ -5,10 +5,9 @@ import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.types.SymbolType;
|
||||
import dk.camelot64.kickc.model.types.SymbolTypeProcedure;
|
||||
import dk.camelot64.kickc.model.values.ProcedureRef;
|
||||
import dk.camelot64.kickc.passes.Pass1PrintfIntrinsicRewrite;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.*;
|
||||
|
||||
/** Symbol describing a procedure/function */
|
||||
public class Procedure extends Scope {
|
||||
@ -17,6 +16,8 @@ public class Procedure extends Scope {
|
||||
private final SymbolType returnType;
|
||||
/** The names of the parameters of the procedure. */
|
||||
private List<String> parameterNames;
|
||||
/** True if the parameter list ends with a variable length parameter list "..." */
|
||||
private boolean variableLengthParameterList;
|
||||
/** true if the procedure is declared inline. */
|
||||
private boolean declaredInline;
|
||||
/** The type of interrupt that the procedure serves. Null for all procedures not serving an interrupt. */
|
||||
@ -27,6 +28,11 @@ public class Procedure extends Scope {
|
||||
private List<Integer> reservedZps;
|
||||
/** The code segment to put the procedure into. */
|
||||
private String codeSegment;
|
||||
/** True if the procedure is declared intrinsic. */
|
||||
private boolean declaredIntrinsic;
|
||||
|
||||
/** The names of all legal intrinsic procedures. */
|
||||
final public static List<String> INTRINSIC_PROCEDURES = Collections.singletonList(Pass1PrintfIntrinsicRewrite.INTRINSIC_PRINTF_NAME);
|
||||
|
||||
/** The method for passing parameters and return value to the procedure. */
|
||||
public enum CallingConvention {
|
||||
@ -85,6 +91,22 @@ public class Procedure extends Scope {
|
||||
return parameterNames;
|
||||
}
|
||||
|
||||
public void setVariableLengthParameterList(boolean variableLengthParameterList) {
|
||||
this.variableLengthParameterList = variableLengthParameterList;
|
||||
}
|
||||
|
||||
public boolean isVariableLengthParameterList() {
|
||||
return variableLengthParameterList;
|
||||
}
|
||||
|
||||
public boolean isDeclaredIntrinsic() {
|
||||
return declaredIntrinsic;
|
||||
}
|
||||
|
||||
public void setDeclaredIntrinsic(boolean declaredIntrinsic) {
|
||||
this.declaredIntrinsic = declaredIntrinsic;
|
||||
}
|
||||
|
||||
public Label getLabel() {
|
||||
return new Label(getFullName(), getScope(), false);
|
||||
}
|
||||
@ -192,7 +214,6 @@ public class Procedure extends Scope {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toString(null);
|
||||
@ -204,6 +225,9 @@ public class Procedure extends Scope {
|
||||
if(declaredInline) {
|
||||
res.append("inline ");
|
||||
}
|
||||
if(declaredIntrinsic) {
|
||||
res.append("__intrinsic ");
|
||||
}
|
||||
if(!callingConvention.equals(CallingConvention.PHI_CALL)) {
|
||||
res.append(getCallingConvention().getName()).append(" ");
|
||||
}
|
||||
@ -221,6 +245,9 @@ public class Procedure extends Scope {
|
||||
res.append(parameter.toString(program));
|
||||
}
|
||||
}
|
||||
if(isVariableLengthParameterList()) {
|
||||
res.append(", ...");
|
||||
}
|
||||
res.append(")");
|
||||
return res.toString();
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ SEMICOLON: ';' ;
|
||||
COLON: ':';
|
||||
COMMA: ',' ;
|
||||
RANGE : '..' ;
|
||||
PARAM_LIST : '...' ;
|
||||
CONDITION : '?' ;
|
||||
DOT : '.' ;
|
||||
ARROW : '->' ;
|
||||
@ -83,6 +84,7 @@ ADDRESS_ZEROPAGE: '__zp' ;
|
||||
ADDRESS_MAINMEM: '__mem' ;
|
||||
FORM_SSA: '__ssa' ;
|
||||
FORM_MA: '__ma' ;
|
||||
INTRINSIC: '__intrinsic' ;
|
||||
CALLING: 'calling';
|
||||
CALLINGCONVENTION: '__stackcall' | '__phicall' ;
|
||||
VARMODEL: 'var_model';
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@ -9,231 +9,235 @@ SEMICOLON=8
|
||||
COLON=9
|
||||
COMMA=10
|
||||
RANGE=11
|
||||
CONDITION=12
|
||||
DOT=13
|
||||
ARROW=14
|
||||
PLUS=15
|
||||
MINUS=16
|
||||
ASTERISK=17
|
||||
DIVIDE=18
|
||||
MODULO=19
|
||||
INC=20
|
||||
DEC=21
|
||||
AND=22
|
||||
BIT_NOT=23
|
||||
BIT_XOR=24
|
||||
BIT_OR=25
|
||||
SHIFT_LEFT=26
|
||||
SHIFT_RIGHT=27
|
||||
EQUAL=28
|
||||
NOT_EQUAL=29
|
||||
LESS_THAN=30
|
||||
LESS_THAN_EQUAL=31
|
||||
GREATER_THAN_EQUAL=32
|
||||
GREATER_THAN=33
|
||||
LOGIC_AND=34
|
||||
LOGIC_OR=35
|
||||
ASSIGN=36
|
||||
ASSIGN_COMPOUND=37
|
||||
TYPEDEF=38
|
||||
RESERVE=39
|
||||
PC=40
|
||||
TARGET=41
|
||||
LINK=42
|
||||
CPU=43
|
||||
CODESEG=44
|
||||
DATASEG=45
|
||||
ENCODING=46
|
||||
CONST=47
|
||||
EXTERN=48
|
||||
EXPORT=49
|
||||
ALIGN=50
|
||||
INLINE=51
|
||||
VOLATILE=52
|
||||
STATIC=53
|
||||
INTERRUPT=54
|
||||
REGISTER=55
|
||||
ADDRESS=56
|
||||
ADDRESS_ZEROPAGE=57
|
||||
ADDRESS_MAINMEM=58
|
||||
FORM_SSA=59
|
||||
FORM_MA=60
|
||||
CALLING=61
|
||||
CALLINGCONVENTION=62
|
||||
VARMODEL=63
|
||||
IF=64
|
||||
ELSE=65
|
||||
WHILE=66
|
||||
DO=67
|
||||
FOR=68
|
||||
SWITCH=69
|
||||
RETURN=70
|
||||
BREAK=71
|
||||
CONTINUE=72
|
||||
ASM=73
|
||||
DEFAULT=74
|
||||
CASE=75
|
||||
STRUCT=76
|
||||
ENUM=77
|
||||
SIZEOF=78
|
||||
TYPEID=79
|
||||
DEFINED=80
|
||||
KICKASM=81
|
||||
RESOURCE=82
|
||||
USES=83
|
||||
CLOBBERS=84
|
||||
BYTES=85
|
||||
CYCLES=86
|
||||
LOGIC_NOT=87
|
||||
SIGNEDNESS=88
|
||||
SIMPLETYPE=89
|
||||
BOOLEAN=90
|
||||
KICKASM_BODY=91
|
||||
IMPORT=92
|
||||
INCLUDE=93
|
||||
PRAGMA=94
|
||||
DEFINE=95
|
||||
DEFINE_CONTINUE=96
|
||||
UNDEF=97
|
||||
IFDEF=98
|
||||
IFNDEF=99
|
||||
IFIF=100
|
||||
ELIF=101
|
||||
IFELSE=102
|
||||
ENDIF=103
|
||||
NUMBER=104
|
||||
NUMFLOAT=105
|
||||
BINFLOAT=106
|
||||
DECFLOAT=107
|
||||
HEXFLOAT=108
|
||||
NUMINT=109
|
||||
BININTEGER=110
|
||||
DECINTEGER=111
|
||||
HEXINTEGER=112
|
||||
NAME=113
|
||||
STRING=114
|
||||
CHAR=115
|
||||
WS=116
|
||||
COMMENT_LINE=117
|
||||
COMMENT_BLOCK=118
|
||||
ASM_BYTE=119
|
||||
ASM_MNEMONIC=120
|
||||
ASM_IMM=121
|
||||
ASM_COLON=122
|
||||
ASM_COMMA=123
|
||||
ASM_PAR_BEGIN=124
|
||||
ASM_PAR_END=125
|
||||
ASM_BRACKET_BEGIN=126
|
||||
ASM_BRACKET_END=127
|
||||
ASM_DOT=128
|
||||
ASM_SHIFT_LEFT=129
|
||||
ASM_SHIFT_RIGHT=130
|
||||
ASM_PLUS=131
|
||||
ASM_MINUS=132
|
||||
ASM_LESS_THAN=133
|
||||
ASM_GREATER_THAN=134
|
||||
ASM_MULTIPLY=135
|
||||
ASM_DIVIDE=136
|
||||
ASM_CURLY_BEGIN=137
|
||||
ASM_CURLY_END=138
|
||||
ASM_NUMBER=139
|
||||
ASM_NUMFLOAT=140
|
||||
ASM_BINFLOAT=141
|
||||
ASM_DECFLOAT=142
|
||||
ASM_HEXFLOAT=143
|
||||
ASM_NUMINT=144
|
||||
ASM_BININTEGER=145
|
||||
ASM_DECINTEGER=146
|
||||
ASM_HEXINTEGER=147
|
||||
ASM_CHAR=148
|
||||
ASM_MULTI_REL=149
|
||||
ASM_MULTI_NAME=150
|
||||
ASM_NAME=151
|
||||
ASM_WS=152
|
||||
ASM_COMMENT_LINE=153
|
||||
ASM_COMMENT_BLOCK=154
|
||||
IMPORT_SYSTEMFILE=155
|
||||
IMPORT_LOCALFILE=156
|
||||
IMPORT_WS=157
|
||||
IMPORT_COMMENT_LINE=158
|
||||
IMPORT_COMMENT_BLOCK=159
|
||||
PARAM_LIST=12
|
||||
CONDITION=13
|
||||
DOT=14
|
||||
ARROW=15
|
||||
PLUS=16
|
||||
MINUS=17
|
||||
ASTERISK=18
|
||||
DIVIDE=19
|
||||
MODULO=20
|
||||
INC=21
|
||||
DEC=22
|
||||
AND=23
|
||||
BIT_NOT=24
|
||||
BIT_XOR=25
|
||||
BIT_OR=26
|
||||
SHIFT_LEFT=27
|
||||
SHIFT_RIGHT=28
|
||||
EQUAL=29
|
||||
NOT_EQUAL=30
|
||||
LESS_THAN=31
|
||||
LESS_THAN_EQUAL=32
|
||||
GREATER_THAN_EQUAL=33
|
||||
GREATER_THAN=34
|
||||
LOGIC_AND=35
|
||||
LOGIC_OR=36
|
||||
ASSIGN=37
|
||||
ASSIGN_COMPOUND=38
|
||||
TYPEDEF=39
|
||||
RESERVE=40
|
||||
PC=41
|
||||
TARGET=42
|
||||
LINK=43
|
||||
CPU=44
|
||||
CODESEG=45
|
||||
DATASEG=46
|
||||
ENCODING=47
|
||||
CONST=48
|
||||
EXTERN=49
|
||||
EXPORT=50
|
||||
ALIGN=51
|
||||
INLINE=52
|
||||
VOLATILE=53
|
||||
STATIC=54
|
||||
INTERRUPT=55
|
||||
REGISTER=56
|
||||
ADDRESS=57
|
||||
ADDRESS_ZEROPAGE=58
|
||||
ADDRESS_MAINMEM=59
|
||||
FORM_SSA=60
|
||||
FORM_MA=61
|
||||
INTRINSIC=62
|
||||
CALLING=63
|
||||
CALLINGCONVENTION=64
|
||||
VARMODEL=65
|
||||
IF=66
|
||||
ELSE=67
|
||||
WHILE=68
|
||||
DO=69
|
||||
FOR=70
|
||||
SWITCH=71
|
||||
RETURN=72
|
||||
BREAK=73
|
||||
CONTINUE=74
|
||||
ASM=75
|
||||
DEFAULT=76
|
||||
CASE=77
|
||||
STRUCT=78
|
||||
ENUM=79
|
||||
SIZEOF=80
|
||||
TYPEID=81
|
||||
DEFINED=82
|
||||
KICKASM=83
|
||||
RESOURCE=84
|
||||
USES=85
|
||||
CLOBBERS=86
|
||||
BYTES=87
|
||||
CYCLES=88
|
||||
LOGIC_NOT=89
|
||||
SIGNEDNESS=90
|
||||
SIMPLETYPE=91
|
||||
BOOLEAN=92
|
||||
KICKASM_BODY=93
|
||||
IMPORT=94
|
||||
INCLUDE=95
|
||||
PRAGMA=96
|
||||
DEFINE=97
|
||||
DEFINE_CONTINUE=98
|
||||
UNDEF=99
|
||||
IFDEF=100
|
||||
IFNDEF=101
|
||||
IFIF=102
|
||||
ELIF=103
|
||||
IFELSE=104
|
||||
ENDIF=105
|
||||
NUMBER=106
|
||||
NUMFLOAT=107
|
||||
BINFLOAT=108
|
||||
DECFLOAT=109
|
||||
HEXFLOAT=110
|
||||
NUMINT=111
|
||||
BININTEGER=112
|
||||
DECINTEGER=113
|
||||
HEXINTEGER=114
|
||||
NAME=115
|
||||
STRING=116
|
||||
CHAR=117
|
||||
WS=118
|
||||
COMMENT_LINE=119
|
||||
COMMENT_BLOCK=120
|
||||
ASM_BYTE=121
|
||||
ASM_MNEMONIC=122
|
||||
ASM_IMM=123
|
||||
ASM_COLON=124
|
||||
ASM_COMMA=125
|
||||
ASM_PAR_BEGIN=126
|
||||
ASM_PAR_END=127
|
||||
ASM_BRACKET_BEGIN=128
|
||||
ASM_BRACKET_END=129
|
||||
ASM_DOT=130
|
||||
ASM_SHIFT_LEFT=131
|
||||
ASM_SHIFT_RIGHT=132
|
||||
ASM_PLUS=133
|
||||
ASM_MINUS=134
|
||||
ASM_LESS_THAN=135
|
||||
ASM_GREATER_THAN=136
|
||||
ASM_MULTIPLY=137
|
||||
ASM_DIVIDE=138
|
||||
ASM_CURLY_BEGIN=139
|
||||
ASM_CURLY_END=140
|
||||
ASM_NUMBER=141
|
||||
ASM_NUMFLOAT=142
|
||||
ASM_BINFLOAT=143
|
||||
ASM_DECFLOAT=144
|
||||
ASM_HEXFLOAT=145
|
||||
ASM_NUMINT=146
|
||||
ASM_BININTEGER=147
|
||||
ASM_DECINTEGER=148
|
||||
ASM_HEXINTEGER=149
|
||||
ASM_CHAR=150
|
||||
ASM_MULTI_REL=151
|
||||
ASM_MULTI_NAME=152
|
||||
ASM_NAME=153
|
||||
ASM_WS=154
|
||||
ASM_COMMENT_LINE=155
|
||||
ASM_COMMENT_BLOCK=156
|
||||
IMPORT_SYSTEMFILE=157
|
||||
IMPORT_LOCALFILE=158
|
||||
IMPORT_WS=159
|
||||
IMPORT_COMMENT_LINE=160
|
||||
IMPORT_COMMENT_BLOCK=161
|
||||
';'=8
|
||||
'..'=11
|
||||
'?'=12
|
||||
'->'=14
|
||||
'%'=19
|
||||
'++'=20
|
||||
'--'=21
|
||||
'&'=22
|
||||
'~'=23
|
||||
'^'=24
|
||||
'|'=25
|
||||
'=='=28
|
||||
'!='=29
|
||||
'<='=31
|
||||
'>='=32
|
||||
'&&'=34
|
||||
'||'=35
|
||||
'='=36
|
||||
'typedef'=38
|
||||
'reserve'=39
|
||||
'pc'=40
|
||||
'target'=41
|
||||
'link'=42
|
||||
'cpu'=43
|
||||
'code_seg'=44
|
||||
'data_seg'=45
|
||||
'encoding'=46
|
||||
'const'=47
|
||||
'extern'=48
|
||||
'export'=49
|
||||
'align'=50
|
||||
'inline'=51
|
||||
'volatile'=52
|
||||
'static'=53
|
||||
'interrupt'=54
|
||||
'register'=55
|
||||
'__address'=56
|
||||
'__zp'=57
|
||||
'__mem'=58
|
||||
'__ssa'=59
|
||||
'__ma'=60
|
||||
'calling'=61
|
||||
'var_model'=63
|
||||
'if'=64
|
||||
'else'=65
|
||||
'while'=66
|
||||
'do'=67
|
||||
'for'=68
|
||||
'switch'=69
|
||||
'return'=70
|
||||
'break'=71
|
||||
'continue'=72
|
||||
'asm'=73
|
||||
'default'=74
|
||||
'case'=75
|
||||
'struct'=76
|
||||
'enum'=77
|
||||
'sizeof'=78
|
||||
'typeid'=79
|
||||
'defined'=80
|
||||
'kickasm'=81
|
||||
'resource'=82
|
||||
'uses'=83
|
||||
'clobbers'=84
|
||||
'bytes'=85
|
||||
'cycles'=86
|
||||
'!'=87
|
||||
'#import'=92
|
||||
'#include'=93
|
||||
'#pragma'=94
|
||||
'#define'=95
|
||||
'#undef'=97
|
||||
'#ifdef'=98
|
||||
'#ifndef'=99
|
||||
'#if'=100
|
||||
'#elif'=101
|
||||
'#else'=102
|
||||
'#endif'=103
|
||||
'.byte'=119
|
||||
'#'=121
|
||||
'...'=12
|
||||
'?'=13
|
||||
'->'=15
|
||||
'%'=20
|
||||
'++'=21
|
||||
'--'=22
|
||||
'&'=23
|
||||
'~'=24
|
||||
'^'=25
|
||||
'|'=26
|
||||
'=='=29
|
||||
'!='=30
|
||||
'<='=32
|
||||
'>='=33
|
||||
'&&'=35
|
||||
'||'=36
|
||||
'='=37
|
||||
'typedef'=39
|
||||
'reserve'=40
|
||||
'pc'=41
|
||||
'target'=42
|
||||
'link'=43
|
||||
'cpu'=44
|
||||
'code_seg'=45
|
||||
'data_seg'=46
|
||||
'encoding'=47
|
||||
'const'=48
|
||||
'extern'=49
|
||||
'export'=50
|
||||
'align'=51
|
||||
'inline'=52
|
||||
'volatile'=53
|
||||
'static'=54
|
||||
'interrupt'=55
|
||||
'register'=56
|
||||
'__address'=57
|
||||
'__zp'=58
|
||||
'__mem'=59
|
||||
'__ssa'=60
|
||||
'__ma'=61
|
||||
'__intrinsic'=62
|
||||
'calling'=63
|
||||
'var_model'=65
|
||||
'if'=66
|
||||
'else'=67
|
||||
'while'=68
|
||||
'do'=69
|
||||
'for'=70
|
||||
'switch'=71
|
||||
'return'=72
|
||||
'break'=73
|
||||
'continue'=74
|
||||
'asm'=75
|
||||
'default'=76
|
||||
'case'=77
|
||||
'struct'=78
|
||||
'enum'=79
|
||||
'sizeof'=80
|
||||
'typeid'=81
|
||||
'defined'=82
|
||||
'kickasm'=83
|
||||
'resource'=84
|
||||
'uses'=85
|
||||
'clobbers'=86
|
||||
'bytes'=87
|
||||
'cycles'=88
|
||||
'!'=89
|
||||
'#import'=94
|
||||
'#include'=95
|
||||
'#pragma'=96
|
||||
'#define'=97
|
||||
'#undef'=99
|
||||
'#ifdef'=100
|
||||
'#ifndef'=101
|
||||
'#if'=102
|
||||
'#elif'=103
|
||||
'#else'=104
|
||||
'#endif'=105
|
||||
'.byte'=121
|
||||
'#'=123
|
||||
|
@ -142,6 +142,7 @@ parameterListDecl
|
||||
parameterDecl
|
||||
: declType declPointer* NAME #parameterDeclType
|
||||
| SIMPLETYPE #parameterDeclVoid
|
||||
| PARAM_LIST #parameterDeclList
|
||||
;
|
||||
|
||||
globalDirective
|
||||
@ -171,6 +172,7 @@ directive
|
||||
| EXTERN #directiveExtern
|
||||
| EXPORT #directiveExport
|
||||
| INLINE #directiveInline
|
||||
| INTRINSIC #directiveIntrinsic
|
||||
| INTERRUPT ( PAR_BEGIN NAME PAR_END )? #directiveInterrupt
|
||||
| RESERVE PAR_BEGIN NUMBER ( COMMA NUMBER )* PAR_END #directiveReserveZp
|
||||
| CALLINGCONVENTION #directiveCallingConvention
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@ -9,231 +9,235 @@ SEMICOLON=8
|
||||
COLON=9
|
||||
COMMA=10
|
||||
RANGE=11
|
||||
CONDITION=12
|
||||
DOT=13
|
||||
ARROW=14
|
||||
PLUS=15
|
||||
MINUS=16
|
||||
ASTERISK=17
|
||||
DIVIDE=18
|
||||
MODULO=19
|
||||
INC=20
|
||||
DEC=21
|
||||
AND=22
|
||||
BIT_NOT=23
|
||||
BIT_XOR=24
|
||||
BIT_OR=25
|
||||
SHIFT_LEFT=26
|
||||
SHIFT_RIGHT=27
|
||||
EQUAL=28
|
||||
NOT_EQUAL=29
|
||||
LESS_THAN=30
|
||||
LESS_THAN_EQUAL=31
|
||||
GREATER_THAN_EQUAL=32
|
||||
GREATER_THAN=33
|
||||
LOGIC_AND=34
|
||||
LOGIC_OR=35
|
||||
ASSIGN=36
|
||||
ASSIGN_COMPOUND=37
|
||||
TYPEDEF=38
|
||||
RESERVE=39
|
||||
PC=40
|
||||
TARGET=41
|
||||
LINK=42
|
||||
CPU=43
|
||||
CODESEG=44
|
||||
DATASEG=45
|
||||
ENCODING=46
|
||||
CONST=47
|
||||
EXTERN=48
|
||||
EXPORT=49
|
||||
ALIGN=50
|
||||
INLINE=51
|
||||
VOLATILE=52
|
||||
STATIC=53
|
||||
INTERRUPT=54
|
||||
REGISTER=55
|
||||
ADDRESS=56
|
||||
ADDRESS_ZEROPAGE=57
|
||||
ADDRESS_MAINMEM=58
|
||||
FORM_SSA=59
|
||||
FORM_MA=60
|
||||
CALLING=61
|
||||
CALLINGCONVENTION=62
|
||||
VARMODEL=63
|
||||
IF=64
|
||||
ELSE=65
|
||||
WHILE=66
|
||||
DO=67
|
||||
FOR=68
|
||||
SWITCH=69
|
||||
RETURN=70
|
||||
BREAK=71
|
||||
CONTINUE=72
|
||||
ASM=73
|
||||
DEFAULT=74
|
||||
CASE=75
|
||||
STRUCT=76
|
||||
ENUM=77
|
||||
SIZEOF=78
|
||||
TYPEID=79
|
||||
DEFINED=80
|
||||
KICKASM=81
|
||||
RESOURCE=82
|
||||
USES=83
|
||||
CLOBBERS=84
|
||||
BYTES=85
|
||||
CYCLES=86
|
||||
LOGIC_NOT=87
|
||||
SIGNEDNESS=88
|
||||
SIMPLETYPE=89
|
||||
BOOLEAN=90
|
||||
KICKASM_BODY=91
|
||||
IMPORT=92
|
||||
INCLUDE=93
|
||||
PRAGMA=94
|
||||
DEFINE=95
|
||||
DEFINE_CONTINUE=96
|
||||
UNDEF=97
|
||||
IFDEF=98
|
||||
IFNDEF=99
|
||||
IFIF=100
|
||||
ELIF=101
|
||||
IFELSE=102
|
||||
ENDIF=103
|
||||
NUMBER=104
|
||||
NUMFLOAT=105
|
||||
BINFLOAT=106
|
||||
DECFLOAT=107
|
||||
HEXFLOAT=108
|
||||
NUMINT=109
|
||||
BININTEGER=110
|
||||
DECINTEGER=111
|
||||
HEXINTEGER=112
|
||||
NAME=113
|
||||
STRING=114
|
||||
CHAR=115
|
||||
WS=116
|
||||
COMMENT_LINE=117
|
||||
COMMENT_BLOCK=118
|
||||
ASM_BYTE=119
|
||||
ASM_MNEMONIC=120
|
||||
ASM_IMM=121
|
||||
ASM_COLON=122
|
||||
ASM_COMMA=123
|
||||
ASM_PAR_BEGIN=124
|
||||
ASM_PAR_END=125
|
||||
ASM_BRACKET_BEGIN=126
|
||||
ASM_BRACKET_END=127
|
||||
ASM_DOT=128
|
||||
ASM_SHIFT_LEFT=129
|
||||
ASM_SHIFT_RIGHT=130
|
||||
ASM_PLUS=131
|
||||
ASM_MINUS=132
|
||||
ASM_LESS_THAN=133
|
||||
ASM_GREATER_THAN=134
|
||||
ASM_MULTIPLY=135
|
||||
ASM_DIVIDE=136
|
||||
ASM_CURLY_BEGIN=137
|
||||
ASM_CURLY_END=138
|
||||
ASM_NUMBER=139
|
||||
ASM_NUMFLOAT=140
|
||||
ASM_BINFLOAT=141
|
||||
ASM_DECFLOAT=142
|
||||
ASM_HEXFLOAT=143
|
||||
ASM_NUMINT=144
|
||||
ASM_BININTEGER=145
|
||||
ASM_DECINTEGER=146
|
||||
ASM_HEXINTEGER=147
|
||||
ASM_CHAR=148
|
||||
ASM_MULTI_REL=149
|
||||
ASM_MULTI_NAME=150
|
||||
ASM_NAME=151
|
||||
ASM_WS=152
|
||||
ASM_COMMENT_LINE=153
|
||||
ASM_COMMENT_BLOCK=154
|
||||
IMPORT_SYSTEMFILE=155
|
||||
IMPORT_LOCALFILE=156
|
||||
IMPORT_WS=157
|
||||
IMPORT_COMMENT_LINE=158
|
||||
IMPORT_COMMENT_BLOCK=159
|
||||
PARAM_LIST=12
|
||||
CONDITION=13
|
||||
DOT=14
|
||||
ARROW=15
|
||||
PLUS=16
|
||||
MINUS=17
|
||||
ASTERISK=18
|
||||
DIVIDE=19
|
||||
MODULO=20
|
||||
INC=21
|
||||
DEC=22
|
||||
AND=23
|
||||
BIT_NOT=24
|
||||
BIT_XOR=25
|
||||
BIT_OR=26
|
||||
SHIFT_LEFT=27
|
||||
SHIFT_RIGHT=28
|
||||
EQUAL=29
|
||||
NOT_EQUAL=30
|
||||
LESS_THAN=31
|
||||
LESS_THAN_EQUAL=32
|
||||
GREATER_THAN_EQUAL=33
|
||||
GREATER_THAN=34
|
||||
LOGIC_AND=35
|
||||
LOGIC_OR=36
|
||||
ASSIGN=37
|
||||
ASSIGN_COMPOUND=38
|
||||
TYPEDEF=39
|
||||
RESERVE=40
|
||||
PC=41
|
||||
TARGET=42
|
||||
LINK=43
|
||||
CPU=44
|
||||
CODESEG=45
|
||||
DATASEG=46
|
||||
ENCODING=47
|
||||
CONST=48
|
||||
EXTERN=49
|
||||
EXPORT=50
|
||||
ALIGN=51
|
||||
INLINE=52
|
||||
VOLATILE=53
|
||||
STATIC=54
|
||||
INTERRUPT=55
|
||||
REGISTER=56
|
||||
ADDRESS=57
|
||||
ADDRESS_ZEROPAGE=58
|
||||
ADDRESS_MAINMEM=59
|
||||
FORM_SSA=60
|
||||
FORM_MA=61
|
||||
INTRINSIC=62
|
||||
CALLING=63
|
||||
CALLINGCONVENTION=64
|
||||
VARMODEL=65
|
||||
IF=66
|
||||
ELSE=67
|
||||
WHILE=68
|
||||
DO=69
|
||||
FOR=70
|
||||
SWITCH=71
|
||||
RETURN=72
|
||||
BREAK=73
|
||||
CONTINUE=74
|
||||
ASM=75
|
||||
DEFAULT=76
|
||||
CASE=77
|
||||
STRUCT=78
|
||||
ENUM=79
|
||||
SIZEOF=80
|
||||
TYPEID=81
|
||||
DEFINED=82
|
||||
KICKASM=83
|
||||
RESOURCE=84
|
||||
USES=85
|
||||
CLOBBERS=86
|
||||
BYTES=87
|
||||
CYCLES=88
|
||||
LOGIC_NOT=89
|
||||
SIGNEDNESS=90
|
||||
SIMPLETYPE=91
|
||||
BOOLEAN=92
|
||||
KICKASM_BODY=93
|
||||
IMPORT=94
|
||||
INCLUDE=95
|
||||
PRAGMA=96
|
||||
DEFINE=97
|
||||
DEFINE_CONTINUE=98
|
||||
UNDEF=99
|
||||
IFDEF=100
|
||||
IFNDEF=101
|
||||
IFIF=102
|
||||
ELIF=103
|
||||
IFELSE=104
|
||||
ENDIF=105
|
||||
NUMBER=106
|
||||
NUMFLOAT=107
|
||||
BINFLOAT=108
|
||||
DECFLOAT=109
|
||||
HEXFLOAT=110
|
||||
NUMINT=111
|
||||
BININTEGER=112
|
||||
DECINTEGER=113
|
||||
HEXINTEGER=114
|
||||
NAME=115
|
||||
STRING=116
|
||||
CHAR=117
|
||||
WS=118
|
||||
COMMENT_LINE=119
|
||||
COMMENT_BLOCK=120
|
||||
ASM_BYTE=121
|
||||
ASM_MNEMONIC=122
|
||||
ASM_IMM=123
|
||||
ASM_COLON=124
|
||||
ASM_COMMA=125
|
||||
ASM_PAR_BEGIN=126
|
||||
ASM_PAR_END=127
|
||||
ASM_BRACKET_BEGIN=128
|
||||
ASM_BRACKET_END=129
|
||||
ASM_DOT=130
|
||||
ASM_SHIFT_LEFT=131
|
||||
ASM_SHIFT_RIGHT=132
|
||||
ASM_PLUS=133
|
||||
ASM_MINUS=134
|
||||
ASM_LESS_THAN=135
|
||||
ASM_GREATER_THAN=136
|
||||
ASM_MULTIPLY=137
|
||||
ASM_DIVIDE=138
|
||||
ASM_CURLY_BEGIN=139
|
||||
ASM_CURLY_END=140
|
||||
ASM_NUMBER=141
|
||||
ASM_NUMFLOAT=142
|
||||
ASM_BINFLOAT=143
|
||||
ASM_DECFLOAT=144
|
||||
ASM_HEXFLOAT=145
|
||||
ASM_NUMINT=146
|
||||
ASM_BININTEGER=147
|
||||
ASM_DECINTEGER=148
|
||||
ASM_HEXINTEGER=149
|
||||
ASM_CHAR=150
|
||||
ASM_MULTI_REL=151
|
||||
ASM_MULTI_NAME=152
|
||||
ASM_NAME=153
|
||||
ASM_WS=154
|
||||
ASM_COMMENT_LINE=155
|
||||
ASM_COMMENT_BLOCK=156
|
||||
IMPORT_SYSTEMFILE=157
|
||||
IMPORT_LOCALFILE=158
|
||||
IMPORT_WS=159
|
||||
IMPORT_COMMENT_LINE=160
|
||||
IMPORT_COMMENT_BLOCK=161
|
||||
';'=8
|
||||
'..'=11
|
||||
'?'=12
|
||||
'->'=14
|
||||
'%'=19
|
||||
'++'=20
|
||||
'--'=21
|
||||
'&'=22
|
||||
'~'=23
|
||||
'^'=24
|
||||
'|'=25
|
||||
'=='=28
|
||||
'!='=29
|
||||
'<='=31
|
||||
'>='=32
|
||||
'&&'=34
|
||||
'||'=35
|
||||
'='=36
|
||||
'typedef'=38
|
||||
'reserve'=39
|
||||
'pc'=40
|
||||
'target'=41
|
||||
'link'=42
|
||||
'cpu'=43
|
||||
'code_seg'=44
|
||||
'data_seg'=45
|
||||
'encoding'=46
|
||||
'const'=47
|
||||
'extern'=48
|
||||
'export'=49
|
||||
'align'=50
|
||||
'inline'=51
|
||||
'volatile'=52
|
||||
'static'=53
|
||||
'interrupt'=54
|
||||
'register'=55
|
||||
'__address'=56
|
||||
'__zp'=57
|
||||
'__mem'=58
|
||||
'__ssa'=59
|
||||
'__ma'=60
|
||||
'calling'=61
|
||||
'var_model'=63
|
||||
'if'=64
|
||||
'else'=65
|
||||
'while'=66
|
||||
'do'=67
|
||||
'for'=68
|
||||
'switch'=69
|
||||
'return'=70
|
||||
'break'=71
|
||||
'continue'=72
|
||||
'asm'=73
|
||||
'default'=74
|
||||
'case'=75
|
||||
'struct'=76
|
||||
'enum'=77
|
||||
'sizeof'=78
|
||||
'typeid'=79
|
||||
'defined'=80
|
||||
'kickasm'=81
|
||||
'resource'=82
|
||||
'uses'=83
|
||||
'clobbers'=84
|
||||
'bytes'=85
|
||||
'cycles'=86
|
||||
'!'=87
|
||||
'#import'=92
|
||||
'#include'=93
|
||||
'#pragma'=94
|
||||
'#define'=95
|
||||
'#undef'=97
|
||||
'#ifdef'=98
|
||||
'#ifndef'=99
|
||||
'#if'=100
|
||||
'#elif'=101
|
||||
'#else'=102
|
||||
'#endif'=103
|
||||
'.byte'=119
|
||||
'#'=121
|
||||
'...'=12
|
||||
'?'=13
|
||||
'->'=15
|
||||
'%'=20
|
||||
'++'=21
|
||||
'--'=22
|
||||
'&'=23
|
||||
'~'=24
|
||||
'^'=25
|
||||
'|'=26
|
||||
'=='=29
|
||||
'!='=30
|
||||
'<='=32
|
||||
'>='=33
|
||||
'&&'=35
|
||||
'||'=36
|
||||
'='=37
|
||||
'typedef'=39
|
||||
'reserve'=40
|
||||
'pc'=41
|
||||
'target'=42
|
||||
'link'=43
|
||||
'cpu'=44
|
||||
'code_seg'=45
|
||||
'data_seg'=46
|
||||
'encoding'=47
|
||||
'const'=48
|
||||
'extern'=49
|
||||
'export'=50
|
||||
'align'=51
|
||||
'inline'=52
|
||||
'volatile'=53
|
||||
'static'=54
|
||||
'interrupt'=55
|
||||
'register'=56
|
||||
'__address'=57
|
||||
'__zp'=58
|
||||
'__mem'=59
|
||||
'__ssa'=60
|
||||
'__ma'=61
|
||||
'__intrinsic'=62
|
||||
'calling'=63
|
||||
'var_model'=65
|
||||
'if'=66
|
||||
'else'=67
|
||||
'while'=68
|
||||
'do'=69
|
||||
'for'=70
|
||||
'switch'=71
|
||||
'return'=72
|
||||
'break'=73
|
||||
'continue'=74
|
||||
'asm'=75
|
||||
'default'=76
|
||||
'case'=77
|
||||
'struct'=78
|
||||
'enum'=79
|
||||
'sizeof'=80
|
||||
'typeid'=81
|
||||
'defined'=82
|
||||
'kickasm'=83
|
||||
'resource'=84
|
||||
'uses'=85
|
||||
'clobbers'=86
|
||||
'bytes'=87
|
||||
'cycles'=88
|
||||
'!'=89
|
||||
'#import'=94
|
||||
'#include'=95
|
||||
'#pragma'=96
|
||||
'#define'=97
|
||||
'#undef'=99
|
||||
'#ifdef'=100
|
||||
'#ifndef'=101
|
||||
'#if'=102
|
||||
'#elif'=103
|
||||
'#else'=104
|
||||
'#endif'=105
|
||||
'.byte'=121
|
||||
'#'=123
|
||||
|
@ -505,6 +505,18 @@ public class KickCParserBaseListener implements KickCParserListener {
|
||||
* <p>The default implementation does nothing.</p>
|
||||
*/
|
||||
@Override public void exitParameterDeclVoid(KickCParser.ParameterDeclVoidContext ctx) { }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation does nothing.</p>
|
||||
*/
|
||||
@Override public void enterParameterDeclList(KickCParser.ParameterDeclListContext ctx) { }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation does nothing.</p>
|
||||
*/
|
||||
@Override public void exitParameterDeclList(KickCParser.ParameterDeclListContext ctx) { }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
@ -781,6 +793,18 @@ public class KickCParserBaseListener implements KickCParserListener {
|
||||
* <p>The default implementation does nothing.</p>
|
||||
*/
|
||||
@Override public void exitDirectiveInline(KickCParser.DirectiveInlineContext ctx) { }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation does nothing.</p>
|
||||
*/
|
||||
@Override public void enterDirectiveIntrinsic(KickCParser.DirectiveIntrinsicContext ctx) { }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation does nothing.</p>
|
||||
*/
|
||||
@Override public void exitDirectiveIntrinsic(KickCParser.DirectiveIntrinsicContext ctx) { }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
|
@ -300,6 +300,13 @@ public class KickCParserBaseVisitor<T> extends AbstractParseTreeVisitor<T> imple
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitParameterDeclVoid(KickCParser.ParameterDeclVoidContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitParameterDeclList(KickCParser.ParameterDeclListContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
@ -461,6 +468,13 @@ public class KickCParserBaseVisitor<T> extends AbstractParseTreeVisitor<T> imple
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitDirectiveInline(KickCParser.DirectiveInlineContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitDirectiveIntrinsic(KickCParser.DirectiveIntrinsicContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
|
@ -459,6 +459,18 @@ public interface KickCParserListener extends ParseTreeListener {
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
void exitParameterDeclVoid(KickCParser.ParameterDeclVoidContext ctx);
|
||||
/**
|
||||
* Enter a parse tree produced by the {@code parameterDeclList}
|
||||
* labeled alternative in {@link KickCParser#parameterDecl}.
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
void enterParameterDeclList(KickCParser.ParameterDeclListContext ctx);
|
||||
/**
|
||||
* Exit a parse tree produced by the {@code parameterDeclList}
|
||||
* labeled alternative in {@link KickCParser#parameterDecl}.
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
void exitParameterDeclList(KickCParser.ParameterDeclListContext ctx);
|
||||
/**
|
||||
* Enter a parse tree produced by the {@code globalDirectiveReserve}
|
||||
* labeled alternative in {@link KickCParser#globalDirective}.
|
||||
@ -735,6 +747,18 @@ public interface KickCParserListener extends ParseTreeListener {
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
void exitDirectiveInline(KickCParser.DirectiveInlineContext ctx);
|
||||
/**
|
||||
* Enter a parse tree produced by the {@code directiveIntrinsic}
|
||||
* labeled alternative in {@link KickCParser#directive}.
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
void enterDirectiveIntrinsic(KickCParser.DirectiveIntrinsicContext ctx);
|
||||
/**
|
||||
* Exit a parse tree produced by the {@code directiveIntrinsic}
|
||||
* labeled alternative in {@link KickCParser#directive}.
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
void exitDirectiveIntrinsic(KickCParser.DirectiveIntrinsicContext ctx);
|
||||
/**
|
||||
* Enter a parse tree produced by the {@code directiveInterrupt}
|
||||
* labeled alternative in {@link KickCParser#directive}.
|
||||
|
@ -278,6 +278,13 @@ public interface KickCParserVisitor<T> extends ParseTreeVisitor<T> {
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitParameterDeclVoid(KickCParser.ParameterDeclVoidContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by the {@code parameterDeclList}
|
||||
* labeled alternative in {@link KickCParser#parameterDecl}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitParameterDeclList(KickCParser.ParameterDeclListContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by the {@code globalDirectiveReserve}
|
||||
* labeled alternative in {@link KickCParser#globalDirective}.
|
||||
@ -439,6 +446,13 @@ public interface KickCParserVisitor<T> extends ParseTreeVisitor<T> {
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitDirectiveInline(KickCParser.DirectiveInlineContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by the {@code directiveIntrinsic}
|
||||
* labeled alternative in {@link KickCParser#directive}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitDirectiveIntrinsic(KickCParser.DirectiveIntrinsicContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by the {@code directiveInterrupt}
|
||||
* labeled alternative in {@link KickCParser#directive}.
|
||||
|
@ -252,10 +252,10 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
|
||||
// Check that the declaration matches any existing declaration!
|
||||
final Symbol existingSymbol = program.getScope().getSymbol(procedure.getRef());
|
||||
if(existingSymbol!=null) {
|
||||
if(existingSymbol != null) {
|
||||
// Already declared - check equality
|
||||
if(!(existingSymbol instanceof Procedure) || !SymbolTypeConversion.procedureDeclarationMatch((Procedure) existingSymbol, procedure))
|
||||
throw new CompileError("Error! Conflicting declarations for: "+procedure.getFullName(), new StatementSource(ctx));
|
||||
throw new CompileError("Error! Conflicting declarations for: " + procedure.getFullName(), new StatementSource(ctx));
|
||||
} else {
|
||||
// Not declared before - add it
|
||||
program.getScope().add(procedure);
|
||||
@ -263,7 +263,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
|
||||
if(ctx.declFunctionBody() != null) {
|
||||
// Make sure directives and more are taken from the procedure with the body!
|
||||
if(existingSymbol!=null) {
|
||||
if(existingSymbol != null) {
|
||||
program.getScope().remove(existingSymbol);
|
||||
program.getScope().add(procedure);
|
||||
}
|
||||
@ -271,7 +271,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
// Check that the body has not already been added
|
||||
for(Statement statement : sequence.getStatements())
|
||||
if(statement instanceof StatementProcedureBegin && ((StatementProcedureBegin) statement).getProcedure().equals(procedure.getRef()))
|
||||
throw new CompileError("Error! Redefinition of function: "+procedure.getFullName(), StatementSource.procedureBegin(ctx));
|
||||
throw new CompileError("Error! Redefinition of function: " + procedure.getFullName(), StatementSource.procedureBegin(ctx));
|
||||
// Add the body
|
||||
scopeStack.push(procedure);
|
||||
sequence.addStatement(new StatementProcedureBegin(procedure.getRef(), StatementSource.procedureBegin(ctx), Comment.NO_COMMENTS));
|
||||
@ -302,11 +302,14 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<Variable> visitParameterListDecl(KickCParser.ParameterListDeclContext ctx) {
|
||||
ArrayList<Variable> parameterDecls = new ArrayList<>();
|
||||
boolean encounteredVariableLengthParamList = false;
|
||||
for(KickCParser.ParameterDeclContext parameterDeclCtx : ctx.parameterDecl()) {
|
||||
if(encounteredVariableLengthParamList) {
|
||||
throw new CompileError("Variable length parameter list is only legal as the last parameter.", new StatementSource(ctx));
|
||||
}
|
||||
Object parameterDecl = this.visit(parameterDeclCtx);
|
||||
if(parameterDecl.equals(SymbolType.VOID)) {
|
||||
if(ctx.parameterDecl().size() == 1) {
|
||||
@ -315,6 +318,11 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
} else {
|
||||
throw new CompileError("Illegal void parameter.", new StatementSource(ctx));
|
||||
}
|
||||
} else if(parameterDecl == PARAM_LIST) {
|
||||
// A "..." parameter list. Update the procedure.
|
||||
final Procedure procedure = (Procedure) getCurrentScope();
|
||||
procedure.setVariableLengthParameterList(true);
|
||||
encounteredVariableLengthParamList = true;
|
||||
} else if(parameterDecl instanceof Variable) {
|
||||
parameterDecls.add((Variable) parameterDecl);
|
||||
} else {
|
||||
@ -345,6 +353,14 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
return SymbolType.VOID;
|
||||
}
|
||||
|
||||
/** Singleton signalling a "..." parameter list. */
|
||||
public static Object PARAM_LIST = new Object();
|
||||
|
||||
@Override
|
||||
public Object visitParameterDeclList(KickCParser.ParameterDeclListContext ctx) {
|
||||
return PARAM_LIST;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitDeclKasm(KickCParser.DeclKasmContext ctx) {
|
||||
String kasm = ctx.KICKASM_BODY().getText();
|
||||
@ -528,7 +544,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
resourceName = resourceName.substring(1, resourceName.length() - 1);
|
||||
Path currentPath = cParser.getSourceFolderPath(ctx);
|
||||
File resourceFile = SourceLoader.loadFile(resourceName, currentPath, new ArrayList<>());
|
||||
if(resourceFile==null)
|
||||
if(resourceFile == null)
|
||||
throw new CompileError("File not found " + resourceName);
|
||||
program.addAsmResourceFile(resourceFile.toPath());
|
||||
if(program.getLog().isVerboseParse()) {
|
||||
@ -999,6 +1015,8 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
procedure.setInterruptType(((Directive.Interrupt) directive).interruptType);
|
||||
} else if(directive instanceof Directive.ReserveZp) {
|
||||
procedure.setReservedZps(((Directive.ReserveZp) directive).reservedZp);
|
||||
} else if(directive instanceof Directive.Intrinsic) {
|
||||
procedure.setDeclaredIntrinsic(true);
|
||||
} else {
|
||||
throw new CompileError("Unsupported function directive " + directive, source);
|
||||
}
|
||||
@ -1034,6 +1052,11 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
return new Directive.Inline();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitDirectiveIntrinsic(KickCParser.DirectiveIntrinsicContext ctx) {
|
||||
return new Directive.Intrinsic();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitDirectiveInterrupt(KickCParser.DirectiveInterruptContext ctx) {
|
||||
String interruptType;
|
||||
@ -1289,6 +1312,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
|
||||
/**
|
||||
* Add code to evaluate a comma-expr condition (used in while/for/...).
|
||||
*
|
||||
* @param conditionCtx The comma-expr condition to evaluate
|
||||
* @param statementSource The statement source used for errors
|
||||
* @return The RValue of the condition
|
||||
@ -1679,7 +1703,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
RValue rValue;
|
||||
if(exprCtx != null) {
|
||||
if(SymbolType.VOID.equals(procedure.getReturnType())) {
|
||||
throw new CompileError("Error! Return value from void function "+procedure.getFullName(), new StatementSource(ctx));
|
||||
throw new CompileError("Error! Return value from void function " + procedure.getFullName(), new StatementSource(ctx));
|
||||
}
|
||||
PrePostModifierHandler.addPreModifiers(this, exprCtx, new StatementSource(ctx));
|
||||
rValue = (RValue) this.visit(exprCtx);
|
||||
|
@ -8,7 +8,7 @@ import dk.camelot64.kickc.model.symbols.Procedure;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/** Pass that checks that all functions declared have a definition with a body*/
|
||||
/** Pass that checks that all functions declared have a definition with a body */
|
||||
public class Pass1AssertProcedureDefined extends Pass1Base {
|
||||
|
||||
public Pass1AssertProcedureDefined(Program program) {
|
||||
@ -19,6 +19,11 @@ public class Pass1AssertProcedureDefined extends Pass1Base {
|
||||
public boolean step() {
|
||||
final Collection<Procedure> allProcedures = getScope().getAllProcedures(true);
|
||||
for(Procedure procedure : allProcedures) {
|
||||
if(procedure.isDeclaredIntrinsic()) {
|
||||
if(!Procedure.INTRINSIC_PROCEDURES.contains(procedure.getLocalName()))
|
||||
throw new CompileError("Error! Undefined intrinsic function: " + procedure.getFullName());
|
||||
continue;
|
||||
}
|
||||
final Label procedureLabel = procedure.getLabel();
|
||||
final ControlFlowBlock procedureBlock = getGraph().getBlock(procedureLabel.getRef());
|
||||
if(procedureBlock == null)
|
||||
|
@ -0,0 +1,121 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.Comment;
|
||||
import dk.camelot64.kickc.model.CompileError;
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.statements.StatementCall;
|
||||
import dk.camelot64.kickc.model.types.SymbolType;
|
||||
import dk.camelot64.kickc.model.values.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Rewrite printf() calls to a series of printf-calls by parsing the format string.
|
||||
*/
|
||||
public class Pass1PrintfIntrinsicRewrite extends Pass2SsaOptimization {
|
||||
|
||||
/** The printf procedure name. */
|
||||
public static final String INTRINSIC_PRINTF_NAME = "printf";
|
||||
|
||||
public Pass1PrintfIntrinsicRewrite(Program program) {
|
||||
super(program);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean step() {
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
final ListIterator<Statement> stmtIt = block.getStatements().listIterator();
|
||||
while(stmtIt.hasNext()) {
|
||||
Statement statement = stmtIt.next();
|
||||
if(statement instanceof StatementCall && ((StatementCall) statement).getProcedureName().equals(INTRINSIC_PRINTF_NAME)) {
|
||||
StatementCall printfCall = (StatementCall) statement;
|
||||
final List<RValue> parameters = printfCall.getParameters();
|
||||
final RValue formatParameter = parameters.get(0);
|
||||
if(!(formatParameter instanceof ConstantValue))
|
||||
throw new CompileError("Error! Only constant printf() format parameter supported!", statement);
|
||||
final ConstantLiteral formatLiteral = ((ConstantValue) formatParameter).calculateLiteral(getProgram().getScope());
|
||||
if(!(formatLiteral instanceof ConstantString))
|
||||
throw new CompileError("Error! printf() format parameter must be a string!", statement);
|
||||
final String formatString = ((ConstantString) formatLiteral).getString();
|
||||
final StringEncoding formatEncoding = ((ConstantString) formatLiteral).getEncoding();
|
||||
|
||||
// Remove the call to printf()
|
||||
stmtIt.remove();
|
||||
|
||||
// Printf Placeholder Format String
|
||||
// "%" start
|
||||
// ([1-9][0-9]* "$")? parameter (gives the # of the parameter to use)
|
||||
// [-+ 0'#]* flags (different flags affecting the formatting "-": left-align, "0": zero-prepend, "+": always sign)
|
||||
// [1-9][0-9]* width (the minimum number of characters)
|
||||
// ("hh" | "l" )? length (specifies the type of integer "hh": char "": int, "l": long)
|
||||
// [%diuxXoscp] type (specifies the type of the parameter/output "d"/"i" decimal signed, "u": decimal unsigned, "x": hexadecimal unsigned (lowercase), "X": hexadecimal unsigned (uppercase), "o": octal unsigned, "s": string, "c": character, "p": pointer, "%": output "%" )
|
||||
Pattern pattern = Pattern.compile("%([1-9][0-9]*[$])?([-+0#]*)([1-9][0-9]*)?(hh|l)?([%diuxXoscp])");
|
||||
final Matcher matcher = pattern.matcher(formatString);
|
||||
int formatIdx = 0;
|
||||
int paramIdx = 1;
|
||||
while(true) {
|
||||
// Find the next pattern match!
|
||||
boolean found = matcher.find();
|
||||
if(!found) {
|
||||
// No more matching patterns
|
||||
break;
|
||||
}
|
||||
final int start = matcher.start();
|
||||
final int end = matcher.end();
|
||||
final String param = matcher.group(1);
|
||||
final String flags = matcher.group(2);
|
||||
final String width = matcher.group(3);
|
||||
final String length = matcher.group(4);
|
||||
final String type = matcher.group(5);
|
||||
|
||||
if(param!=null)
|
||||
throw new CompileError("printf parameter field not supported", printfCall);
|
||||
|
||||
// First grab the non-matching part
|
||||
String prefix = formatString.substring(formatIdx, start);
|
||||
printfConstantString(prefix, printfCall, stmtIt, formatEncoding);
|
||||
|
||||
formatIdx = end;
|
||||
if(type.equals("s")) {
|
||||
// A string
|
||||
long w = (width==null)?0:Integer.parseInt(width);
|
||||
long leftJustify = (flags!=null && flags.contains("-"))?1:0;
|
||||
final ValueList format_string_struct = new ValueList(Arrays.asList(new ConstantInteger(w, SymbolType.BYTE), new ConstantInteger(leftJustify, SymbolType.BYTE)));
|
||||
final StatementCall call_printf_str = new StatementCall(null, "printf_string", Arrays.asList(parameters.get(paramIdx), format_string_struct), printfCall.getSource(), Comment.NO_COMMENTS);
|
||||
call_printf_str.setProcedure(getScope().getLocalProcedure(call_printf_str.getProcedureName()).getRef());
|
||||
stmtIt.add(call_printf_str);
|
||||
paramIdx++;
|
||||
} else if(type.equals("d")) {
|
||||
System.out.println("decimal");
|
||||
}
|
||||
}
|
||||
// Grab the rest
|
||||
String suffix = formatString.substring(formatIdx);
|
||||
printfConstantString(suffix, printfCall, stmtIt, formatEncoding);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a printf_str() that prints a constant string.
|
||||
* @param prefix The string to print
|
||||
* @param printfCall The original printf call
|
||||
* @param stmtIt The statement iterator to add to
|
||||
* @param encoding The string encoding
|
||||
*/
|
||||
private void printfConstantString(String prefix, StatementCall printfCall, ListIterator<Statement> stmtIt, StringEncoding encoding) {
|
||||
final StatementCall call_printf_str = new StatementCall(null, "printf_str", Arrays.asList(new ConstantString(prefix, encoding, true)), printfCall.getSource(), Comment.NO_COMMENTS);
|
||||
call_printf_str.setProcedure(getScope().getLocalProcedure(call_printf_str.getProcedureName()).getRef());
|
||||
stmtIt.add(call_printf_str);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -6,7 +6,6 @@ import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.statements.StatementCall;
|
||||
import dk.camelot64.kickc.model.symbols.Procedure;
|
||||
import dk.camelot64.kickc.model.symbols.Scope;
|
||||
|
||||
/**
|
||||
* Updates procedure calls to point to the actual procedure called.
|
||||
@ -29,11 +28,12 @@ public class Pass1Procedures extends Pass2SsaOptimization {
|
||||
throw new CompileError("Called procedure not found. " + call.toString(getProgram(), false), statement.getSource());
|
||||
}
|
||||
call.setProcedure(procedure.getRef());
|
||||
if(procedure.getParameters().size() != call.getParameters().size()) {
|
||||
if(procedure.isVariableLengthParameterList() && procedure.getParameters().size() > call.getParameters().size()) {
|
||||
throw new CompileError("Wrong number of parameters in call. Expected " + procedure.getParameters().size() + " or more. " + statement.toString(), statement.getSource());
|
||||
} else if(!procedure.isVariableLengthParameterList() && procedure.getParameters().size() != call.getParameters().size()) {
|
||||
throw new CompileError("Wrong number of parameters in call. Expected " + procedure.getParameters().size() + ". " + statement.toString(), statement.getSource());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
@ -40,6 +40,11 @@ public class TestPrograms {
|
||||
public TestPrograms() {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPintf10() throws IOException, URISyntaxException {
|
||||
compileAndCompare("printf-10.c", log());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProblemNegateConst() throws IOException, URISyntaxException {
|
||||
compileAndCompare("problem-negate-const.c");
|
||||
@ -3896,6 +3901,16 @@ public class TestPrograms {
|
||||
assertError("tofewparams.c", "Wrong number of parameters in call");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToFewParamsVarlength() throws IOException, URISyntaxException {
|
||||
assertError("tofewparams-varlength.c", "Wrong number of parameters in call");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVarlengthError() throws IOException, URISyntaxException {
|
||||
assertError("varlength-error.c", "Variable length parameter list is only legal as the last parameter.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoReturn() throws IOException, URISyntaxException {
|
||||
assertError("noreturn.c", "Method must end with a return statement", false);
|
||||
|
13
src/test/kc/.vscode/c_cpp_properties.json
vendored
Normal file
13
src/test/kc/.vscode/c_cpp_properties.json
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"env": {
|
||||
"myDefaultIncludePath": ["${workspaceFolder}", "~/c64/kickc_local/include"]
|
||||
},
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Mac",
|
||||
"includePath": ["${myDefaultIncludePath}", "~/c64/kickc_local/include"],
|
||||
"defines": ["FOO", "BAR=100"]
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
146
src/test/kc/.vscode/tasks.json
vendored
Normal file
146
src/test/kc/.vscode/tasks.json
vendored
Normal file
@ -0,0 +1,146 @@
|
||||
{
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
// for the documentation about the tasks.json format
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "KickAssembler",
|
||||
"type": "shell",
|
||||
"command": "java",
|
||||
"args": [
|
||||
"-jar",
|
||||
"${config:kickassembler.kickAssPath}",
|
||||
"${file}",
|
||||
"-odir",
|
||||
"build",
|
||||
"-showmem",
|
||||
"-execute",
|
||||
"${workspaceFolder}\\tools\\exomize.bat"
|
||||
],
|
||||
"group": "build",
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "KickAsm Vice",
|
||||
"type": "shell",
|
||||
"command": "java",
|
||||
"args": [
|
||||
"-jar",
|
||||
"${config:kickassembler.kickAssPath}",
|
||||
"${file}",
|
||||
"-define",
|
||||
"AUTORUN",
|
||||
"-showmem",
|
||||
"-vicesymbols",
|
||||
"-execute",
|
||||
"\"${config:vice.vicePath}\" -moncommands ${fileBasenameNoExtension}.vs"
|
||||
],
|
||||
"group": "build"
|
||||
},
|
||||
{
|
||||
"label": "KickAsm Vice Debug",
|
||||
"type": "shell",
|
||||
"command": "java",
|
||||
"args": [
|
||||
"-jar",
|
||||
"${config:kickassembler.kickAssPath}",
|
||||
"${file}",
|
||||
"-odir",
|
||||
"debug",
|
||||
"-define",
|
||||
"AUTORUN",
|
||||
"-define",
|
||||
"DEBUG",
|
||||
"-showmem",
|
||||
"-vicesymbols",
|
||||
":debug=true",
|
||||
"-execute",
|
||||
"\"${config:vice.vicePath}\" -moncommands ${fileBasenameNoExtension}.vs"
|
||||
],
|
||||
"group": "build"
|
||||
},
|
||||
{
|
||||
"label": "KickAsm C64Debugger",
|
||||
"type": "shell",
|
||||
"command": "java",
|
||||
"args": [
|
||||
"-jar",
|
||||
"${config:kickassembler.kickAssPath}",
|
||||
"${file}",
|
||||
"-odir",
|
||||
"bin",
|
||||
"-define",
|
||||
"AUTORUN",
|
||||
"-showmem",
|
||||
"-debugdump",
|
||||
"-execute",
|
||||
"\"${config:c64debugger.c64debuggerPath}\""
|
||||
],
|
||||
"group": "build"
|
||||
},
|
||||
{
|
||||
"label": "KickAsm C64Debugger Debug",
|
||||
"type": "shell",
|
||||
"command": "java",
|
||||
"args": [
|
||||
"-jar",
|
||||
"${config:kickassembler.kickAssPath}",
|
||||
"${file}",
|
||||
"-odir",
|
||||
"debug",
|
||||
"-define",
|
||||
"AUTORUN",
|
||||
"-define",
|
||||
"DEBUG",
|
||||
"-showmem",
|
||||
"-debugdump",
|
||||
":debug=true",
|
||||
"-execute",
|
||||
"\"${config:c64debugger.c64debuggerPath}\""
|
||||
],
|
||||
"group": "build"
|
||||
},
|
||||
{
|
||||
"label": "KickAsm Build",
|
||||
"command": "java",
|
||||
"args": [
|
||||
"-jar",
|
||||
"${config:kickassembler.kickAssPath}",
|
||||
"${file}",
|
||||
"-odir",
|
||||
"build",
|
||||
"-showmem"
|
||||
],
|
||||
"group": "build"
|
||||
},
|
||||
{
|
||||
"label": "KickC Build & Run",
|
||||
"type": "shell",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"command": "~/c64/kickc_local/bin/kickc.sh",
|
||||
"args": [
|
||||
"-odir",
|
||||
"~/c64/tmp/",
|
||||
"-e",
|
||||
"${relativeFile}"
|
||||
],
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Exomize Build",
|
||||
"command": "${workspaceFolder}\\tools\\exomize.bat",
|
||||
"args": [
|
||||
"${config:exomizer.exomizerPath}",
|
||||
"${file}"
|
||||
],
|
||||
"dependsOn": [
|
||||
"KickAsm Build"
|
||||
],
|
||||
"group": "build"
|
||||
}
|
||||
]
|
||||
}
|
33
src/test/kc/printf-10.c
Normal file
33
src/test/kc/printf-10.c
Normal file
@ -0,0 +1,33 @@
|
||||
// Tests printf function call rewriting
|
||||
// A simple string - with the printf-sub cuntions in the same file.
|
||||
|
||||
__intrinsic void printf(char* format, ...);
|
||||
|
||||
char * screen = 0x0400;
|
||||
char idx = 0;
|
||||
|
||||
void printf_str(char* str) {
|
||||
while(*str) {
|
||||
*screen++ = *str++;
|
||||
}
|
||||
}
|
||||
|
||||
// Format specifying how to format a printed string
|
||||
struct printf_format_string {
|
||||
// The minimal number of chars to output (used for padding with spaces or 0).
|
||||
char min_length;
|
||||
// Justify left instead of right, which is the default.
|
||||
char justify_left;
|
||||
};
|
||||
|
||||
// Print a string value using a specific format
|
||||
// Handles justification and min length
|
||||
void printf_string(char* str, struct printf_format_string format) {
|
||||
printf_str(str);
|
||||
}
|
||||
|
||||
void main() {
|
||||
char name[] = "Jesper";
|
||||
printf("Hello, I am %s. who are you?", name);
|
||||
}
|
||||
|
7
src/test/kc/tofewparams-varlength.c
Normal file
7
src/test/kc/tofewparams-varlength.c
Normal file
@ -0,0 +1,7 @@
|
||||
// To few parameters to a function with variable parameter list length
|
||||
|
||||
__intrinsic void printf(char* format, ...);
|
||||
|
||||
void main() {
|
||||
printf();
|
||||
}
|
7
src/test/kc/varlength-error.c
Normal file
7
src/test/kc/varlength-error.c
Normal file
@ -0,0 +1,7 @@
|
||||
// A procedure with the varlength in the middle of the list
|
||||
|
||||
void printf(char* format, ..., int x);
|
||||
|
||||
void main() {
|
||||
printf("c", 1, 2, 3);
|
||||
}
|
73
src/test/ref/printf-10.asm
Normal file
73
src/test/ref/printf-10.asm
Normal file
@ -0,0 +1,73 @@
|
||||
// Tests printf function call rewriting
|
||||
// A simple string - with the printf-sub cuntions in the same file.
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
.label screen = 2
|
||||
main: {
|
||||
// printf("Hello, I am %s. who are you?", name)
|
||||
lda #<$400
|
||||
sta.z screen
|
||||
lda #>$400
|
||||
sta.z screen+1
|
||||
lda #<str
|
||||
sta.z printf_str.str
|
||||
lda #>str
|
||||
sta.z printf_str.str+1
|
||||
jsr printf_str
|
||||
// printf("Hello, I am %s. who are you?", name)
|
||||
jsr printf_string
|
||||
// printf("Hello, I am %s. who are you?", name)
|
||||
lda #<str1
|
||||
sta.z printf_str.str
|
||||
lda #>str1
|
||||
sta.z printf_str.str+1
|
||||
jsr printf_str
|
||||
// }
|
||||
rts
|
||||
name: .text "Jesper"
|
||||
.byte 0
|
||||
str: .text "Hello, I am "
|
||||
.byte 0
|
||||
str1: .text ". who are you?"
|
||||
.byte 0
|
||||
}
|
||||
// printf_str(byte* zp(4) str)
|
||||
printf_str: {
|
||||
.label str = 4
|
||||
__b1:
|
||||
// while(*str)
|
||||
ldy #0
|
||||
lda (str),y
|
||||
cmp #0
|
||||
bne __b2
|
||||
// }
|
||||
rts
|
||||
__b2:
|
||||
// *screen++ = *str++
|
||||
ldy #0
|
||||
lda (str),y
|
||||
sta (screen),y
|
||||
// *screen++ = *str++;
|
||||
inc.z screen
|
||||
bne !+
|
||||
inc.z screen+1
|
||||
!:
|
||||
inc.z str
|
||||
bne !+
|
||||
inc.z str+1
|
||||
!:
|
||||
jmp __b1
|
||||
}
|
||||
// Print a string value using a specific format
|
||||
// Handles justification and min length
|
||||
printf_string: {
|
||||
// printf_str(str)
|
||||
lda #<main.name
|
||||
sta.z printf_str.str
|
||||
lda #>main.name
|
||||
sta.z printf_str.str+1
|
||||
jsr printf_str
|
||||
// }
|
||||
rts
|
||||
}
|
54
src/test/ref/printf-10.cfg
Normal file
54
src/test/ref/printf-10.cfg
Normal file
@ -0,0 +1,54 @@
|
||||
@begin: scope:[] from
|
||||
[0] phi()
|
||||
to:@1
|
||||
@1: scope:[] from @begin
|
||||
[1] phi()
|
||||
[2] call main
|
||||
to:@end
|
||||
@end: scope:[] from @1
|
||||
[3] phi()
|
||||
|
||||
(void()) main()
|
||||
main: scope:[main] from @1
|
||||
[4] phi()
|
||||
[5] call printf_str
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main
|
||||
[6] phi()
|
||||
[7] call printf_string
|
||||
to:main::@2
|
||||
main::@2: scope:[main] from main::@1
|
||||
[8] phi()
|
||||
[9] call printf_str
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@2
|
||||
[10] return
|
||||
to:@return
|
||||
|
||||
(void()) printf_str((byte*) printf_str::str)
|
||||
printf_str: scope:[printf_str] from main main::@2 printf_string
|
||||
[11] (byte*) screen#23 ← phi( main/(byte*) 1024 main::@2/(byte*) screen#10 printf_string/(byte*) screen#10 )
|
||||
[11] (byte*) printf_str::str#6 ← phi( main/(const byte*) main::str main::@2/(const byte*) main::str1 printf_string/(const byte*) main::name )
|
||||
to:printf_str::@1
|
||||
printf_str::@1: scope:[printf_str] from printf_str printf_str::@2
|
||||
[12] (byte*) screen#10 ← phi( printf_str/(byte*) screen#23 printf_str::@2/(byte*) screen#1 )
|
||||
[12] (byte*) printf_str::str#4 ← phi( printf_str/(byte*) printf_str::str#6 printf_str::@2/(byte*) printf_str::str#0 )
|
||||
[13] if((byte) 0!=*((byte*) printf_str::str#4)) goto printf_str::@2
|
||||
to:printf_str::@return
|
||||
printf_str::@return: scope:[printf_str] from printf_str::@1
|
||||
[14] return
|
||||
to:@return
|
||||
printf_str::@2: scope:[printf_str] from printf_str::@1
|
||||
[15] *((byte*) screen#10) ← *((byte*) printf_str::str#4)
|
||||
[16] (byte*) screen#1 ← ++ (byte*) screen#10
|
||||
[17] (byte*) printf_str::str#0 ← ++ (byte*) printf_str::str#4
|
||||
to:printf_str::@1
|
||||
|
||||
(void()) printf_string((byte*) printf_string::str , (byte) printf_string::format_min_length , (byte) printf_string::format_justify_left)
|
||||
printf_string: scope:[printf_string] from main::@1
|
||||
[18] phi()
|
||||
[19] call printf_str
|
||||
to:printf_string::@return
|
||||
printf_string::@return: scope:[printf_string] from printf_string
|
||||
[20] return
|
||||
to:@return
|
834
src/test/ref/printf-10.log
Normal file
834
src/test/ref/printf-10.log
Normal file
@ -0,0 +1,834 @@
|
||||
Added struct type cast to parameter value list call printf_string (const byte*) main::name (struct printf_format_string){ (byte) 0, (byte) 0 }
|
||||
Created struct value member variable (byte) printf_string::format_min_length
|
||||
Created struct value member variable (byte) printf_string::format_justify_left
|
||||
Converted struct value to member variables (struct printf_format_string) printf_string::format
|
||||
Converted procedure struct value parameter to member unwinding (void()) printf_string((byte*) printf_string::str , (byte) printf_string::format_min_length , (byte) printf_string::format_justify_left)
|
||||
Converted call struct value parameter to member unwinding call printf_string (const byte*) main::name (byte) 0 (byte) 0
|
||||
Warning! Adding boolean cast to non-boolean condition *((byte*) printf_str::str)
|
||||
Identified constant variable (byte) idx
|
||||
Eliminating unused variable with no statement (void~) main::$0
|
||||
Culled Empty Block (label) printf_str::@4
|
||||
Culled Empty Block (label) printf_str::@3
|
||||
Culled Empty Block (label) printf_str::@5
|
||||
Culled Empty Block (label) printf_str::@6
|
||||
Culled Empty Block (label) @1
|
||||
Culled Empty Block (label) @2
|
||||
|
||||
CONTROL FLOW GRAPH SSA
|
||||
@begin: scope:[] from
|
||||
(byte*) screen#0 ← (byte*)(number) $400
|
||||
to:@3
|
||||
|
||||
(void()) printf_str((byte*) printf_str::str)
|
||||
printf_str: scope:[printf_str] from main main::@2 printf_string
|
||||
(byte*) screen#23 ← phi( main/(byte*) screen#21 main::@2/(byte*) screen#6 printf_string/(byte*) screen#20 )
|
||||
(byte*) printf_str::str#6 ← phi( main/(byte*) printf_str::str#2 main::@2/(byte*) printf_str::str#3 printf_string/(byte*) printf_str::str#1 )
|
||||
to:printf_str::@1
|
||||
printf_str::@1: scope:[printf_str] from printf_str printf_str::@2
|
||||
(byte*) screen#19 ← phi( printf_str/(byte*) screen#23 printf_str::@2/(byte*) screen#1 )
|
||||
(byte*) printf_str::str#4 ← phi( printf_str/(byte*) printf_str::str#6 printf_str::@2/(byte*) printf_str::str#0 )
|
||||
(bool~) printf_str::$0 ← (number) 0 != *((byte*) printf_str::str#4)
|
||||
if((bool~) printf_str::$0) goto printf_str::@2
|
||||
to:printf_str::@return
|
||||
printf_str::@2: scope:[printf_str] from printf_str::@1
|
||||
(byte*) screen#10 ← phi( printf_str::@1/(byte*) screen#19 )
|
||||
(byte*) printf_str::str#5 ← phi( printf_str::@1/(byte*) printf_str::str#4 )
|
||||
*((byte*) screen#10) ← *((byte*) printf_str::str#5)
|
||||
(byte*) screen#1 ← ++ (byte*) screen#10
|
||||
(byte*) printf_str::str#0 ← ++ (byte*) printf_str::str#5
|
||||
to:printf_str::@1
|
||||
printf_str::@return: scope:[printf_str] from printf_str::@1
|
||||
(byte*) screen#11 ← phi( printf_str::@1/(byte*) screen#19 )
|
||||
(byte*) screen#2 ← (byte*) screen#11
|
||||
return
|
||||
to:@return
|
||||
|
||||
(void()) printf_string((byte*) printf_string::str , (byte) printf_string::format_min_length , (byte) printf_string::format_justify_left)
|
||||
printf_string: scope:[printf_string] from main::@1
|
||||
(byte*) screen#20 ← phi( main::@1/(byte*) screen#5 )
|
||||
(byte*) printf_string::str#1 ← phi( main::@1/(byte*) printf_string::str#0 )
|
||||
(byte*) printf_str::str#1 ← (byte*) printf_string::str#1
|
||||
call printf_str
|
||||
to:printf_string::@1
|
||||
printf_string::@1: scope:[printf_string] from printf_string
|
||||
(byte*) screen#12 ← phi( printf_string/(byte*) screen#2 )
|
||||
(byte*) screen#3 ← (byte*) screen#12
|
||||
to:printf_string::@return
|
||||
printf_string::@return: scope:[printf_string] from printf_string::@1
|
||||
(byte*) screen#13 ← phi( printf_string::@1/(byte*) screen#3 )
|
||||
(byte*) screen#4 ← (byte*) screen#13
|
||||
return
|
||||
to:@return
|
||||
|
||||
(void()) main()
|
||||
main: scope:[main] from @3
|
||||
(byte*) screen#21 ← phi( @3/(byte*) screen#22 )
|
||||
(byte*) printf_str::str#2 ← (const byte*) main::str
|
||||
call printf_str
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main
|
||||
(byte*) screen#14 ← phi( main/(byte*) screen#2 )
|
||||
(byte*) screen#5 ← (byte*) screen#14
|
||||
(byte*) printf_string::str#0 ← (const byte*) main::name
|
||||
(byte) printf_string::format_min_length#0 ← (byte) 0
|
||||
(byte) printf_string::format_justify_left#0 ← (byte) 0
|
||||
call printf_string
|
||||
to:main::@2
|
||||
main::@2: scope:[main] from main::@1
|
||||
(byte*) screen#15 ← phi( main::@1/(byte*) screen#4 )
|
||||
(byte*) screen#6 ← (byte*) screen#15
|
||||
(byte*) printf_str::str#3 ← (const byte*) main::str1
|
||||
call printf_str
|
||||
to:main::@3
|
||||
main::@3: scope:[main] from main::@2
|
||||
(byte*) screen#16 ← phi( main::@2/(byte*) screen#2 )
|
||||
(byte*) screen#7 ← (byte*) screen#16
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@3
|
||||
(byte*) screen#17 ← phi( main::@3/(byte*) screen#7 )
|
||||
(byte*) screen#8 ← (byte*) screen#17
|
||||
return
|
||||
to:@return
|
||||
@3: scope:[] from @begin
|
||||
(byte*) screen#22 ← phi( @begin/(byte*) screen#0 )
|
||||
call main
|
||||
to:@4
|
||||
@4: scope:[] from @3
|
||||
(byte*) screen#18 ← phi( @3/(byte*) screen#8 )
|
||||
(byte*) screen#9 ← (byte*) screen#18
|
||||
to:@end
|
||||
@end: scope:[] from @4
|
||||
|
||||
SYMBOL TABLE SSA
|
||||
(label) @3
|
||||
(label) @4
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(void()) main()
|
||||
(label) main::@1
|
||||
(label) main::@2
|
||||
(label) main::@3
|
||||
(label) main::@return
|
||||
(const byte*) main::name[] = (byte*) "Jesper"
|
||||
(const byte*) main::str[(byte) $d] = (byte*) "Hello, I am "
|
||||
(const byte*) main::str1[(byte) $f] = (byte*) ". who are you?"
|
||||
(byte) printf_format_string::justify_left
|
||||
(byte) printf_format_string::min_length
|
||||
(void()) printf_str((byte*) printf_str::str)
|
||||
(bool~) printf_str::$0
|
||||
(label) printf_str::@1
|
||||
(label) printf_str::@2
|
||||
(label) printf_str::@return
|
||||
(byte*) printf_str::str
|
||||
(byte*) printf_str::str#0
|
||||
(byte*) printf_str::str#1
|
||||
(byte*) printf_str::str#2
|
||||
(byte*) printf_str::str#3
|
||||
(byte*) printf_str::str#4
|
||||
(byte*) printf_str::str#5
|
||||
(byte*) printf_str::str#6
|
||||
(void()) printf_string((byte*) printf_string::str , (byte) printf_string::format_min_length , (byte) printf_string::format_justify_left)
|
||||
(label) printf_string::@1
|
||||
(label) printf_string::@return
|
||||
(struct printf_format_string) printf_string::format
|
||||
(byte) printf_string::format_justify_left
|
||||
(byte) printf_string::format_justify_left#0
|
||||
(byte) printf_string::format_min_length
|
||||
(byte) printf_string::format_min_length#0
|
||||
(byte*) printf_string::str
|
||||
(byte*) printf_string::str#0
|
||||
(byte*) printf_string::str#1
|
||||
(byte*) screen
|
||||
(byte*) screen#0
|
||||
(byte*) screen#1
|
||||
(byte*) screen#10
|
||||
(byte*) screen#11
|
||||
(byte*) screen#12
|
||||
(byte*) screen#13
|
||||
(byte*) screen#14
|
||||
(byte*) screen#15
|
||||
(byte*) screen#16
|
||||
(byte*) screen#17
|
||||
(byte*) screen#18
|
||||
(byte*) screen#19
|
||||
(byte*) screen#2
|
||||
(byte*) screen#20
|
||||
(byte*) screen#21
|
||||
(byte*) screen#22
|
||||
(byte*) screen#23
|
||||
(byte*) screen#3
|
||||
(byte*) screen#4
|
||||
(byte*) screen#5
|
||||
(byte*) screen#6
|
||||
(byte*) screen#7
|
||||
(byte*) screen#8
|
||||
(byte*) screen#9
|
||||
|
||||
Adding number conversion cast (unumber) 0 in (bool~) printf_str::$0 ← (number) 0 != *((byte*) printf_str::str#4)
|
||||
Successful SSA optimization PassNAddNumberTypeConversions
|
||||
Simplifying constant pointer cast (byte*) 1024
|
||||
Simplifying constant integer cast 0
|
||||
Successful SSA optimization PassNCastSimplification
|
||||
Finalized unsigned number type (byte) 0
|
||||
Successful SSA optimization PassNFinalizeNumberTypeConversions
|
||||
Alias printf_str::str#4 = printf_str::str#5
|
||||
Alias screen#10 = screen#19 screen#11 screen#2
|
||||
Alias screen#12 = screen#3 screen#13 screen#4
|
||||
Alias screen#14 = screen#5
|
||||
Alias screen#15 = screen#6
|
||||
Alias screen#16 = screen#7 screen#17 screen#8
|
||||
Alias screen#0 = screen#22
|
||||
Alias screen#18 = screen#9
|
||||
Successful SSA optimization Pass2AliasElimination
|
||||
Identical Phi Values (byte*) printf_string::str#1 (byte*) printf_string::str#0
|
||||
Identical Phi Values (byte*) screen#20 (byte*) screen#14
|
||||
Identical Phi Values (byte*) screen#12 (byte*) screen#10
|
||||
Identical Phi Values (byte*) screen#21 (byte*) screen#0
|
||||
Identical Phi Values (byte*) screen#14 (byte*) screen#10
|
||||
Identical Phi Values (byte*) screen#15 (byte*) screen#12
|
||||
Identical Phi Values (byte*) screen#16 (byte*) screen#10
|
||||
Identical Phi Values (byte*) screen#18 (byte*) screen#16
|
||||
Successful SSA optimization Pass2IdenticalPhiElimination
|
||||
Simple Condition (bool~) printf_str::$0 [4] if((byte) 0!=*((byte*) printf_str::str#4)) goto printf_str::@2
|
||||
Successful SSA optimization Pass2ConditionalJumpSimplification
|
||||
Constant (const byte*) screen#0 = (byte*) 1024
|
||||
Constant (const byte*) printf_str::str#2 = main::str
|
||||
Constant (const byte*) printf_string::str#0 = main::name
|
||||
Constant (const byte) printf_string::format_min_length#0 = 0
|
||||
Constant (const byte) printf_string::format_justify_left#0 = 0
|
||||
Constant (const byte*) printf_str::str#3 = main::str1
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Constant (const byte*) printf_str::str#1 = printf_string::str#0
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Eliminating unused constant (const byte) printf_string::format_min_length#0
|
||||
Eliminating unused constant (const byte) printf_string::format_justify_left#0
|
||||
Successful SSA optimization PassNEliminateUnusedVars
|
||||
Inlining constant with var siblings (const byte*) printf_str::str#2
|
||||
Inlining constant with var siblings (const byte*) printf_str::str#3
|
||||
Inlining constant with var siblings (const byte*) printf_str::str#1
|
||||
Inlining constant with var siblings (const byte*) screen#0
|
||||
Constant inlined printf_string::str#0 = (const byte*) main::name
|
||||
Constant inlined printf_str::str#2 = (const byte*) main::str
|
||||
Constant inlined printf_str::str#1 = (const byte*) main::name
|
||||
Constant inlined screen#0 = (byte*) 1024
|
||||
Constant inlined printf_str::str#3 = (const byte*) main::str1
|
||||
Successful SSA optimization Pass2ConstantInlining
|
||||
Adding NOP phi() at start of @begin
|
||||
Adding NOP phi() at start of @3
|
||||
Adding NOP phi() at start of @4
|
||||
Adding NOP phi() at start of @end
|
||||
Adding NOP phi() at start of main
|
||||
Adding NOP phi() at start of main::@1
|
||||
Adding NOP phi() at start of main::@3
|
||||
Adding NOP phi() at start of printf_string::@1
|
||||
CALL GRAPH
|
||||
Calls in [] to main:2
|
||||
Calls in [main] to printf_str:6 printf_string:8 printf_str:10
|
||||
Calls in [printf_string] to printf_str:25
|
||||
|
||||
Created 4 initial phi equivalence classes
|
||||
Coalesced [9] screen#24 ← screen#10
|
||||
Coalesced [14] printf_str::str#7 ← printf_str::str#6
|
||||
Coalesced (already) [15] screen#26 ← screen#23
|
||||
Coalesced [22] printf_str::str#8 ← printf_str::str#0
|
||||
Coalesced [23] screen#27 ← screen#1
|
||||
Coalesced (already) [24] screen#25 ← screen#10
|
||||
Coalesced down to 2 phi equivalence classes
|
||||
Culled Empty Block (label) @4
|
||||
Culled Empty Block (label) main::@3
|
||||
Culled Empty Block (label) printf_string::@1
|
||||
Renumbering block @3 to @1
|
||||
Adding NOP phi() at start of @begin
|
||||
Adding NOP phi() at start of @1
|
||||
Adding NOP phi() at start of @end
|
||||
Adding NOP phi() at start of main
|
||||
Adding NOP phi() at start of main::@1
|
||||
Adding NOP phi() at start of main::@2
|
||||
Adding NOP phi() at start of printf_string
|
||||
|
||||
FINAL CONTROL FLOW GRAPH
|
||||
@begin: scope:[] from
|
||||
[0] phi()
|
||||
to:@1
|
||||
@1: scope:[] from @begin
|
||||
[1] phi()
|
||||
[2] call main
|
||||
to:@end
|
||||
@end: scope:[] from @1
|
||||
[3] phi()
|
||||
|
||||
(void()) main()
|
||||
main: scope:[main] from @1
|
||||
[4] phi()
|
||||
[5] call printf_str
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main
|
||||
[6] phi()
|
||||
[7] call printf_string
|
||||
to:main::@2
|
||||
main::@2: scope:[main] from main::@1
|
||||
[8] phi()
|
||||
[9] call printf_str
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@2
|
||||
[10] return
|
||||
to:@return
|
||||
|
||||
(void()) printf_str((byte*) printf_str::str)
|
||||
printf_str: scope:[printf_str] from main main::@2 printf_string
|
||||
[11] (byte*) screen#23 ← phi( main/(byte*) 1024 main::@2/(byte*) screen#10 printf_string/(byte*) screen#10 )
|
||||
[11] (byte*) printf_str::str#6 ← phi( main/(const byte*) main::str main::@2/(const byte*) main::str1 printf_string/(const byte*) main::name )
|
||||
to:printf_str::@1
|
||||
printf_str::@1: scope:[printf_str] from printf_str printf_str::@2
|
||||
[12] (byte*) screen#10 ← phi( printf_str/(byte*) screen#23 printf_str::@2/(byte*) screen#1 )
|
||||
[12] (byte*) printf_str::str#4 ← phi( printf_str/(byte*) printf_str::str#6 printf_str::@2/(byte*) printf_str::str#0 )
|
||||
[13] if((byte) 0!=*((byte*) printf_str::str#4)) goto printf_str::@2
|
||||
to:printf_str::@return
|
||||
printf_str::@return: scope:[printf_str] from printf_str::@1
|
||||
[14] return
|
||||
to:@return
|
||||
printf_str::@2: scope:[printf_str] from printf_str::@1
|
||||
[15] *((byte*) screen#10) ← *((byte*) printf_str::str#4)
|
||||
[16] (byte*) screen#1 ← ++ (byte*) screen#10
|
||||
[17] (byte*) printf_str::str#0 ← ++ (byte*) printf_str::str#4
|
||||
to:printf_str::@1
|
||||
|
||||
(void()) printf_string((byte*) printf_string::str , (byte) printf_string::format_min_length , (byte) printf_string::format_justify_left)
|
||||
printf_string: scope:[printf_string] from main::@1
|
||||
[18] phi()
|
||||
[19] call printf_str
|
||||
to:printf_string::@return
|
||||
printf_string::@return: scope:[printf_string] from printf_string
|
||||
[20] return
|
||||
to:@return
|
||||
|
||||
|
||||
VARIABLE REGISTER WEIGHTS
|
||||
(void()) main()
|
||||
(byte) printf_format_string::justify_left
|
||||
(byte) printf_format_string::min_length
|
||||
(void()) printf_str((byte*) printf_str::str)
|
||||
(byte*) printf_str::str
|
||||
(byte*) printf_str::str#0 20002.0
|
||||
(byte*) printf_str::str#4 10251.25
|
||||
(byte*) printf_str::str#6 1001.0
|
||||
(void()) printf_string((byte*) printf_string::str , (byte) printf_string::format_min_length , (byte) printf_string::format_justify_left)
|
||||
(struct printf_format_string) printf_string::format
|
||||
(byte) printf_string::format_justify_left
|
||||
(byte) printf_string::format_min_length
|
||||
(byte*) printf_string::str
|
||||
(byte*) screen
|
||||
(byte*) screen#1 10001.0
|
||||
(byte*) screen#10 2828.7272727272725
|
||||
(byte*) screen#23 1113.0
|
||||
|
||||
Initial phi equivalence classes
|
||||
[ screen#23 screen#10 screen#1 ]
|
||||
[ printf_str::str#4 printf_str::str#6 printf_str::str#0 ]
|
||||
Complete equivalence classes
|
||||
[ screen#23 screen#10 screen#1 ]
|
||||
[ printf_str::str#4 printf_str::str#6 printf_str::str#0 ]
|
||||
Allocated zp[2]:2 [ screen#23 screen#10 screen#1 ]
|
||||
Allocated zp[2]:4 [ printf_str::str#4 printf_str::str#6 printf_str::str#0 ]
|
||||
|
||||
INITIAL ASM
|
||||
Target platform is c64basic / MOS6502X
|
||||
// File Comments
|
||||
// Tests printf function call rewriting
|
||||
// A simple string - with the printf-sub cuntions in the same file.
|
||||
// Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(__bbegin)
|
||||
.pc = $80d "Program"
|
||||
// Global Constants & labels
|
||||
.label screen = 2
|
||||
// @begin
|
||||
__bbegin:
|
||||
// [1] phi from @begin to @1 [phi:@begin->@1]
|
||||
__b1_from___bbegin:
|
||||
jmp __b1
|
||||
// @1
|
||||
__b1:
|
||||
// [2] call main
|
||||
// [4] phi from @1 to main [phi:@1->main]
|
||||
main_from___b1:
|
||||
jsr main
|
||||
// [3] phi from @1 to @end [phi:@1->@end]
|
||||
__bend_from___b1:
|
||||
jmp __bend
|
||||
// @end
|
||||
__bend:
|
||||
// main
|
||||
main: {
|
||||
// [5] call printf_str
|
||||
// [11] phi from main to printf_str [phi:main->printf_str]
|
||||
printf_str_from_main:
|
||||
// [11] phi (byte*) screen#23 = (byte*) 1024 [phi:main->printf_str#0] -- pbuz1=pbuc1
|
||||
lda #<$400
|
||||
sta.z screen
|
||||
lda #>$400
|
||||
sta.z screen+1
|
||||
// [11] phi (byte*) printf_str::str#6 = (const byte*) main::str [phi:main->printf_str#1] -- pbuz1=pbuc1
|
||||
lda #<str
|
||||
sta.z printf_str.str
|
||||
lda #>str
|
||||
sta.z printf_str.str+1
|
||||
jsr printf_str
|
||||
// [6] phi from main to main::@1 [phi:main->main::@1]
|
||||
__b1_from_main:
|
||||
jmp __b1
|
||||
// main::@1
|
||||
__b1:
|
||||
// [7] call printf_string
|
||||
// [18] phi from main::@1 to printf_string [phi:main::@1->printf_string]
|
||||
printf_string_from___b1:
|
||||
jsr printf_string
|
||||
// [8] phi from main::@1 to main::@2 [phi:main::@1->main::@2]
|
||||
__b2_from___b1:
|
||||
jmp __b2
|
||||
// main::@2
|
||||
__b2:
|
||||
// [9] call printf_str
|
||||
// [11] phi from main::@2 to printf_str [phi:main::@2->printf_str]
|
||||
printf_str_from___b2:
|
||||
// [11] phi (byte*) screen#23 = (byte*) screen#10 [phi:main::@2->printf_str#0] -- register_copy
|
||||
// [11] phi (byte*) printf_str::str#6 = (const byte*) main::str1 [phi:main::@2->printf_str#1] -- pbuz1=pbuc1
|
||||
lda #<str1
|
||||
sta.z printf_str.str
|
||||
lda #>str1
|
||||
sta.z printf_str.str+1
|
||||
jsr printf_str
|
||||
jmp __breturn
|
||||
// main::@return
|
||||
__breturn:
|
||||
// [10] return
|
||||
rts
|
||||
name: .text "Jesper"
|
||||
.byte 0
|
||||
str: .text "Hello, I am "
|
||||
.byte 0
|
||||
str1: .text ". who are you?"
|
||||
.byte 0
|
||||
}
|
||||
// printf_str
|
||||
// printf_str(byte* zp(4) str)
|
||||
printf_str: {
|
||||
.label str = 4
|
||||
// [12] phi from printf_str printf_str::@2 to printf_str::@1 [phi:printf_str/printf_str::@2->printf_str::@1]
|
||||
__b1_from_printf_str:
|
||||
__b1_from___b2:
|
||||
// [12] phi (byte*) screen#10 = (byte*) screen#23 [phi:printf_str/printf_str::@2->printf_str::@1#0] -- register_copy
|
||||
// [12] phi (byte*) printf_str::str#4 = (byte*) printf_str::str#6 [phi:printf_str/printf_str::@2->printf_str::@1#1] -- register_copy
|
||||
jmp __b1
|
||||
// printf_str::@1
|
||||
__b1:
|
||||
// [13] if((byte) 0!=*((byte*) printf_str::str#4)) goto printf_str::@2 -- vbuc1_neq__deref_pbuz1_then_la1
|
||||
ldy #0
|
||||
lda (str),y
|
||||
cmp #0
|
||||
bne __b2
|
||||
jmp __breturn
|
||||
// printf_str::@return
|
||||
__breturn:
|
||||
// [14] return
|
||||
rts
|
||||
// printf_str::@2
|
||||
__b2:
|
||||
// [15] *((byte*) screen#10) ← *((byte*) printf_str::str#4) -- _deref_pbuz1=_deref_pbuz2
|
||||
ldy #0
|
||||
lda (str),y
|
||||
ldy #0
|
||||
sta (screen),y
|
||||
// [16] (byte*) screen#1 ← ++ (byte*) screen#10 -- pbuz1=_inc_pbuz1
|
||||
inc.z screen
|
||||
bne !+
|
||||
inc.z screen+1
|
||||
!:
|
||||
// [17] (byte*) printf_str::str#0 ← ++ (byte*) printf_str::str#4 -- pbuz1=_inc_pbuz1
|
||||
inc.z str
|
||||
bne !+
|
||||
inc.z str+1
|
||||
!:
|
||||
jmp __b1_from___b2
|
||||
}
|
||||
// printf_string
|
||||
// Print a string value using a specific format
|
||||
// Handles justification and min length
|
||||
printf_string: {
|
||||
// [19] call printf_str
|
||||
// [11] phi from printf_string to printf_str [phi:printf_string->printf_str]
|
||||
printf_str_from_printf_string:
|
||||
// [11] phi (byte*) screen#23 = (byte*) screen#10 [phi:printf_string->printf_str#0] -- register_copy
|
||||
// [11] phi (byte*) printf_str::str#6 = (const byte*) main::name [phi:printf_string->printf_str#1] -- pbuz1=pbuc1
|
||||
lda #<main.name
|
||||
sta.z printf_str.str
|
||||
lda #>main.name
|
||||
sta.z printf_str.str+1
|
||||
jsr printf_str
|
||||
jmp __breturn
|
||||
// printf_string::@return
|
||||
__breturn:
|
||||
// [20] return
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
|
||||
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||
Statement [13] if((byte) 0!=*((byte*) printf_str::str#4)) goto printf_str::@2 [ screen#10 printf_str::str#4 ] ( main:2::printf_str:5 [ screen#10 printf_str::str#4 ] { } main:2::printf_str:9 [ screen#10 printf_str::str#4 ] { { screen#10 = screen#23 } } main:2::printf_string:7::printf_str:19 [ screen#10 printf_str::str#4 ] { { screen#10 = screen#23 } } ) always clobbers reg byte a reg byte y
|
||||
Statement [15] *((byte*) screen#10) ← *((byte*) printf_str::str#4) [ screen#10 printf_str::str#4 ] ( main:2::printf_str:5 [ screen#10 printf_str::str#4 ] { } main:2::printf_str:9 [ screen#10 printf_str::str#4 ] { { screen#10 = screen#23 } } main:2::printf_string:7::printf_str:19 [ screen#10 printf_str::str#4 ] { { screen#10 = screen#23 } } ) always clobbers reg byte a reg byte y
|
||||
Potential registers zp[2]:2 [ screen#23 screen#10 screen#1 ] : zp[2]:2 ,
|
||||
Potential registers zp[2]:4 [ printf_str::str#4 printf_str::str#6 printf_str::str#0 ] : zp[2]:4 ,
|
||||
|
||||
REGISTER UPLIFT SCOPES
|
||||
Uplift Scope [printf_str] 31,254.25: zp[2]:4 [ printf_str::str#4 printf_str::str#6 printf_str::str#0 ]
|
||||
Uplift Scope [] 13,942.73: zp[2]:2 [ screen#23 screen#10 screen#1 ]
|
||||
Uplift Scope [printf_format_string]
|
||||
Uplift Scope [printf_string]
|
||||
Uplift Scope [main]
|
||||
|
||||
Uplifting [printf_str] best 721 combination zp[2]:4 [ printf_str::str#4 printf_str::str#6 printf_str::str#0 ]
|
||||
Uplifting [] best 721 combination zp[2]:2 [ screen#23 screen#10 screen#1 ]
|
||||
Uplifting [printf_format_string] best 721 combination
|
||||
Uplifting [printf_string] best 721 combination
|
||||
Uplifting [main] best 721 combination
|
||||
|
||||
ASSEMBLER BEFORE OPTIMIZATION
|
||||
// File Comments
|
||||
// Tests printf function call rewriting
|
||||
// A simple string - with the printf-sub cuntions in the same file.
|
||||
// Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(__bbegin)
|
||||
.pc = $80d "Program"
|
||||
// Global Constants & labels
|
||||
.label screen = 2
|
||||
// @begin
|
||||
__bbegin:
|
||||
// [1] phi from @begin to @1 [phi:@begin->@1]
|
||||
__b1_from___bbegin:
|
||||
jmp __b1
|
||||
// @1
|
||||
__b1:
|
||||
// [2] call main
|
||||
// [4] phi from @1 to main [phi:@1->main]
|
||||
main_from___b1:
|
||||
jsr main
|
||||
// [3] phi from @1 to @end [phi:@1->@end]
|
||||
__bend_from___b1:
|
||||
jmp __bend
|
||||
// @end
|
||||
__bend:
|
||||
// main
|
||||
main: {
|
||||
// [5] call printf_str
|
||||
// [11] phi from main to printf_str [phi:main->printf_str]
|
||||
printf_str_from_main:
|
||||
// [11] phi (byte*) screen#23 = (byte*) 1024 [phi:main->printf_str#0] -- pbuz1=pbuc1
|
||||
lda #<$400
|
||||
sta.z screen
|
||||
lda #>$400
|
||||
sta.z screen+1
|
||||
// [11] phi (byte*) printf_str::str#6 = (const byte*) main::str [phi:main->printf_str#1] -- pbuz1=pbuc1
|
||||
lda #<str
|
||||
sta.z printf_str.str
|
||||
lda #>str
|
||||
sta.z printf_str.str+1
|
||||
jsr printf_str
|
||||
// [6] phi from main to main::@1 [phi:main->main::@1]
|
||||
__b1_from_main:
|
||||
jmp __b1
|
||||
// main::@1
|
||||
__b1:
|
||||
// [7] call printf_string
|
||||
// [18] phi from main::@1 to printf_string [phi:main::@1->printf_string]
|
||||
printf_string_from___b1:
|
||||
jsr printf_string
|
||||
// [8] phi from main::@1 to main::@2 [phi:main::@1->main::@2]
|
||||
__b2_from___b1:
|
||||
jmp __b2
|
||||
// main::@2
|
||||
__b2:
|
||||
// [9] call printf_str
|
||||
// [11] phi from main::@2 to printf_str [phi:main::@2->printf_str]
|
||||
printf_str_from___b2:
|
||||
// [11] phi (byte*) screen#23 = (byte*) screen#10 [phi:main::@2->printf_str#0] -- register_copy
|
||||
// [11] phi (byte*) printf_str::str#6 = (const byte*) main::str1 [phi:main::@2->printf_str#1] -- pbuz1=pbuc1
|
||||
lda #<str1
|
||||
sta.z printf_str.str
|
||||
lda #>str1
|
||||
sta.z printf_str.str+1
|
||||
jsr printf_str
|
||||
jmp __breturn
|
||||
// main::@return
|
||||
__breturn:
|
||||
// [10] return
|
||||
rts
|
||||
name: .text "Jesper"
|
||||
.byte 0
|
||||
str: .text "Hello, I am "
|
||||
.byte 0
|
||||
str1: .text ". who are you?"
|
||||
.byte 0
|
||||
}
|
||||
// printf_str
|
||||
// printf_str(byte* zp(4) str)
|
||||
printf_str: {
|
||||
.label str = 4
|
||||
// [12] phi from printf_str printf_str::@2 to printf_str::@1 [phi:printf_str/printf_str::@2->printf_str::@1]
|
||||
__b1_from_printf_str:
|
||||
__b1_from___b2:
|
||||
// [12] phi (byte*) screen#10 = (byte*) screen#23 [phi:printf_str/printf_str::@2->printf_str::@1#0] -- register_copy
|
||||
// [12] phi (byte*) printf_str::str#4 = (byte*) printf_str::str#6 [phi:printf_str/printf_str::@2->printf_str::@1#1] -- register_copy
|
||||
jmp __b1
|
||||
// printf_str::@1
|
||||
__b1:
|
||||
// [13] if((byte) 0!=*((byte*) printf_str::str#4)) goto printf_str::@2 -- vbuc1_neq__deref_pbuz1_then_la1
|
||||
ldy #0
|
||||
lda (str),y
|
||||
cmp #0
|
||||
bne __b2
|
||||
jmp __breturn
|
||||
// printf_str::@return
|
||||
__breturn:
|
||||
// [14] return
|
||||
rts
|
||||
// printf_str::@2
|
||||
__b2:
|
||||
// [15] *((byte*) screen#10) ← *((byte*) printf_str::str#4) -- _deref_pbuz1=_deref_pbuz2
|
||||
ldy #0
|
||||
lda (str),y
|
||||
ldy #0
|
||||
sta (screen),y
|
||||
// [16] (byte*) screen#1 ← ++ (byte*) screen#10 -- pbuz1=_inc_pbuz1
|
||||
inc.z screen
|
||||
bne !+
|
||||
inc.z screen+1
|
||||
!:
|
||||
// [17] (byte*) printf_str::str#0 ← ++ (byte*) printf_str::str#4 -- pbuz1=_inc_pbuz1
|
||||
inc.z str
|
||||
bne !+
|
||||
inc.z str+1
|
||||
!:
|
||||
jmp __b1_from___b2
|
||||
}
|
||||
// printf_string
|
||||
// Print a string value using a specific format
|
||||
// Handles justification and min length
|
||||
printf_string: {
|
||||
// [19] call printf_str
|
||||
// [11] phi from printf_string to printf_str [phi:printf_string->printf_str]
|
||||
printf_str_from_printf_string:
|
||||
// [11] phi (byte*) screen#23 = (byte*) screen#10 [phi:printf_string->printf_str#0] -- register_copy
|
||||
// [11] phi (byte*) printf_str::str#6 = (const byte*) main::name [phi:printf_string->printf_str#1] -- pbuz1=pbuc1
|
||||
lda #<main.name
|
||||
sta.z printf_str.str
|
||||
lda #>main.name
|
||||
sta.z printf_str.str+1
|
||||
jsr printf_str
|
||||
jmp __breturn
|
||||
// printf_string::@return
|
||||
__breturn:
|
||||
// [20] return
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
|
||||
ASSEMBLER OPTIMIZATIONS
|
||||
Removing instruction jmp __b1
|
||||
Removing instruction jmp __bend
|
||||
Removing instruction jmp __b1
|
||||
Removing instruction jmp __b2
|
||||
Removing instruction jmp __breturn
|
||||
Removing instruction jmp __b1
|
||||
Removing instruction jmp __breturn
|
||||
Removing instruction jmp __breturn
|
||||
Succesful ASM optimization Pass5NextJumpElimination
|
||||
Removing instruction ldy #0
|
||||
Succesful ASM optimization Pass5UnnecesaryLoadElimination
|
||||
Replacing label __b1_from___b2 with __b1
|
||||
Removing instruction __b1_from___bbegin:
|
||||
Removing instruction __b1:
|
||||
Removing instruction main_from___b1:
|
||||
Removing instruction __bend_from___b1:
|
||||
Removing instruction __b1_from_main:
|
||||
Removing instruction printf_string_from___b1:
|
||||
Removing instruction __b2_from___b1:
|
||||
Removing instruction printf_str_from___b2:
|
||||
Removing instruction __b1_from_printf_str:
|
||||
Removing instruction __b1_from___b2:
|
||||
Succesful ASM optimization Pass5RedundantLabelElimination
|
||||
Removing instruction __bend:
|
||||
Removing instruction printf_str_from_main:
|
||||
Removing instruction __b1:
|
||||
Removing instruction __b2:
|
||||
Removing instruction __breturn:
|
||||
Removing instruction __breturn:
|
||||
Removing instruction printf_str_from_printf_string:
|
||||
Removing instruction __breturn:
|
||||
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||
Updating BasicUpstart to call main directly
|
||||
Removing instruction jsr main
|
||||
Succesful ASM optimization Pass5SkipBegin
|
||||
Removing instruction __bbegin:
|
||||
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||
|
||||
FINAL SYMBOL TABLE
|
||||
(label) @1
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(void()) main()
|
||||
(label) main::@1
|
||||
(label) main::@2
|
||||
(label) main::@return
|
||||
(const byte*) main::name[] = (byte*) "Jesper"
|
||||
(const byte*) main::str[(byte) $d] = (byte*) "Hello, I am "
|
||||
(const byte*) main::str1[(byte) $f] = (byte*) ". who are you?"
|
||||
(byte) printf_format_string::justify_left
|
||||
(byte) printf_format_string::min_length
|
||||
(void()) printf_str((byte*) printf_str::str)
|
||||
(label) printf_str::@1
|
||||
(label) printf_str::@2
|
||||
(label) printf_str::@return
|
||||
(byte*) printf_str::str
|
||||
(byte*) printf_str::str#0 str zp[2]:4 20002.0
|
||||
(byte*) printf_str::str#4 str zp[2]:4 10251.25
|
||||
(byte*) printf_str::str#6 str zp[2]:4 1001.0
|
||||
(void()) printf_string((byte*) printf_string::str , (byte) printf_string::format_min_length , (byte) printf_string::format_justify_left)
|
||||
(label) printf_string::@return
|
||||
(struct printf_format_string) printf_string::format
|
||||
(byte) printf_string::format_justify_left
|
||||
(byte) printf_string::format_min_length
|
||||
(byte*) printf_string::str
|
||||
(byte*) screen
|
||||
(byte*) screen#1 screen zp[2]:2 10001.0
|
||||
(byte*) screen#10 screen zp[2]:2 2828.7272727272725
|
||||
(byte*) screen#23 screen zp[2]:2 1113.0
|
||||
|
||||
zp[2]:2 [ screen#23 screen#10 screen#1 ]
|
||||
zp[2]:4 [ printf_str::str#4 printf_str::str#6 printf_str::str#0 ]
|
||||
|
||||
|
||||
FINAL ASSEMBLER
|
||||
Score: 617
|
||||
|
||||
// File Comments
|
||||
// Tests printf function call rewriting
|
||||
// A simple string - with the printf-sub cuntions in the same file.
|
||||
// Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
// Global Constants & labels
|
||||
.label screen = 2
|
||||
// @begin
|
||||
// [1] phi from @begin to @1 [phi:@begin->@1]
|
||||
// @1
|
||||
// [2] call main
|
||||
// [4] phi from @1 to main [phi:@1->main]
|
||||
// [3] phi from @1 to @end [phi:@1->@end]
|
||||
// @end
|
||||
// main
|
||||
main: {
|
||||
// printf("Hello, I am %s. who are you?", name)
|
||||
// [5] call printf_str
|
||||
// [11] phi from main to printf_str [phi:main->printf_str]
|
||||
// [11] phi (byte*) screen#23 = (byte*) 1024 [phi:main->printf_str#0] -- pbuz1=pbuc1
|
||||
lda #<$400
|
||||
sta.z screen
|
||||
lda #>$400
|
||||
sta.z screen+1
|
||||
// [11] phi (byte*) printf_str::str#6 = (const byte*) main::str [phi:main->printf_str#1] -- pbuz1=pbuc1
|
||||
lda #<str
|
||||
sta.z printf_str.str
|
||||
lda #>str
|
||||
sta.z printf_str.str+1
|
||||
jsr printf_str
|
||||
// [6] phi from main to main::@1 [phi:main->main::@1]
|
||||
// main::@1
|
||||
// printf("Hello, I am %s. who are you?", name)
|
||||
// [7] call printf_string
|
||||
// [18] phi from main::@1 to printf_string [phi:main::@1->printf_string]
|
||||
jsr printf_string
|
||||
// [8] phi from main::@1 to main::@2 [phi:main::@1->main::@2]
|
||||
// main::@2
|
||||
// printf("Hello, I am %s. who are you?", name)
|
||||
// [9] call printf_str
|
||||
// [11] phi from main::@2 to printf_str [phi:main::@2->printf_str]
|
||||
// [11] phi (byte*) screen#23 = (byte*) screen#10 [phi:main::@2->printf_str#0] -- register_copy
|
||||
// [11] phi (byte*) printf_str::str#6 = (const byte*) main::str1 [phi:main::@2->printf_str#1] -- pbuz1=pbuc1
|
||||
lda #<str1
|
||||
sta.z printf_str.str
|
||||
lda #>str1
|
||||
sta.z printf_str.str+1
|
||||
jsr printf_str
|
||||
// main::@return
|
||||
// }
|
||||
// [10] return
|
||||
rts
|
||||
name: .text "Jesper"
|
||||
.byte 0
|
||||
str: .text "Hello, I am "
|
||||
.byte 0
|
||||
str1: .text ". who are you?"
|
||||
.byte 0
|
||||
}
|
||||
// printf_str
|
||||
// printf_str(byte* zp(4) str)
|
||||
printf_str: {
|
||||
.label str = 4
|
||||
// [12] phi from printf_str printf_str::@2 to printf_str::@1 [phi:printf_str/printf_str::@2->printf_str::@1]
|
||||
// [12] phi (byte*) screen#10 = (byte*) screen#23 [phi:printf_str/printf_str::@2->printf_str::@1#0] -- register_copy
|
||||
// [12] phi (byte*) printf_str::str#4 = (byte*) printf_str::str#6 [phi:printf_str/printf_str::@2->printf_str::@1#1] -- register_copy
|
||||
// printf_str::@1
|
||||
__b1:
|
||||
// while(*str)
|
||||
// [13] if((byte) 0!=*((byte*) printf_str::str#4)) goto printf_str::@2 -- vbuc1_neq__deref_pbuz1_then_la1
|
||||
ldy #0
|
||||
lda (str),y
|
||||
cmp #0
|
||||
bne __b2
|
||||
// printf_str::@return
|
||||
// }
|
||||
// [14] return
|
||||
rts
|
||||
// printf_str::@2
|
||||
__b2:
|
||||
// *screen++ = *str++
|
||||
// [15] *((byte*) screen#10) ← *((byte*) printf_str::str#4) -- _deref_pbuz1=_deref_pbuz2
|
||||
ldy #0
|
||||
lda (str),y
|
||||
sta (screen),y
|
||||
// *screen++ = *str++;
|
||||
// [16] (byte*) screen#1 ← ++ (byte*) screen#10 -- pbuz1=_inc_pbuz1
|
||||
inc.z screen
|
||||
bne !+
|
||||
inc.z screen+1
|
||||
!:
|
||||
// [17] (byte*) printf_str::str#0 ← ++ (byte*) printf_str::str#4 -- pbuz1=_inc_pbuz1
|
||||
inc.z str
|
||||
bne !+
|
||||
inc.z str+1
|
||||
!:
|
||||
jmp __b1
|
||||
}
|
||||
// printf_string
|
||||
// Print a string value using a specific format
|
||||
// Handles justification and min length
|
||||
printf_string: {
|
||||
// printf_str(str)
|
||||
// [19] call printf_str
|
||||
// [11] phi from printf_string to printf_str [phi:printf_string->printf_str]
|
||||
// [11] phi (byte*) screen#23 = (byte*) screen#10 [phi:printf_string->printf_str#0] -- register_copy
|
||||
// [11] phi (byte*) printf_str::str#6 = (const byte*) main::name [phi:printf_string->printf_str#1] -- pbuz1=pbuc1
|
||||
lda #<main.name
|
||||
sta.z printf_str.str
|
||||
lda #>main.name
|
||||
sta.z printf_str.str+1
|
||||
jsr printf_str
|
||||
// printf_string::@return
|
||||
// }
|
||||
// [20] return
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
|
33
src/test/ref/printf-10.sym
Normal file
33
src/test/ref/printf-10.sym
Normal file
@ -0,0 +1,33 @@
|
||||
(label) @1
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(void()) main()
|
||||
(label) main::@1
|
||||
(label) main::@2
|
||||
(label) main::@return
|
||||
(const byte*) main::name[] = (byte*) "Jesper"
|
||||
(const byte*) main::str[(byte) $d] = (byte*) "Hello, I am "
|
||||
(const byte*) main::str1[(byte) $f] = (byte*) ". who are you?"
|
||||
(byte) printf_format_string::justify_left
|
||||
(byte) printf_format_string::min_length
|
||||
(void()) printf_str((byte*) printf_str::str)
|
||||
(label) printf_str::@1
|
||||
(label) printf_str::@2
|
||||
(label) printf_str::@return
|
||||
(byte*) printf_str::str
|
||||
(byte*) printf_str::str#0 str zp[2]:4 20002.0
|
||||
(byte*) printf_str::str#4 str zp[2]:4 10251.25
|
||||
(byte*) printf_str::str#6 str zp[2]:4 1001.0
|
||||
(void()) printf_string((byte*) printf_string::str , (byte) printf_string::format_min_length , (byte) printf_string::format_justify_left)
|
||||
(label) printf_string::@return
|
||||
(struct printf_format_string) printf_string::format
|
||||
(byte) printf_string::format_justify_left
|
||||
(byte) printf_string::format_min_length
|
||||
(byte*) printf_string::str
|
||||
(byte*) screen
|
||||
(byte*) screen#1 screen zp[2]:2 10001.0
|
||||
(byte*) screen#10 screen zp[2]:2 2828.7272727272725
|
||||
(byte*) screen#23 screen zp[2]:2 1113.0
|
||||
|
||||
zp[2]:2 [ screen#23 screen#10 screen#1 ]
|
||||
zp[2]:4 [ printf_str::str#4 printf_str::str#6 printf_str::str#0 ]
|
12
src/test/vs.code/kickc-test.code-workspace
Normal file
12
src/test/vs.code/kickc-test.code-workspace
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"folders": [
|
||||
{
|
||||
"path": "../kc"
|
||||
}
|
||||
],
|
||||
"settings": {
|
||||
"files.associations": {
|
||||
"print.h": "c"
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user