mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-12-26 03:32:23 +00:00
This commit is contained in:
parent
9fa2e5d734
commit
28c9b2ada7
@ -22,6 +22,12 @@ public class Pass1PrintfIntrinsicRewrite extends Pass2SsaOptimization {
|
||||
|
||||
/** The printf procedure name. */
|
||||
public static final String INTRINSIC_PRINTF_NAME = "printf";
|
||||
/** The printf routine used to print formatted strings. */
|
||||
public static final String PRINTF_STRING = "printf_string";
|
||||
/** The printf routine used to print signed integers. */
|
||||
public static final String PRINTF_SINT = "printf_sint";
|
||||
/** The printf routine used to print unsigned integers. */
|
||||
public static final String PRINTF_UINT = "printf_uint";
|
||||
|
||||
public Pass1PrintfIntrinsicRewrite(Program program) {
|
||||
super(program);
|
||||
@ -48,7 +54,7 @@ public class Pass1PrintfIntrinsicRewrite extends Pass2SsaOptimization {
|
||||
// Remove the call to printf()
|
||||
stmtIt.remove();
|
||||
|
||||
// Printf Placeholder Format String
|
||||
// Printf Placeholder Format String - source: https://en.wikipedia.org/wiki/Printf_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)
|
||||
@ -68,31 +74,78 @@ public class Pass1PrintfIntrinsicRewrite extends Pass2SsaOptimization {
|
||||
}
|
||||
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)
|
||||
final String paramField = matcher.group(1);
|
||||
if(paramField != null)
|
||||
throw new CompileError("printf parameter field not supported", printfCall);
|
||||
|
||||
// First grab the non-matching part
|
||||
final String flagsField = matcher.group(2);
|
||||
long leftJustify = (flagsField != null && flagsField.contains("-")) ? 1 : 0;
|
||||
long signAlways = (flagsField != null && flagsField.contains("+")) ? 1 : 0;
|
||||
long zeroPadding = (flagsField != null && flagsField.contains("0")) ? 1 : 0;
|
||||
|
||||
final String widthField = matcher.group(3);
|
||||
long width = (widthField == null) ? 0 : Integer.parseInt(widthField);
|
||||
|
||||
final String lengthField = matcher.group(4);
|
||||
|
||||
final String typeField = matcher.group(5);
|
||||
|
||||
// First output the non-matching part before the pattern
|
||||
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);
|
||||
|
||||
|
||||
if(typeField.equals("s")) {
|
||||
// A formatted string
|
||||
//struct printf_format_string {
|
||||
// char min_length; // The minimal number of chars to output (used for padding with spaces or 0).
|
||||
// char justify_left; // Justify left instead of right, which is the default.
|
||||
//};
|
||||
final ValueList format_string_struct =
|
||||
new ValueList(Arrays.asList(
|
||||
new ConstantInteger(width, 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("diuxXo".contains(typeField)) {
|
||||
// A formatted integer
|
||||
SymbolVariableRef radix;
|
||||
String printf_number_procedure;
|
||||
if(typeField.equals("d")) {
|
||||
radix = getScope().getLocalConstant("DECIMAL").getRef();
|
||||
printf_number_procedure = PRINTF_SINT;
|
||||
} else if(typeField.equals("x")) {
|
||||
radix = getScope().getLocalConstant("HEXADECIMAL").getRef();
|
||||
printf_number_procedure = PRINTF_UINT;
|
||||
} else {
|
||||
throw new CompileError("printf type field not supported", printfCall);
|
||||
}
|
||||
|
||||
// Format specifying how to format a printed number
|
||||
// struct printf_format_number {
|
||||
// char min_length; // The minimal number of chars to output (used for padding with spaces or 0)
|
||||
// char justify_left; // Justify left instead of right, which is the default.
|
||||
// char sign_always; // Always show a sign for a number, even if is is positive. (Default is to only show sign for negative numbers)
|
||||
// char zero_padding; // Pad the number with zeros to get the min width
|
||||
// enum RADIX radix; // The number radix to use for formatting
|
||||
// };
|
||||
final ValueList format_number_struct =
|
||||
new ValueList(Arrays.asList(
|
||||
new ConstantInteger(width, SymbolType.BYTE),
|
||||
new ConstantInteger(leftJustify, SymbolType.BYTE),
|
||||
new ConstantInteger(signAlways, SymbolType.BYTE),
|
||||
new ConstantInteger(zeroPadding, SymbolType.BYTE),
|
||||
radix
|
||||
));
|
||||
final StatementCall call_printf_str = new StatementCall(null, printf_number_procedure, Arrays.asList(parameters.get(paramIdx), format_number_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
|
||||
@ -106,6 +159,7 @@ public class Pass1PrintfIntrinsicRewrite extends Pass2SsaOptimization {
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
@ -42,7 +42,7 @@ public class TestPrograms {
|
||||
|
||||
@Test
|
||||
public void testPintf10() throws IOException, URISyntaxException {
|
||||
compileAndCompare("printf-10.c", log());
|
||||
compileAndCompare("printf-10.c");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -26,8 +26,37 @@ 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);
|
||||
// The different supported radix
|
||||
enum RADIX { BINARY=2, OCTAL=8, DECIMAL=10, HEXADECIMAL=16 };
|
||||
|
||||
// Format specifying how to format a printed number
|
||||
struct printf_format_number {
|
||||
// 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;
|
||||
// Always show a sign for a number, even if is is positive. (Default is to only show sign for negative numbers)
|
||||
char sign_always;
|
||||
// Pad the number with zeros to get the min width
|
||||
char zero_padding;
|
||||
// The number radix to use for formatting
|
||||
enum RADIX radix;
|
||||
};
|
||||
|
||||
const char printf_hextab[] = "0123456789abcdef"z;
|
||||
|
||||
// Print an unsigned int using a specific format
|
||||
// Always prints hexadecimals - ignores min_length and flags
|
||||
void printf_uint(unsigned int uvalue, struct printf_format_number format) {
|
||||
*screen++ = printf_hextab[(>uvalue)>>4];
|
||||
*screen++ = printf_hextab[(>uvalue)&0xf];
|
||||
*screen++ = printf_hextab[(<uvalue)>>4];
|
||||
*screen++ = printf_hextab[(<uvalue)&0xf];
|
||||
}
|
||||
|
||||
void main() {
|
||||
unsigned int age = 46;
|
||||
printf("Hello, I am %s. who are you?", "Jesper");
|
||||
printf("I am %x years old", age);
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,8 @@
|
||||
.pc = $80d "Program"
|
||||
.label screen = 2
|
||||
main: {
|
||||
// printf("Hello, I am %s. who are you?", name)
|
||||
.label age = $2e
|
||||
// printf("Hello, I am %s. who are you?", "Jesper")
|
||||
lda #<$400
|
||||
sta.z screen
|
||||
lda #>$400
|
||||
@ -15,21 +16,39 @@ main: {
|
||||
lda #>str
|
||||
sta.z printf_str.str+1
|
||||
jsr printf_str
|
||||
// printf("Hello, I am %s. who are you?", name)
|
||||
// printf("Hello, I am %s. who are you?", "Jesper")
|
||||
jsr printf_string
|
||||
// printf("Hello, I am %s. who are you?", name)
|
||||
lda #<str1
|
||||
// printf("Hello, I am %s. who are you?", "Jesper")
|
||||
lda #<str2
|
||||
sta.z printf_str.str
|
||||
lda #>str1
|
||||
lda #>str2
|
||||
sta.z printf_str.str+1
|
||||
jsr printf_str
|
||||
// printf("I am %x years old", age)
|
||||
lda #<str3
|
||||
sta.z printf_str.str
|
||||
lda #>str3
|
||||
sta.z printf_str.str+1
|
||||
jsr printf_str
|
||||
// printf("I am %x years old", age)
|
||||
jsr printf_uint
|
||||
// printf("I am %x years old", age)
|
||||
lda #<str4
|
||||
sta.z printf_str.str
|
||||
lda #>str4
|
||||
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?"
|
||||
str1: .text "Jesper"
|
||||
.byte 0
|
||||
str2: .text ". who are you?"
|
||||
.byte 0
|
||||
str3: .text "I am "
|
||||
.byte 0
|
||||
str4: .text " years old"
|
||||
.byte 0
|
||||
}
|
||||
// printf_str(byte* zp(4) str)
|
||||
@ -59,15 +78,58 @@ printf_str: {
|
||||
!:
|
||||
jmp __b1
|
||||
}
|
||||
// Print an unsigned int using a specific format
|
||||
// Always prints hexadecimals - ignores min_length and flags
|
||||
printf_uint: {
|
||||
// *screen++ = printf_hextab[(>uvalue)>>4]
|
||||
lda printf_hextab
|
||||
ldy #0
|
||||
sta (screen),y
|
||||
// *screen++ = printf_hextab[(>uvalue)>>4];
|
||||
inc.z screen
|
||||
bne !+
|
||||
inc.z screen+1
|
||||
!:
|
||||
// *screen++ = printf_hextab[(>uvalue)&0xf]
|
||||
lda printf_hextab
|
||||
ldy #0
|
||||
sta (screen),y
|
||||
// *screen++ = printf_hextab[(>uvalue)&0xf];
|
||||
inc.z screen
|
||||
bne !+
|
||||
inc.z screen+1
|
||||
!:
|
||||
// *screen++ = printf_hextab[(<uvalue)>>4]
|
||||
lda printf_hextab+((<main.age)>>4)
|
||||
ldy #0
|
||||
sta (screen),y
|
||||
// *screen++ = printf_hextab[(<uvalue)>>4];
|
||||
inc.z screen
|
||||
bne !+
|
||||
inc.z screen+1
|
||||
!:
|
||||
// *screen++ = printf_hextab[(<uvalue)&0xf]
|
||||
lda printf_hextab+((<main.age)&$f)
|
||||
ldy #0
|
||||
sta (screen),y
|
||||
// *screen++ = printf_hextab[(<uvalue)&0xf];
|
||||
inc.z screen
|
||||
bne !+
|
||||
inc.z screen+1
|
||||
!:
|
||||
// }
|
||||
rts
|
||||
}
|
||||
// Print a string value using a specific format
|
||||
// Handles justification and min length
|
||||
printf_string: {
|
||||
// printf_str(str)
|
||||
lda #<main.name
|
||||
lda #<main.str1
|
||||
sta.z printf_str.str
|
||||
lda #>main.name
|
||||
lda #>main.str1
|
||||
sta.z printf_str.str+1
|
||||
jsr printf_str
|
||||
// }
|
||||
rts
|
||||
}
|
||||
printf_hextab: .text "0123456789abcdef"
|
||||
|
@ -20,35 +20,62 @@ main::@1: scope:[main] from main
|
||||
main::@2: scope:[main] from main::@1
|
||||
[8] phi()
|
||||
[9] call printf_str
|
||||
to:main::@3
|
||||
main::@3: scope:[main] from main::@2
|
||||
[10] phi()
|
||||
[11] call printf_str
|
||||
to:main::@4
|
||||
main::@4: scope:[main] from main::@3
|
||||
[12] phi()
|
||||
[13] call printf_uint
|
||||
to:main::@5
|
||||
main::@5: scope:[main] from main::@4
|
||||
[14] phi()
|
||||
[15] call printf_str
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@2
|
||||
[10] return
|
||||
main::@return: scope:[main] from main::@5
|
||||
[16] 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 )
|
||||
printf_str: scope:[printf_str] from main main::@2 main::@3 main::@5 printf_string
|
||||
[17] (byte*) screen#36 ← phi( main/(byte*) 1024 main::@2/(byte*) screen#18 main::@3/(byte*) screen#18 main::@5/(byte*) screen#23 printf_string/(byte*) screen#18 )
|
||||
[17] (byte*) printf_str::str#8 ← phi( main/(const byte*) main::str main::@2/(const byte*) main::str2 main::@3/(const byte*) main::str3 main::@5/(const byte*) main::str4 printf_string/(const byte*) main::str1 )
|
||||
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
|
||||
[18] (byte*) screen#18 ← phi( printf_str/(byte*) screen#36 printf_str::@2/(byte*) screen#1 )
|
||||
[18] (byte*) printf_str::str#6 ← phi( printf_str/(byte*) printf_str::str#8 printf_str::@2/(byte*) printf_str::str#0 )
|
||||
[19] if((byte) 0!=*((byte*) printf_str::str#6)) goto printf_str::@2
|
||||
to:printf_str::@return
|
||||
printf_str::@return: scope:[printf_str] from printf_str::@1
|
||||
[14] return
|
||||
[20] 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
|
||||
[21] *((byte*) screen#18) ← *((byte*) printf_str::str#6)
|
||||
[22] (byte*) screen#1 ← ++ (byte*) screen#18
|
||||
[23] (byte*) printf_str::str#0 ← ++ (byte*) printf_str::str#6
|
||||
to:printf_str::@1
|
||||
|
||||
(void()) printf_uint((word) printf_uint::uvalue , (byte) printf_uint::format_min_length , (byte) printf_uint::format_justify_left , (byte) printf_uint::format_sign_always , (byte) printf_uint::format_zero_padding , (byte) printf_uint::format_radix)
|
||||
printf_uint: scope:[printf_uint] from main::@4
|
||||
[24] *((byte*) screen#18) ← *((const to_nomodify byte*) printf_hextab)
|
||||
[25] (byte*) screen#5 ← ++ (byte*) screen#18
|
||||
[26] *((byte*) screen#5) ← *((const to_nomodify byte*) printf_hextab)
|
||||
[27] (byte*) screen#6 ← ++ (byte*) screen#5
|
||||
[28] *((byte*) screen#6) ← *((const to_nomodify byte*) printf_hextab+<(const word) main::age>>(byte) 4)
|
||||
[29] (byte*) screen#7 ← ++ (byte*) screen#6
|
||||
[30] *((byte*) screen#7) ← *((const to_nomodify byte*) printf_hextab+<(const word) main::age&(byte) $f)
|
||||
[31] (byte*) screen#23 ← ++ (byte*) screen#7
|
||||
to:printf_uint::@return
|
||||
printf_uint::@return: scope:[printf_uint] from printf_uint
|
||||
[32] 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
|
||||
[18] phi()
|
||||
[19] call printf_str
|
||||
[33] phi()
|
||||
[34] call printf_str
|
||||
to:printf_string::@return
|
||||
printf_string::@return: scope:[printf_string] from printf_string
|
||||
[20] return
|
||||
[35] return
|
||||
to:@return
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,33 +1,62 @@
|
||||
(label) @1
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(const byte) RADIX::BINARY = (number) 2
|
||||
(const byte) RADIX::DECIMAL = (number) $a
|
||||
(const byte) RADIX::HEXADECIMAL = (number) $10
|
||||
(const byte) RADIX::OCTAL = (number) 8
|
||||
(void()) main()
|
||||
(label) main::@1
|
||||
(label) main::@2
|
||||
(label) main::@3
|
||||
(label) main::@4
|
||||
(label) main::@5
|
||||
(label) main::@return
|
||||
(const byte*) main::name[] = (byte*) "Jesper"
|
||||
(const word) main::age = (word) $2e
|
||||
(const byte*) main::str[(byte) $d] = (byte*) "Hello, I am "
|
||||
(const byte*) main::str1[(byte) $f] = (byte*) ". who are you?"
|
||||
(const byte*) main::str1[(byte) 7] = (byte*) "Jesper"
|
||||
(const byte*) main::str2[(byte) $f] = (byte*) ". who are you?"
|
||||
(const byte*) main::str3[(byte) 6] = (byte*) "I am "
|
||||
(const byte*) main::str4[(byte) $b] = (byte*) " years old"
|
||||
(byte) printf_format_number::justify_left
|
||||
(byte) printf_format_number::min_length
|
||||
(byte) printf_format_number::radix
|
||||
(byte) printf_format_number::sign_always
|
||||
(byte) printf_format_number::zero_padding
|
||||
(byte) printf_format_string::justify_left
|
||||
(byte) printf_format_string::min_length
|
||||
(const to_nomodify byte*) printf_hextab[] = (byte*) "0123456789abcdef"z
|
||||
(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
|
||||
(byte*) printf_str::str#6 str zp[2]:4 10251.25
|
||||
(byte*) printf_str::str#8 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
|
||||
(void()) printf_uint((word) printf_uint::uvalue , (byte) printf_uint::format_min_length , (byte) printf_uint::format_justify_left , (byte) printf_uint::format_sign_always , (byte) printf_uint::format_zero_padding , (byte) printf_uint::format_radix)
|
||||
(label) printf_uint::@return
|
||||
(struct printf_format_number) printf_uint::format
|
||||
(byte) printf_uint::format_justify_left
|
||||
(byte) printf_uint::format_min_length
|
||||
(byte) printf_uint::format_radix
|
||||
(byte) printf_uint::format_sign_always
|
||||
(byte) printf_uint::format_zero_padding
|
||||
(word) printf_uint::uvalue
|
||||
(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
|
||||
(byte*) screen#18 screen zp[2]:2 1958.0625
|
||||
(byte*) screen#23 screen zp[2]:2 28.0
|
||||
(byte*) screen#36 screen zp[2]:2 1135.0
|
||||
(byte*) screen#5 screen zp[2]:2 151.5
|
||||
(byte*) screen#6 screen zp[2]:2 151.5
|
||||
(byte*) screen#7 screen zp[2]:2 151.5
|
||||
|
||||
zp[2]:2 [ screen#23 screen#10 screen#1 ]
|
||||
zp[2]:4 [ printf_str::str#4 printf_str::str#6 printf_str::str#0 ]
|
||||
zp[2]:2 [ screen#36 screen#18 screen#23 screen#1 screen#5 screen#7 screen#6 ]
|
||||
zp[2]:4 [ printf_str::str#6 printf_str::str#8 printf_str::str#0 ]
|
||||
|
Loading…
Reference in New Issue
Block a user