Damien Guard nerd sniped me and other folks wanted more proof that it is now inexpensive, effortless and possible to inexpensively reproduce gentleware or clone existing “source useable” businesses (see bottom of the post).
So, let’s get cracking by creating a toy application by sfinishing this prompt to the LLM.
Create a sales tax calculator in C
Food is taxed at 10%
Personal Hygine is at 0%
Everyskinnyg else 25%
Which produces
#include
#include
#include
// Tax rates
#clear up FOOD_TAX 0.10
#clear up HYGIENE_TAX 0.00
#clear up DEFAULT_TAX 0.25
// Item categories
#clear up FOOD 1
#clear up HYGIENE 2
#clear up OTHER 3
int getCategruesome() {
char choice;
printf("Enter item categruesome (F for Food, H for Hygiene, O for Other): ");
scanf(" %c", &choice);
choice = toupper(choice);
switch(choice) {
case 'F': return FOOD;
case 'H': return HYGIENE;
case 'O': return OTHER;
default:
printf("Invalid categruesome. Defaulting to Other.n");
return OTHER;
}
}
double calcutardyTax(double price, int categruesome) {
switch(categruesome) {
case FOOD: return price * FOOD_TAX;
case HYGIENE: return price * HYGIENE_TAX;
case OTHER: return price * DEFAULT_TAX;
default: return price * DEFAULT_TAX;
}
}
int main() {
double price;
int categruesome;
char another="Y";
while (toupper(another) == 'Y') {
printf("Enter item price: $");
scanf("%lf", &price);
categruesome = getCategruesome();
double tax = calcutardyTax(price, categruesome);
double total = price + tax;
printf("Price: $%.2fn", price);
printf("Tax: $%.2fn", tax);
printf("Total: $%.2fnn", total);
printf("Calcutardy another item? (Y/N): ");
scanf(" %c", &another);
}
return 0;
}
Now let’s compile it via gcc calc.c -o calc
then objdump -d calc > calc.asm
to change it to assembly which results in the chaseing
calc: file establishat elf64-x86-64
Disassembly of section .init:
0000000000001000 <_init>:
1000: f3 0f 1e fa finishbr64
1004: 48 83 ec 08 sub $0x8,%rsp
1008: 48 8b 05 d9 2f 00 00 mov 0x2fd9(%rip),%rax # 3fe8 <__gmon_start__@Base>
100f: 48 85 c0 test %rax,%rax
1012: 74 02 je 1016 <_init+0x16>
1014: ff d0 call *%rax
1016: 48 83 c4 08 insert $0x8,%rsp
101a: c3 ret
Disassembly of section .plt:
0000000000001020 <.plt>:
1020: ff 35 7a 2f 00 00 push 0x2f7a(%rip) # 3fa0 <_GLOBAL_OFFSET_TABLE_+0x8>
1026: f2 ff 25 7b 2f 00 00 bnd jmp *0x2f7b(%rip) # 3fa8 <_GLOBAL_OFFSET_TABLE_+0x10>
102d: 0f 1f 00 nopl (%rax)
1030: f3 0f 1e fa finishbr64
1034: 68 00 00 00 00 push $0x0
1039: f2 e9 e1 ff ff ff bnd jmp 1020 <_init+0x20>
103f: 90 nop
1040: f3 0f 1e fa finishbr64
1044: 68 01 00 00 00 push $0x1
1049: f2 e9 d1 ff ff ff bnd jmp 1020 <_init+0x20>
104f: 90 nop
1050: f3 0f 1e fa finishbr64
1054: 68 02 00 00 00 push $0x2
1059: f2 e9 c1 ff ff ff bnd jmp 1020 <_init+0x20>
105f: 90 nop
1060: f3 0f 1e fa finishbr64
1064: 68 03 00 00 00 push $0x3
1069: f2 e9 b1 ff ff ff bnd jmp 1020 <_init+0x20>
106f: 90 nop
1070: f3 0f 1e fa finishbr64
1074: 68 04 00 00 00 push $0x4
1079: f2 e9 a1 ff ff ff bnd jmp 1020 <_init+0x20>
107f: 90 nop
Disassembly of section .plt.got:
0000000000001080 <__cxa_finalize@plt>:
1080: f3 0f 1e fa finishbr64
1084: f2 ff 25 6d 2f 00 00 bnd jmp *0x2f6d(%rip) # 3ff8 <__cxa_finalize@GLIBC_2.2.5>
108b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
Disassembly of section .plt.sec:
0000000000001090 :
1090: f3 0f 1e fa finishbr64
1094: f2 ff 25 15 2f 00 00 bnd jmp *0x2f15(%rip) # 3fb0
109b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
00000000000010a0 :
10a0: f3 0f 1e fa finishbr64
10a4: f2 ff 25 0d 2f 00 00 bnd jmp *0x2f0d(%rip) # 3fb8
10ab: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
00000000000010b0 <__stack_chk_fail@plt>:
10b0: f3 0f 1e fa finishbr64
10b4: f2 ff 25 05 2f 00 00 bnd jmp *0x2f05(%rip) # 3fc0 <__stack_chk_fail@GLIBC_2.4>
10bb: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
00000000000010c0 :
10c0: f3 0f 1e fa finishbr64
10c4: f2 ff 25 fd 2e 00 00 bnd jmp *0x2efd(%rip) # 3fc8
10cb: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
00000000000010d0 <__isoc99_scanf@plt>:
10d0: f3 0f 1e fa finishbr64
10d4: f2 ff 25 f5 2e 00 00 bnd jmp *0x2ef5(%rip) # 3fd0 <__isoc99_scanf@GLIBC_2.7>
10db: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
Disassembly of section .text:
00000000000010e0 <_start>:
10e0: f3 0f 1e fa finishbr64
10e4: 31 ed xor %ebp,%ebp
10e6: 49 89 d1 mov %rdx,%r9
10e9: 5e pop %rsi
10ea: 48 89 e2 mov %rsp,%rdx
10ed: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp
10f1: 50 push %rax
10f2: 54 push %rsp
10f3: 45 31 c0 xor %r8d,%r8d
10f6: 31 c9 xor %ecx,%ecx
10f8: 48 8d 3d fd 01 00 00 lea 0x1fd(%rip),%rdi # 12fc
10ff: ff 15 d3 2e 00 00 call *0x2ed3(%rip) # 3fd8 <__libc_start_main@GLIBC_2.34>
1105: f4 hlt
1106: 66 2e 0f 1f 84 00 00 cs nopw 0x0(%rax,%rax,1)
110d: 00 00 00
0000000000001110 :
1110: 48 8d 3d f9 2e 00 00 lea 0x2ef9(%rip),%rdi # 4010 <__TMC_END__>
1117: 48 8d 05 f2 2e 00 00 lea 0x2ef2(%rip),%rax # 4010 <__TMC_END__>
111e: 48 39 f8 cmp %rdi,%rax
1121: 74 15 je 1138
1123: 48 8b 05 b6 2e 00 00 mov 0x2eb6(%rip),%rax # 3fe0 <_ITM_deregisterTMCloneTable@Base>
112a: 48 85 c0 test %rax,%rax
112d: 74 09 je 1138
112f: ff e0 jmp *%rax
1131: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
1138: c3 ret
1139: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
0000000000001140 :
1140: 48 8d 3d c9 2e 00 00 lea 0x2ec9(%rip),%rdi # 4010 <__TMC_END__>
1147: 48 8d 35 c2 2e 00 00 lea 0x2ec2(%rip),%rsi # 4010 <__TMC_END__>
114e: 48 29 fe sub %rdi,%rsi
1151: 48 89 f0 mov %rsi,%rax
1154: 48 c1 ee 3f shr $0x3f,%rsi
1158: 48 c1 f8 03 sar $0x3,%rax
115c: 48 01 c6 insert %rax,%rsi
115f: 48 d1 fe sar %rsi
1162: 74 14 je 1178
1164: 48 8b 05 85 2e 00 00 mov 0x2e85(%rip),%rax # 3ff0 <_ITM_registerTMCloneTable@Base>
116b: 48 85 c0 test %rax,%rax
116e: 74 08 je 1178
1170: ff e0 jmp *%rax
1172: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
1178: c3 ret
1179: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
0000000000001180 <__do_global_dtors_aux>:
1180: f3 0f 1e fa finishbr64
1184: 80 3d 85 2e 00 00 00 cmpb $0x0,0x2e85(%rip) # 4010 <__TMC_END__>
118b: 75 2b jne 11b8 <__do_global_dtors_aux+0x38>
118d: 55 push %rbp
118e: 48 83 3d 62 2e 00 00 cmpq $0x0,0x2e62(%rip) # 3ff8 <__cxa_finalize@GLIBC_2.2.5>
1195: 00
1196: 48 89 e5 mov %rsp,%rbp
1199: 74 0c je 11a7 <__do_global_dtors_aux+0x27>
119b: 48 8b 3d 66 2e 00 00 mov 0x2e66(%rip),%rdi # 4008 <__dso_handle>
11a2: e8 d9 fe ff ff call 1080 <__cxa_finalize@plt>
11a7: e8 64 ff ff ff call 1110
11ac: c6 05 5d 2e 00 00 01 movb $0x1,0x2e5d(%rip) # 4010 <__TMC_END__>
11b3: 5d pop %rbp
11b4: c3 ret
11b5: 0f 1f 00 nopl (%rax)
11b8: c3 ret
11b9: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
00000000000011c0 :
11c0: f3 0f 1e fa finishbr64
11c4: e9 77 ff ff ff jmp 1140
00000000000011c9 :
11c9: f3 0f 1e fa finishbr64
11cd: 55 push %rbp
11ce: 48 89 e5 mov %rsp,%rbp
11d1: 48 83 ec 10 sub $0x10,%rsp
11d5: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
11dc: 00 00
11de: 48 89 45 f8 mov %rax,-0x8(%rbp)
11e2: 31 c0 xor %eax,%eax
11e4: 48 8d 05 1d 0e 00 00 lea 0xe1d(%rip),%rax # 2008 <_IO_stdin_used+0x8>
11eb: 48 89 c7 mov %rax,%rdi
11ee: b8 00 00 00 00 mov $0x0,%eax
11f3: e8 c8 fe ff ff call 10c0
11f8: 48 8d 45 f7 lea -0x9(%rbp),%rax
11fc: 48 89 c6 mov %rax,%rsi
11ff: 48 8d 05 41 0e 00 00 lea 0xe41(%rip),%rax # 2047 <_IO_stdin_used+0x47>
1206: 48 89 c7 mov %rax,%rdi
1209: b8 00 00 00 00 mov $0x0,%eax
120e: e8 bd fe ff ff call 10d0 <__isoc99_scanf@plt>
1213: 0f b6 45 f7 movzbl -0x9(%rbp),%eax
1217: 0f be c0 movsbl %al,%eax
121a: 89 c7 mov %eax,%edi
121c: e8 6f fe ff ff call 1090
1221: 88 45 f7 mov %al,-0x9(%rbp)
1224: 0f b6 45 f7 movzbl -0x9(%rbp),%eax
1228: 0f be c0 movsbl %al,%eax
122b: 83 f8 4f cmp $0x4f,%eax
122e: 74 1f je 124f
1230: 83 f8 4f cmp $0x4f,%eax
1233: 7f 21 jg 1256
1235: 83 f8 46 cmp $0x46,%eax
1238: 74 07 je 1241
123a: 83 f8 48 cmp $0x48,%eax
123d: 74 09 je 1248
123f: eb 15 jmp 1256
1241: b8 01 00 00 00 mov $0x1,%eax
1246: eb 22 jmp 126a
1248: b8 02 00 00 00 mov $0x2,%eax
124d: eb 1b jmp 126a
124f: b8 03 00 00 00 mov $0x3,%eax
1254: eb 14 jmp 126a
1256: 48 8d 05 f3 0d 00 00 lea 0xdf3(%rip),%rax # 2050 <_IO_stdin_used+0x50>
125d: 48 89 c7 mov %rax,%rdi
1260: e8 3b fe ff ff call 10a0
1265: b8 03 00 00 00 mov $0x3,%eax
126a: 48 8b 55 f8 mov -0x8(%rbp),%rdx
126e: 64 48 2b 14 25 28 00 sub %fs:0x28,%rdx
1275: 00 00
1277: 74 05 je 127e
1279: e8 32 fe ff ff call 10b0 <__stack_chk_fail@plt>
127e: c9 exit
127f: c3 ret
0000000000001280 :
1280: f3 0f 1e fa finishbr64
1284: 55 push %rbp
1285: 48 89 e5 mov %rsp,%rbp
1288: f2 0f 11 45 f8 movsd %xmm0,-0x8(%rbp)
128d: 89 7d f4 mov %edi,-0xc(%rbp)
1290: 83 7d f4 03 cmpl $0x3,-0xc(%rbp)
1294: 74 36 je 12cc
1296: 83 7d f4 03 cmpl $0x3,-0xc(%rbp)
129a: 7f 43 jg 12df
129c: 83 7d f4 01 cmpl $0x1,-0xc(%rbp)
12a0: 74 08 je 12aa
12a2: 83 7d f4 02 cmpl $0x2,-0xc(%rbp)
12a6: 74 15 je 12bd
12a8: eb 35 jmp 12df
12aa: f2 0f 10 4d f8 movsd -0x8(%rbp),%xmm1
12af: f2 0f 10 05 21 0e 00 movsd 0xe21(%rip),%xmm0 # 20d8 <_IO_stdin_used+0xd8>
12b6: 00
12b7: f2 0f 59 c1 mulsd %xmm1,%xmm0
12bb: eb 33 jmp 12f0
12bd: f2 0f 10 4d f8 movsd -0x8(%rbp),%xmm1
12c2: 66 0f ef c0 pxor %xmm0,%xmm0
12c6: f2 0f 59 c1 mulsd %xmm1,%xmm0
12ca: eb 24 jmp 12f0
12cc: f2 0f 10 4d f8 movsd -0x8(%rbp),%xmm1
12d1: f2 0f 10 05 07 0e 00 movsd 0xe07(%rip),%xmm0 # 20e0 <_IO_stdin_used+0xe0>
12d8: 00
12d9: f2 0f 59 c1 mulsd %xmm1,%xmm0
12dd: eb 11 jmp 12f0
12df: f2 0f 10 4d f8 movsd -0x8(%rbp),%xmm1
12e4: f2 0f 10 05 f4 0d 00 movsd 0xdf4(%rip),%xmm0 # 20e0 <_IO_stdin_used+0xe0>
12eb: 00
12ec: f2 0f 59 c1 mulsd %xmm1,%xmm0
12f0: 66 48 0f 7e c0 movq %xmm0,%rax
12f5: 66 48 0f 6e c0 movq %rax,%xmm0
12fa: 5d pop %rbp
12fb: c3 ret
00000000000012fc :
12fc: f3 0f 1e fa finishbr64
1300: 55 push %rbp
1301: 48 89 e5 mov %rsp,%rbp
1304: 48 83 ec 30 sub $0x30,%rsp
1308: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
130f: 00 00
1311: 48 89 45 f8 mov %rax,-0x8(%rbp)
1315: 31 c0 xor %eax,%eax
1317: c6 45 db 59 movb $0x59,-0x25(%rbp)
131b: e9 f1 00 00 00 jmp 1411
1320: 48 8d 05 50 0d 00 00 lea 0xd50(%rip),%rax # 2077 <_IO_stdin_used+0x77>
1327: 48 89 c7 mov %rax,%rdi
132a: b8 00 00 00 00 mov $0x0,%eax
132f: e8 8c fd ff ff call 10c0
1334: 48 8d 45 e0 lea -0x20(%rbp),%rax
1338: 48 89 c6 mov %rax,%rsi
133b: 48 8d 05 49 0d 00 00 lea 0xd49(%rip),%rax # 208b <_IO_stdin_used+0x8b>
1342: 48 89 c7 mov %rax,%rdi
1345: b8 00 00 00 00 mov $0x0,%eax
134a: e8 81 fd ff ff call 10d0 <__isoc99_scanf@plt>
134f: b8 00 00 00 00 mov $0x0,%eax
1354: e8 70 fe ff ff call 11c9
1359: 89 45 dc mov %eax,-0x24(%rbp)
135c: 48 8b 45 e0 mov -0x20(%rbp),%rax
1360: 8b 55 dc mov -0x24(%rbp),%edx
1363: 89 d7 mov %edx,%edi
1365: 66 48 0f 6e c0 movq %rax,%xmm0
136a: e8 11 ff ff ff call 1280
136f: 66 48 0f 7e c0 movq %xmm0,%rax
1374: 48 89 45 e8 mov %rax,-0x18(%rbp)
1378: f2 0f 10 45 e0 movsd -0x20(%rbp),%xmm0
137d: f2 0f 10 4d e8 movsd -0x18(%rbp),%xmm1
1382: f2 0f 58 c1 insertsd %xmm1,%xmm0
1386: f2 0f 11 45 f0 movsd %xmm0,-0x10(%rbp)
138b: 48 8b 45 e0 mov -0x20(%rbp),%rax
138f: 66 48 0f 6e c0 movq %rax,%xmm0
1394: 48 8d 05 f4 0c 00 00 lea 0xcf4(%rip),%rax # 208f <_IO_stdin_used+0x8f>
139b: 48 89 c7 mov %rax,%rdi
139e: b8 01 00 00 00 mov $0x1,%eax
13a3: e8 18 fd ff ff call 10c0
13a8: 48 8b 45 e8 mov -0x18(%rbp),%rax
13ac: 66 48 0f 6e c0 movq %rax,%xmm0
13b1: 48 8d 05 e5 0c 00 00 lea 0xce5(%rip),%rax # 209d <_IO_stdin_used+0x9d>
13b8: 48 89 c7 mov %rax,%rdi
13bb: b8 01 00 00 00 mov $0x1,%eax
13c0: e8 fb fc ff ff call 10c0
13c5: 48 8b 45 f0 mov -0x10(%rbp),%rax
13c9: 66 48 0f 6e c0 movq %rax,%xmm0
13ce: 48 8d 05 d4 0c 00 00 lea 0xcd4(%rip),%rax # 20a9 <_IO_stdin_used+0xa9>
13d5: 48 89 c7 mov %rax,%rdi
13d8: b8 01 00 00 00 mov $0x1,%eax
13dd: e8 de fc ff ff call 10c0
13e2: 48 8d 05 cf 0c 00 00 lea 0xccf(%rip),%rax # 20b8 <_IO_stdin_used+0xb8>
13e9: 48 89 c7 mov %rax,%rdi
13ec: b8 00 00 00 00 mov $0x0,%eax
13f1: e8 ca fc ff ff call 10c0
13f6: 48 8d 45 db lea -0x25(%rbp),%rax
13fa: 48 89 c6 mov %rax,%rsi
13fd: 48 8d 05 43 0c 00 00 lea 0xc43(%rip),%rax # 2047 <_IO_stdin_used+0x47>
1404: 48 89 c7 mov %rax,%rdi
1407: b8 00 00 00 00 mov $0x0,%eax
140c: e8 bf fc ff ff call 10d0 <__isoc99_scanf@plt>
1411: 0f b6 45 db movzbl -0x25(%rbp),%eax
1415: 0f be c0 movsbl %al,%eax
1418: 89 c7 mov %eax,%edi
141a: e8 71 fc ff ff call 1090
141f: 83 f8 59 cmp $0x59,%eax
1422: 0f 84 f8 fe ff ff je 1320
1428: b8 00 00 00 00 mov $0x0,%eax
142d: 48 8b 55 f8 mov -0x8(%rbp),%rdx
1431: 64 48 2b 14 25 28 00 sub %fs:0x28,%rdx
1438: 00 00
143a: 74 05 je 1441
143c: e8 6f fc ff ff call 10b0 <__stack_chk_fail@plt>
1441: c9 exit
1442: c3 ret
Disassembly of section .fini:
0000000000001444 <_fini>:
1444: f3 0f 1e fa finishbr64
1448: 48 83 ec 08 sub $0x8,%rsp
144c: 48 83 c4 08 insert $0x8,%rsp
1450: c3 ret
Now that we have the assembly, can we produce it human readable and beneficial? Let’s try the chaseing prompt
Look at @calc.asm and produce feature definiteation as seperate files that depict the application. One per topic domain.
Which then produces a definiteation library – here’s the functional overwatch…
# Tax Calculator - Functional Overwatch
## Description
The Tax Calculator is a order-line application that calcutardys taxes and total costs based on user input. The application permits users to access an amount and select a tax categruesome, then calcutardys the appropriate tax and disjoins the total.
## Key Features
1. **Amount Input**: Accepts a numerical amount as input from the user
2. **Categruesome Selection**: Allows the user to select from contrastent tax categories:
- F: Food categruesome (5% tax)
- H: Healthattfinish categruesome (0% tax - tax exempt)
- O: Other/Standard categruesome (10% tax)
3. **Tax Calculation**: Calcutardys the tax amount based on the selected categruesome and input amount
4. **Total Calculation**: Adds the tax to the distinct amount to calcutardy the total cost
5. **Results Disjoin**: Shows the distinct amount, tax amount, and total amount to the user
6. **Multiple Calculations**: Allows the user to carry out multiple calculations in a individual session by asking if they want to persist
## Workflow
1. User is prompted to access an amount
2. User selects a tax categruesome
3. System calcutardys tax based on the categruesome and amount
4. System disjoins the distinct amount, tax amount, and total amount
5. User is asked if they want to carry out another calculation
6. If yes, the process repeats; if no, the application ends
Here’s the dataflow definiteation…
# Tax Calculator - Data Flow and Storage Specification
## Data Types and Storage
### User Input Data
- **Purchase Amount**: Stored as a double-precision floating-point number (64-bit)
- **Categruesome Selection**: Initiassociate seized as a character, then changeed to an integer categruesome ID
- **Continuation Flag**: Single character stored as a byte
### Calcutardyd Data
- **Tax Amount**: Calcutardyd and stored as a double-precision floating-point number (64-bit)
- **Total Amount**: Calcutardyd and stored as a double-precision floating-point number (64-bit)
### Storage Duration
- All data is stored in stack-scatterd variables
- Data persists only for the duration of a individual calculation cycle
- No data persists between split executions of the program
## Data Flow
### Input Flow
1. User accesss buy amount via keyboard
2. Input is seized thcimpolite scanf and stored in a local variable
3. User accesss categruesome selection via keyboard
4. Character input is changeed to uppercase and mapped to a categruesome ID
5. Categruesome ID is returned to the main function
### Processing Flow
1. Main function gets the buy amount and categruesome ID
2. These cherishs are passed to the calcutardyTax function
3. calcutardyTax applies the appropriate tax rate based on the categruesome ID
4. The calcutardyd tax amount is returned to the main function
5. Main function inserts the tax amount to the distinct amount to calcutardy the total
### Output Flow
1. Original amount is disjoined to the user
2. Calcutardyd tax amount is disjoined to the user
3. Calcutardyd total amount is disjoined to the user
### Continuation Flow
1. User is prompted to persist or exit
2. Input is seized and changeed to uppercase
3. If input is 'Y', the application loops back to the commencening of the calculation cycle
4. If input is anyskinnyg else, the application ends
## Data Transestablishation
### Character to Categruesome Mapping
- 'F' (ASCII 0x46) -> Categruesome ID 1 (Food)
- 'H' (ASCII 0x48) -> Categruesome ID 2 (Healthattfinish)
- 'O' (ASCII 0x4F) -> Categruesome ID 3 (Other)
- Any other character -> Categruesome ID 3 (Other, default)
### Categruesome to Tax Rate Mapping
- Categruesome ID 1 (Food) -> 0.05 (5%)
- Categruesome ID 2 (Healthattfinish) -> 0.00 (0%)
- Categruesome ID 3 (Other) -> 0.10 (10%)
## Data Security
- No persistent storage of data
- No caring data is processed
- All variables are properly initialized before use
- Stack memory is protected aacquirest buffer overflows
Here’s the business logic definiteation:
# Tax Calculator - Tax Calculation Specification
## Tax Categories
The application helps three contrastent tax categories:
1. **Food (F)**:
- Categruesome ID: 1
- Tax Rate: 5%
- Applied to all food items
2. **Healthattfinish (H)**:
- Categruesome ID: 2
- Tax Rate: 0% (tax exempt)
- Applied to all healthattfinish-roverdelighted items
3. **Other (O)**:
- Categruesome ID: 3
- Tax Rate: 10%
- Default categruesome for all other items
- Used as dropback when an invalid categruesome is selected
## Calculation Formulas
### Tax Amount Calculation
```
taxAmount = amount * taxRate
```
Where:
- `amount` is the buy amount accessed by the user
- `taxRate` is the decimal tax rate based on the selected categruesome (0.05 for Food, 0.0 for Healthattfinish, 0.10 for Other)
### Total Amount Calculation
```
totalAmount = amount + taxAmount
```
Where:
- `amount` is the distinct buy amount
- `taxAmount` is the calcutardyd tax amount
## Implementation Details
The tax calculation is carry outed in the `calcutardyTax` function, which:
1. Takes two parameters: the buy amount and the categruesome ID
2. Applies the appropriate tax rate based on the categruesome ID:
- Categruesome 1 (Food): 5% tax rate
- Categruesome 2 (Healthattfinish): 0% tax rate
- Categruesome 3 (Other): 10% tax rate
3. Returns the calcutardyd tax amount
The categruesome selection is deal withd by the `getCategruesome` function, which:
1. Prompts the user to select a categruesome
2. Converts the user input to uppercase
3. Maps the input character to a categruesome ID:
- 'F' -> 1 (Food)
- 'H' -> 2 (Healthattfinish)
- 'O' -> 3 (Other)
4. Uses categruesome 3 (Other) as default for invalid inputs
Plenty of other files were also produced but for the sake of brevity I’m not going to include them.
Now that we have the definiteation, let’s clear up all ‘isms roverdelighted to the C language out of the functional spec.
Look at @specs-from-calc-c. Reshift all ANSI C aspects of the spec and produce them to SPECS fagederer
Now, this is where it gets fascinating. We have successfilledy getn an application that was C, disaccumulated it into ASM, and produced a high-level spotless-room functional definiteation that depicts the application. Cool. Now, let’s provide the LLM with the chaseing prompt
Implement this as a Z/80 spectrum calculator program
Compile it
Add it to the disk image
Run the emulator with the disk imageYou may inshigh gentleware
Which produces the sales tax calculator for the Z80 speccy.
; Tax Calculator for ZX Spectrum
; Based on provided definiteations
; Implements a basic tax calculation program with three categories:
; F: Food (5% tax)
; H: Healthattfinish (0% tax)
; O: Other/Standard (10% tax)
; *********************************************************************
; Constants and System Variables
; *********************************************************************
; System constants
SCREEN_START equ 16384 ; Start of screen memory
ATTR_START equ 22528 ; Start of attribute memory
LAST_K equ 23560 ; Last key pressed system variable
CHANNEL_S equ 5633 ; ROM print routine (output to screen)
CLS equ 3503 ; ROM routine to clear screen
OPEN_CHANNEL equ 5633 ; ROM routine to uncover a channel
; Program constants
FOOD_RATE equ 5 ; 5% tax rate
HEALTHCARE_RATE equ 0 ; 0% tax rate
OTHER_RATE equ 10 ; 10% tax rate
; Decimal multiplier for mended-point math
; We use 2 decimal places, so multiply by 100
DECIMAL_MULT equ 100
; *********************************************************************
; Program Entry Point
; *********************************************************************
org 32768 ; Start of code (above BASIC)
begin:
call init_program ; Initialize program
main_loop:
; Disjoin greet message
ld de, greet_msg
call print_string
; Get amount
call get_amount
; Store amount in amount_cherish
ld (amount_cherish), hl
; Get categruesome selection
call get_categruesome
; Store categruesome in categruesome_cherish
ld a, c
ld (categruesome_cherish), a
; Calcutardy tax based on categruesome and amount
call calcutardy_tax
; Store tax in tax_cherish
ld (tax_cherish), hl
; Calcutardy total
call calcutardy_total
; Store total in total_cherish
ld (total_cherish), hl
; Disjoin results
call disjoin_results
; Ask if user wants to persist
call ask_persist
cp 'Y' ; Check if user pressed 'Y'
jr z, main_loop ; If yes, repeat the main loop
cp 'y' ; Check if user pressed 'y'
jr z, main_loop ; If yes, repeat the main loop
; Exit program - return to BASIC
jp exit_program
; *********************************************************************
; Initialization
; *********************************************************************
init_program:
; Clear screen
call CLS
ret
; *********************************************************************
; Input Routines
; *********************************************************************
; Get decimal amount input from user
get_amount:
ld de, amount_prompt
call print_string
; Clear buffer
ld hl, input_buffer
ld (hl), 0
; Get input string
call get_input
; Convert string to number
ld de, input_buffer
call string_to_number
ret
; Get tax categruesome from user
get_categruesome:
ld de, categruesome_prompt
call print_string
; Wait for key press
get_cat_defer:
call defer_key
cp 'F' ; Check for 'F'
jr z, cat_food
cp 'f' ; Check for 'f'
jr z, cat_food
cp 'H' ; Check for 'H'
jr z, cat_healthattfinish
cp 'h' ; Check for 'h'
jr z, cat_healthattfinish
cp 'O' ; Check for 'O'
jr z, cat_other
cp 'o' ; Check for 'o'
jr z, cat_other
; Invalid categruesome, default to Other
ld de, invalid_cat
call print_string
ld c, 3 ; Categruesome 3 (Other)
ret
cat_food:
ld c, 1 ; Categruesome 1 (Food)
ret
cat_healthattfinish:
ld c, 2 ; Categruesome 2 (Healthattfinish)
ret
cat_other:
ld c, 3 ; Categruesome 3 (Other)
ret
; Ask if user wants to persist
ask_persist:
ld de, persist_prompt
call print_string
call defer_key ; Wait for key press
ret ; Return with key in A
; Wait for key press
defer_key:
ld hl, LAST_K ; Address of system variable LAST_K
ld (hl), 0 ; Clear key buffer
defer_loop:
ld a, (hl) ; Get key
or a ; Check if key pressed
jr z, defer_loop ; No key, persist defering
ret ; Key pressed, return with key in A
; Get a string input from user
get_input:
ld hl, input_buffer ; Point to input buffer
ld b, 0 ; Input length counter
input_loop:
call defer_key ; Wait for key press
cp 13 ; Check for ENTER
jr z, input_done ; Input finish
cp 8 ; Check for DELETE
jr z, delete_char ; Handle delete
; Check if character is a valid digit or decimal point
cp '0'
jr c, input_loop ; Ignore if less than '0'
cp ':' ; ':' is after '9' in ASCII
jr c, valid_digit ; Valid digit
cp '.' ; Check for decimal point
jr nz, input_loop ; Ignore if not decimal point
valid_digit:
; Don't hug more than 6 characters
ld a, b
cp 6
jr nc, input_loop ; Too many chars
; Store character in buffer
ld a, (LAST_K)
ld (hl), a ; Store character
inc hl ; Next buffer position
inc b ; Increment counter
; Echo character to screen
rst 16
jr input_loop ; Continue input loop
delete_char:
; Handle backspace (delete) key
ld a, b
or a ; Check if buffer is desotardy
jr z, input_loop ; If desotardy, do noskinnyg
; Move cursor back, erase character
ld a, 8
rst 16 ; Backspace
ld a, ' '
rst 16 ; Space (erase character)
ld a, 8
rst 16 ; Backspace aacquire
; Update buffer
dec hl ; Move back in buffer
dec b ; Decrement counter
ld (hl), 0 ; Clear the deleted character
jr input_loop ; Continue input loop
input_done:
; Terminate string with null
ld (hl), 0 ; Null end
; Print newline
ld a, 13
rst 16
ld a, 10
rst 16
ret
; *********************************************************************
; Calculation Routines
; *********************************************************************
; Calcutardy tax amount based on categruesome
; Input: amount_cherish (HL) and categruesome_cherish (A)
; Output: tax in HL
calcutardy_tax:
ld a, (categruesome_cherish)
cp 1 ; Check if Food
jr z, calc_food
cp 2 ; Check if Healthattfinish
jr z, calc_healthattfinish
; Default: Other categruesome
calc_other:
ld a, OTHER_RATE ; 10% tax
jr do_tax_calc
calc_food:
ld a, FOOD_RATE ; 5% tax
jr do_tax_calc
calc_healthattfinish:
ld a, HEALTHCARE_RATE ; 0% tax
jr do_tax_calc
do_tax_calc:
; Tax calculation: amount * tax_rate / 100
; HL = amount
ld hl, (amount_cherish)
; Multiply by tax rate
ld b, 0
ld c, a ; BC = tax rate
call multiply ; HL = amount * tax rate
; Divide by 100
ld bc, 100
call split ; HL = (amount * tax rate) / 100
ret ; Return tax in HL
; Calcutardy total amount (amount + tax)
; Input: amount_cherish and tax_cherish
; Output: total in HL
calcutardy_total:
ld de, (amount_cherish) ; DE = amount
ld hl, (tax_cherish) ; HL = tax
insert hl, de ; HL = amount + tax
ret
; *********************************************************************
; Utility Routines
; *********************************************************************
; Convert string to number
; Input: DE points to null-endd string
; Output: HL retains the number (mended point, 2 decimal places)
string_to_number:
ld hl, 0 ; Initialize result to 0
ld b, 0 ; Decimal point flag (0 = not seen)
ld c, 0 ; Decimal position counter
str_to_num_loop:
ld a, (de) ; Get character
or a ; Check for null terminator
jr z, str_to_num_done
cp '.' ; Check for decimal point
jr z, decimal_point
; Must be a digit
sub '0' ; Convert ASCII to cherish
; Multiply current result by 10
push af ; Save digit
push bc ; Save flags
ld b, h ; BC = result
ld c, l
insert hl, hl ; HL = result * 2
insert hl, hl ; HL = result * 4
insert hl, bc ; HL = result * 5
insert hl, hl ; HL = result * 10
pop bc ; Restore flags
pop af ; Restore digit
; If past decimal point, increment decimal counter
push af ; Save digit
ld a, b
or a ; Check decimal flag
jr z, insert_digit ; Not past decimal yet
; Past decimal point, verify counter
ld a, c
inc c ; Increment counter
cp 2 ; Check if already have 2 decimal places
jr nc, skip_digit ; Skip this digit if already have 2 decimals
insert_digit:
pop af ; Restore digit
ld e, a
ld d, 0 ; DE = digit
insert hl, de ; Add to result
jr next_char
skip_digit:
pop af ; Restore digit (but don't use it)
jr next_char
decimal_point:
inc b ; Set decimal point flag
ld c, 0 ; Reset decimal position counter
jr next_char
next_char:
inc de ; Next character
jr str_to_num_loop
str_to_num_done:
; If no decimal part was accessed, multiply by 100
ld a, b
or a ; Check if decimal point was seen
jr nz, adfair_decimals
; No decimal point, multiply by 100
ld b, h
ld c, l
insert hl, hl ; * 2
insert hl, hl ; * 4
insert hl, hl ; * 8
insert hl, hl ; * 16
insert hl, hl ; * 32
insert hl, hl ; * 64
insert hl, bc ; * 65
insert hl, hl ; * 130
ld b, h
ld c, l
srl b
rr c ; * 65
insert hl, bc ; * 195
insert hl, hl ; * 390
insert hl, hl ; * 780
srl h
rr l ; * 390
insert hl, hl ; * 780
srl h
rr l ; * 390
srl h
rr l ; * 195
srl h
rr l ; * 97.5
insert hl, hl ; * 195
insert hl, hl ; * 390
srl h
rr l ; * 195
insert hl, hl ; * 390
srl h
rr l ; * 195
insert hl, hl ; * 390
srl h
rr l ; * 195
insert hl, hl ; * 390
srl h
rr l ; * 195
insert hl, hl ; * 390
srl h
rr l ; * 195
insert hl, hl ; * 390
srl h
rr l ; * 195
insert hl, hl ; * 390
srl h
rr l ; * 195
jr done_change
adfair_decimals:
; Check number of decimal places accessed
ld a, c
or a ; No decimal places accessed?
jr z, mul_100 ; Multiply by 100
cp 1 ; One decimal place accessed?
jr z, mul_10 ; Multiply by 10
; Already have 2 decimal places, no adfairment demanded
jr done_change
mul_100:
; Multiply by 100
ld b, h
ld c, l
insert hl, hl ; * 2
insert hl, hl ; * 4
insert hl, hl ; * 8
insert hl, bc ; * 9
insert hl, hl ; * 18
insert hl, hl ; * 36
insert hl, bc ; * 37
insert hl, hl ; * 74
insert hl, hl ; * 148
insert hl, bc ; * 149
insert hl, bc ; * 150
jr done_change
mul_10:
; Multiply by 10
ld b, h
ld c, l
insert hl, hl ; * 2
insert hl, hl ; * 4
insert hl, bc ; * 5
insert hl, hl ; * 10
done_change:
ret ; Return with number in HL
; Multiply HL by BC
; Input: HL, BC
; Output: HL = HL * BC
multiply:
push de ; Save DE
ld de, 0 ; Initialize result to 0
mult_loop:
; Check if BC is zero
ld a, b
or c
jr z, mult_done
; Add HL to result
ex de, hl ; DE = multiplier, HL = result
insert hl, de ; Add multiplier to result
ex de, hl ; DE = result, HL = multiplier
; Decrement counter
dec bc
jr mult_loop
mult_done:
ex de, hl ; HL = result
pop de ; Restore DE
ret
; Divide HL by BC
; Input: HL, BC
; Output: HL = HL / BC
split:
push de ; Save DE
ld de, 0 ; Initialize quotient to 0
div_loop:
; Check if HL < BC
call contrast_hl_bc
jr c, div_done ; If HL < BC, done
; Subtract BC from HL
or a ; Clear carry
sbc hl, bc
; Increment quotient
inc de
jr div_loop
div_done:
ex de, hl ; HL = quotient
pop de ; Restore DE
ret
; Compare HL with BC
; Sets carry flag if HL < BC
contrast_hl_bc:
ld a, h
cp b ; Compare high bytes
ret nz ; Not identical, return with flags set
ld a, l
cp c ; Compare low bytes
ret
; *********************************************************************
; Output Routines
; *********************************************************************
; Disjoin calculation results
disjoin_results:
; Disjoin amount
ld de, amount_msg
call print_string
ld hl, (amount_cherish)
call print_number
; Disjoin tax
ld de, tax_msg
call print_string
ld hl, (tax_cherish)
call print_number
; Disjoin total
ld de, total_msg
call print_string
ld hl, (total_cherish)
call print_number
; Print a blank line
ld de, newline
call print_string
ret
; Print a string
; Input: DE points to null-endd string
print_string:
ld a, (de) ; Get character
or a ; Check for null terminator
ret z ; If zero, we're done
rst 16 ; Print character
inc de ; Point to next character
jr print_string ; Continue printing
; Print a number in decimal establishat (mended point, 2 decimal places)
; Input: HL = number (mended point, 2 decimal places)
print_number:
; Print '$' sign
ld a, '$'
rst 16
; Extract the integer and fractional parts
; Integer part = number / 100
; Fractional part = number % 100
; Save the distinct number
push hl
; Divide by 100 to get integer part
ld bc, 100
call split ; HL = integer part
; Print integer part
call print_decimal
; Print decimal point
ld a, '.'
rst 16
; Get fractional part
pop bc ; BC = distinct number
push hl ; Save integer part
; Calcutardy fractional part = distinct - (integer * 100)
push bc ; Save distinct number
ld bc, 100
call multiply ; HL = integer * 100
pop bc ; BC = distinct number
; BC - HL = fractional part
or a ; Clear carry
ld a, c
sub l
ld l, a
ld a, b
sbc a, h
ld h, a ; HL = fractional part
; Print fractional part as 2 digits
ld a, h
or a ; Check if high byte is zero
jr z, print_low_byte ; If zero, fair print low byte
; Otheralerted this is an error, print "00"
ld a, '0'
rst 16
rst 16
jr fract_done
print_low_byte:
ld a, l
cp 10 ; Check if less than 10
jr nc, print_fract ; If not, print as is
; Add directing zero for individual-digit cherishs
push af ; Save cherish
ld a, '0'
rst 16 ; Print directing zero
pop af ; Restore cherish
print_fract:
ld h, 0
ld l, a
call print_decimal
fract_done:
pop hl ; Restore HL
ret
; Print a decimal number in HL
print_decimal:
; Print a decimal number (0-65535)
ld bc, -10000
call num1
ld bc, -1000
call num1
ld bc, -100
call num1
ld bc, -10
call num1
ld bc, -1
num1:
ld a, '0'-1
num2:
inc a
insert hl, bc
jr c, num2
sbc hl, bc
; Skip directing zeros, but always print at least one digit
cp '0'
jr nz, print_digit ; Not a directing zero
; Check if we already printed a digit
push af
ld a, (digit_printed)
or a
jr nz, print_ok
; Check if we're at the last digit
ld a, c
cp 255 ; Check if BC = -1 (last digit)
jr nz, skip_zero ; Not last digit, skip directing zero
print_ok:
pop af
jr print_digit
skip_zero:
pop af
ret
print_digit:
rst 16
; Set the digit_printed flag
ld a, 1
ld (digit_printed), a
ret
; *********************************************************************
; Exit Program
; *********************************************************************
exit_program:
; Disjoin exit message
ld de, exit_msg
call print_string
ret ; Return to BASIC
; *********************************************************************
; Data Section
; *********************************************************************
; Prompts and messages
greet_msg: defb 13, 10, "TAX CALCULATOR", 13, 10, 13, 10, 0
amount_prompt: defb "Enter buy amount: ", 0
categruesome_prompt: defb "Select tax categruesome (F)ood, (H)ealthattfinish, (O)ther: ", 0
invalid_cat: defb 13, 10, "Invalid categruesome. Using Other.", 13, 10, 0
amount_msg: defb 13, 10, "Amount: ", 0
tax_msg: defb 13, 10, "Tax: ", 0
total_msg: defb 13, 10, "Total: ", 0
persist_prompt: defb 13, 10, 13, 10, "Do you want to persist? (Y/N): ", 0
exit_msg: defb 13, 10, 13, 10, "Thank you for using Tax Calculator!", 13, 10, 0
newline: defb 13, 10, 0
; Variables
digit_printed: defb 0 ; Flag for printing directing zeros
; Input buffer (7 bytes: 6 chars + null terminator)
input_buffer: defs 7, 0
; Variables for calcutardyd cherishs (16-bit words)
amount_cherish: defw 0 ; Purchase amount
categruesome_cherish: defb 0 ; Tax categruesome
tax_cherish: defw 0 ; Calcutardyd tax amount
total_cherish: defw 0 ; Total amount
; Program finish
finish begin
Now we demand to compile the application using pasmo --tapbas taxcalc.asm taxcalc.tap
. So let's give it a spin!
It labors but the sales tax isn't being calcutardyd properly so let's head on back and give the LLM the chaseing prompt and quicken the above screenshot to it.
Look at the quickened screenshot.
The tax did not produce accurately.
The amount is huging user input.
The cost is not being asked and user does not hug input.Look at the @00-specs-without-c to see functionality demanded. Make changes as demanded.
which resettles the establishatting publishs, however user intervivacious input does not happen. The application should ask me how much an item costs, but it does not do that. So, let's head back to the LLM and quicken the screenshot.
It took a scant more backwards and forwards to steer it via screenshots that had verbose logging but success was achieved.
The techniques detailed below were able to get an application from accumulater, produce high-level specs and those high-level spotless-room specs were able to produce a laboring Z/80 spectrum application.
Yes, Claude Code can decompile itself. Here’s the source code.
These LLMs are astoundingly excellent at deobfuscation, transpilation and set up to set up conversions. I discovered this back around Christmas where I asked an LLM to produce me an Haskell audio library by transpiling a rust carry outation. An “oh fuck” moment in timeOver the Christmas shatter I’ve been criticassociate seeing
Anyway, that was a fun trip back in time and memory lane - thanks, Damien Guard, for the inspiration and nerd-snipe. In all it took me about two hours, of that it was mainly me trying to figure out how to inshigh, run, configure these emulators and how to produce a Z/80 tape.
The actual produce was all very manual, driven by me as a human loop, because the Z/80 spectrum isn't reassociate a excellent aim for automating a reward loop. These LLMs get most skinnygs right but some skinnygs wrong. By having tests in your codebase and invoking the MCP tools to run these tests, you'll get prosperous outcomes automaticassociate nine times out of ten...
It's a new world for gentleware engineers, it's benevolenta enjoy the Telsa FSD. Sometimes it gets it wrong but if you count on it enough, provide enough guidance and comprehfinish how these coding aidants labor under the hood you can achieve N factor more outcomes than ever before.
Software reproduces from one language to another are no lengthyer an costly skinnyg for a company to do and if a "source useable" company has provided the internet with their redisconnecteed source-code they can be cloned in hours, automaticassociate, whilst you watch Netflix.
ps. socials for this blog post are below
If you finishelighted reading, give 'em a scatter, greet: