Source is an extract from calc.c in rpilot from github:
(which appears to be a fork of rpilot on sourceforge:)
I chose the calc() function in calc.c as an exercise to test how difficult the entire project would be. Just this much took me more than eight hours. (Admittedly, it did not have my full attention, and, at sixty, I'm probably not as quick at this as I was at twenty-one.)
I initially started working on a compile to 6800 code, because that is a more interesting (meaning, harder) target, but I spent an awful lot of time in working out glue logic, and the result was tending to look like a list of subroutine calls (which is generally good indication to write in Forth instead of assembler).
The purpose in this sort of exercise is to prepare for writing a compiler.
Yeah, it's a little hard to read. The C source is in the comment lines.
*** An exercise in semi-blind hand-compiling C to 6809, *** from the rpilot source code. *** Joel Rees, Amagasaki, Japan, August 2021 */* * calc.c - handle simple mathematical expressions * rob - started july.25.2000 * * updates: * - got around to finishing it - aug.11.2000 * - RPilot special code - aug.11.2000 */ *-------------------- * An include file somewhere would have * Native integer width for C programs: _INTWIDTH EQU 2 _ADRWIDTH EQU 2 *-------------------- * #include "rpilot.h" * #include "rstring.h" * #include "calc.h" INCLUDE calc.h.6809.asm * #include "var.h" * #include <string.h> * #include <stdio.h> * #include <ctype.h> * #include <stdlib.h> * int next_num( char *str, int *pos, int *status ); * char next_tok( char *str, int *pos ); * int find_match( char *str, int pos, char what, char match ); * int read_num( char *str, int *pos ); * int read_var( char *str, int *pos ); * int calc( char *expr, int *status ) expr SET 0 status SET expr+_ADRWIDTH _PSZ SET status+_ADRWIDTH calc * { * int pos = 0; pos SET 0 * int num = 0, result = 0; num SET pos+_INTWIDTH result SET num+_INTWIDTH * char op = 0; op SET result+_INTWIDTH _LOCSZ SET op+1 LDD #0 PSHU D PSHU D PSHU D PSHU B * total_trim( expr ); LDX expr+_LOCSZ,U PSHU X LBSR total_trim LEAU _ADRWIDTH,U ; returned pointer unnecessary, balance stack * result = next_num( expr, &pos, status ); LDY status+_LOCSZ,U LEAX pos,U LDD expr+_LOCSZ,U PSHU D,X,Y LBSR next_num PULU D STD result,U * while( pos < strlen(expr) ) { calc_lp00 LDX expr+_LOCSZ,U PSHU X LBSR strlen LDD pos+_INTWIDTH,U CMPD ,U++ LBGE calc_lx00 * op = next_tok( expr, &pos ); LEAX pos,U LDD expr+_LOCSZ,U PSHU X,Y LBSR next_tok PULU B STB op,U * num = next_num( expr, &pos, status ); LDY status+_LOCSZ,U LEAX pos,U LDD expr+_LOCSZ,U PSHU D,X,Y LBSR next_num PULU D STD num,U * Directly indexing a jump table from op takes too much memory * from 6809 address range. * Not enough cases to warrant searching in a loop. * switch( op ) { LDB op,U * Use value-optimized binary test tree: * (We don't really need it to be this fast.) CMPB #'+' BEQ calc_if00_c01 BLO calc_if00_t00 CMPB #'^' BEQ calc_if00_c08 BLO calc_if00_t01 CMPB #'|' BEQ calc_if00_c07 BRA calc_if00_else calc_if00_t01 CMPB #'-' BEQ calc_if00_c02 CMPB #'/' BEQ calc_if00_c03 BRA calc_if00_else calc_if00_t00 CMPB #'*' BEQ calc_if00_c04 CMPB #'&' BEQ calc_if00_c06 CMPB #'%' BEQ calc_if00_c05 * case 0 : // invalid operand * Code duplicate of default calc_if00_else calc_if00_c00 * *status = CALC_NO_OP; LDD #CALC_NO_OP STD [status+_LOCSZ,U] * return 0; LDD #0 PSHU D RTS * break; * case '+' : calc_if00_c01 * result += num; LDD result,U ADDD num,U * break; BRA calc_if00_end * case '-' : calc_if00_c02 * result -= num; LDD result,U SUBD num,U * break; BRA calc_if00_end * case '/' : calc_if00_c03 * result /= num; LDX result,U LDD num,U PSHU D,X LBSR IDIV PULU D * break; BRA calc_if00_end * case '*' : calc_if00_c04 * result *= num; LDX result,U LDD num,U PSHU D,X LBSR IMUL PULU D * break; BRA calc_if00_end * case '%' : calc_if00_c05 * result %= num; LDX result,U LDD num,U PSHU D,X LBSR IMOD PULU D * break; BRA calc_if00_end * case '&' : calc_if00_c06 * result &= num; LDD result,U ANDB num+1,U ANDA num,U * break; BRA calc_if00_end * case '|' : calc_if00_c07 * result |= num; LDD result,U ORB num+1,U ORA num,U * break; BRA calc_if00_end * case '^' : calc_if00_c08 * result ^= num; LDD result,U EORB num+1,U EORA num,U * break; BRA calc_if00_end * Code duplicate of case 0 * default: * calc_if00_else * *status = CALC_BAD_OP; * return 0; * break; * } calc_if00_end STD result,U LBRA calc_lp00 * } calc_lx00 * *status = CALC_SUCCESS; LDD #CALC_NO_OP STD [status+_LOCSZ,U] * return result; LDD result,U PSHU D RTS * } * Leave it possible to assemble, if not run: IMUL IDIV IMOD strlen next_num find_match read_num next_tok read_var EQU * total_trim END
Here's the assembler output, for reference:
( calc.c.6809.asm):00001 *** An exercise in semi-blind hand-compiling C to 6809, ( calc.c.6809.asm):00002 *** from the rpilot source code. ( calc.c.6809.asm):00003 *** Joel Rees, Amagasaki, Japan, August 2021 ( calc.c.6809.asm):00004 ( calc.c.6809.asm):00005 */* ( calc.c.6809.asm):00006 * calc.c - handle simple mathematical expressions ( calc.c.6809.asm):00007 * rob - started july.25.2000 ( calc.c.6809.asm):00008 * ( calc.c.6809.asm):00009 * updates: ( calc.c.6809.asm):00010 * - got around to finishing it - aug.11.2000 ( calc.c.6809.asm):00011 * - RPilot special code - aug.11.2000 ( calc.c.6809.asm):00012 */ ( calc.c.6809.asm):00013 ( calc.c.6809.asm):00014 *-------------------- ( calc.c.6809.asm):00015 ( calc.c.6809.asm):00016 * An include file somewhere would have ( calc.c.6809.asm):00017 ( calc.c.6809.asm):00018 * Native integer width for C programs: 0002 ( calc.c.6809.asm):00019 _INTWIDTH EQU 2 0002 ( calc.c.6809.asm):00020 _ADRWIDTH EQU 2 ( calc.c.6809.asm):00021 ( calc.c.6809.asm):00022 *-------------------- ( calc.c.6809.asm):00023 ( calc.c.6809.asm):00024 * #include "rpilot.h" ( calc.c.6809.asm):00025 * #include "rstring.h" ( calc.c.6809.asm):00026 * #include "calc.h" ( calc.c.6809.asm):00027 INCLUDE calc.h.6809.asm ( calc.h.6809.asm):00001 */* ( calc.h.6809.asm):00002 * calc.h - header file for the calc package ( calc.h.6809.asm):00003 * rob linwood (rcl211@nyu.edu) ( calc.h.6809.asm):00004 * see README for more information ( calc.h.6809.asm):00005 */ ( calc.h.6809.asm):00006 ( calc.h.6809.asm):00007 * #ifndef _calc_h_ ( calc.h.6809.asm):00008 * #define _calc_h_ ( calc.h.6809.asm):00009 ( calc.h.6809.asm):00010 * #define CALC_SUCCESS 0 /* Indicates success */ 0000 ( calc.h.6809.asm):00011 CALC_SUCCESS EQU 0 ( calc.h.6809.asm):00012 * #define CALC_NO_OP 1 /* No mathematical operator in expression */ 0001 ( calc.h.6809.asm):00013 CALC_NO_OP EQU 1 ( calc.h.6809.asm):00014 * #define CALC_BAD_OP 2 /* Unknown mathematical operator in expression */ 0002 ( calc.h.6809.asm):00015 CALC_BAD_OP EQU 2 ( calc.h.6809.asm):00016 * int calc( char *expr, int *status ); ( calc.h.6809.asm):00017 ( calc.h.6809.asm):00018 * #endif ( calc.c.6809.asm):00028 * #include "var.h" ( calc.c.6809.asm):00029 ( calc.c.6809.asm):00030 * #include <string.h> ( calc.c.6809.asm):00031 * #include <stdio.h> ( calc.c.6809.asm):00032 * #include <ctype.h> ( calc.c.6809.asm):00033 * #include <stdlib.h> ( calc.c.6809.asm):00034 ( calc.c.6809.asm):00035 * int next_num( char *str, int *pos, int *status ); ( calc.c.6809.asm):00036 * char next_tok( char *str, int *pos ); ( calc.c.6809.asm):00037 * int find_match( char *str, int pos, char what, char match ); ( calc.c.6809.asm):00038 * int read_num( char *str, int *pos ); ( calc.c.6809.asm):00039 * int read_var( char *str, int *pos ); ( calc.c.6809.asm):00040 ( calc.c.6809.asm):00041 * int calc( char *expr, int *status ) 0000 ( calc.c.6809.asm):00042 expr SET 0 0002 ( calc.c.6809.asm):00043 status SET expr+_ADRWIDTH 0004 ( calc.c.6809.asm):00044 _PSZ SET status+_ADRWIDTH 0000 ( calc.c.6809.asm):00045 calc ( calc.c.6809.asm):00046 * { ( calc.c.6809.asm):00047 * int pos = 0; 0000 ( calc.c.6809.asm):00048 pos SET 0 ( calc.c.6809.asm):00049 * int num = 0, result = 0; 0002 ( calc.c.6809.asm):00050 num SET pos+_INTWIDTH 0004 ( calc.c.6809.asm):00051 result SET num+_INTWIDTH ( calc.c.6809.asm):00052 * char op = 0; 0006 ( calc.c.6809.asm):00053 op SET result+_INTWIDTH 0007 ( calc.c.6809.asm):00054 _LOCSZ SET op+1 0000 CC0000 ( calc.c.6809.asm):00055 LDD #0 0003 3606 ( calc.c.6809.asm):00056 PSHU D 0005 3606 ( calc.c.6809.asm):00057 PSHU D 0007 3606 ( calc.c.6809.asm):00058 PSHU D 0009 3604 ( calc.c.6809.asm):00059 PSHU B ( calc.c.6809.asm):00060 ( calc.c.6809.asm):00061 * total_trim( expr ); 000B AE47 ( calc.c.6809.asm):00062 LDX expr+_LOCSZ,U 000D 3610 ( calc.c.6809.asm):00063 PSHU X 000F 1700D0 ( calc.c.6809.asm):00064 LBSR total_trim 0012 3342 ( calc.c.6809.asm):00065 LEAU _ADRWIDTH,U ; returned pointer unnecessary, balance stack ( calc.c.6809.asm):00066 ( calc.c.6809.asm):00067 * result = next_num( expr, &pos, status ); 0014 10AE49 ( calc.c.6809.asm):00068 LDY status+_LOCSZ,U 0017 30C4 ( calc.c.6809.asm):00069 LEAX pos,U 0019 EC47 ( calc.c.6809.asm):00070 LDD expr+_LOCSZ,U 001B 3636 ( calc.c.6809.asm):00071 PSHU D,X,Y 001D 1700C2 ( calc.c.6809.asm):00072 LBSR next_num 0020 3706 ( calc.c.6809.asm):00073 PULU D 0022 ED44 ( calc.c.6809.asm):00074 STD result,U ( calc.c.6809.asm):00075 ( calc.c.6809.asm):00076 * while( pos < strlen(expr) ) { 0024 ( calc.c.6809.asm):00077 calc_lp00 0024 AE47 ( calc.c.6809.asm):00078 LDX expr+_LOCSZ,U 0026 3610 ( calc.c.6809.asm):00079 PSHU X 0028 1700B7 ( calc.c.6809.asm):00080 LBSR strlen 002B EC42 ( calc.c.6809.asm):00081 LDD pos+_INTWIDTH,U 002D 10A3C1 ( calc.c.6809.asm):00082 CMPD ,U++ 0030 102C00A3 ( calc.c.6809.asm):00083 LBGE calc_lx00 ( calc.c.6809.asm):00084 ( calc.c.6809.asm):00085 * op = next_tok( expr, &pos ); 0034 30C4 ( calc.c.6809.asm):00086 LEAX pos,U 0036 EC47 ( calc.c.6809.asm):00087 LDD expr+_LOCSZ,U 0038 3630 ( calc.c.6809.asm):00088 PSHU X,Y 003A 1700A5 ( calc.c.6809.asm):00089 LBSR next_tok 003D 3704 ( calc.c.6809.asm):00090 PULU B 003F E746 ( calc.c.6809.asm):00091 STB op,U ( calc.c.6809.asm):00092 * num = next_num( expr, &pos, status ); 0041 10AE49 ( calc.c.6809.asm):00093 LDY status+_LOCSZ,U 0044 30C4 ( calc.c.6809.asm):00094 LEAX pos,U 0046 EC47 ( calc.c.6809.asm):00095 LDD expr+_LOCSZ,U 0048 3636 ( calc.c.6809.asm):00096 PSHU D,X,Y 004A 170095 ( calc.c.6809.asm):00097 LBSR next_num 004D 3706 ( calc.c.6809.asm):00098 PULU D 004F ED42 ( calc.c.6809.asm):00099 STD num,U ( calc.c.6809.asm):00100 ( calc.c.6809.asm):00101 * Directly indexing a jump table from op takes too much memory ( calc.c.6809.asm):00102 * from 6809 address range. ( calc.c.6809.asm):00103 * Not enough cases to warrant searching in a loop. ( calc.c.6809.asm):00104 * switch( op ) { 0051 E646 ( calc.c.6809.asm):00105 LDB op,U ( calc.c.6809.asm):00106 * Use value-optimized binary test tree: ( calc.c.6809.asm):00107 * (We don't really need it to be this fast.) 0053 C12B ( calc.c.6809.asm):00108 CMPB #'+' 0055 2730 ( calc.c.6809.asm):00109 BEQ calc_if00_c01 0057 2516 ( calc.c.6809.asm):00110 BLO calc_if00_t00 0059 C15E ( calc.c.6809.asm):00111 CMPB #'^' 005B 276D ( calc.c.6809.asm):00112 BEQ calc_if00_c08 005D 2506 ( calc.c.6809.asm):00113 BLO calc_if00_t01 005F C17C ( calc.c.6809.asm):00114 CMPB #'|' 0061 275F ( calc.c.6809.asm):00115 BEQ calc_if00_c07 0063 2016 ( calc.c.6809.asm):00116 BRA calc_if00_else 0065 ( calc.c.6809.asm):00117 calc_if00_t01 0065 C12D ( calc.c.6809.asm):00118 CMPB #'-' 0067 2724 ( calc.c.6809.asm):00119 BEQ calc_if00_c02 0069 C12F ( calc.c.6809.asm):00120 CMPB #'/' 006B 2726 ( calc.c.6809.asm):00121 BEQ calc_if00_c03 006D 200C ( calc.c.6809.asm):00122 BRA calc_if00_else 006F ( calc.c.6809.asm):00123 calc_if00_t00 006F C12A ( calc.c.6809.asm):00124 CMPB #'*' 0071 272D ( calc.c.6809.asm):00125 BEQ calc_if00_c04 0073 C126 ( calc.c.6809.asm):00126 CMPB #'&' 0075 2743 ( calc.c.6809.asm):00127 BEQ calc_if00_c06 0077 C125 ( calc.c.6809.asm):00128 CMPB #'%' 0079 2732 ( calc.c.6809.asm):00129 BEQ calc_if00_c05 ( calc.c.6809.asm):00130 * case 0 : // invalid operand ( calc.c.6809.asm):00131 * Code duplicate of default 007B ( calc.c.6809.asm):00132 calc_if00_else 007B ( calc.c.6809.asm):00133 calc_if00_c00 ( calc.c.6809.asm):00134 * *status = CALC_NO_OP; 007B CC0001 ( calc.c.6809.asm):00135 LDD #CALC_NO_OP 007E EDD809 ( calc.c.6809.asm):00136 STD [status+_LOCSZ,U] ( calc.c.6809.asm):00137 * return 0; 0081 CC0000 ( calc.c.6809.asm):00138 LDD #0 0084 3606 ( calc.c.6809.asm):00139 PSHU D 0086 39 ( calc.c.6809.asm):00140 RTS ( calc.c.6809.asm):00141 * break; ( calc.c.6809.asm):00142 ( calc.c.6809.asm):00143 * case '+' : 0087 ( calc.c.6809.asm):00144 calc_if00_c01 ( calc.c.6809.asm):00145 * result += num; 0087 EC44 ( calc.c.6809.asm):00146 LDD result,U 0089 E342 ( calc.c.6809.asm):00147 ADDD num,U ( calc.c.6809.asm):00148 * break; 008B 2045 ( calc.c.6809.asm):00149 BRA calc_if00_end ( calc.c.6809.asm):00150 * case '-' : 008D ( calc.c.6809.asm):00151 calc_if00_c02 ( calc.c.6809.asm):00152 * result -= num; 008D EC44 ( calc.c.6809.asm):00153 LDD result,U 008F A342 ( calc.c.6809.asm):00154 SUBD num,U ( calc.c.6809.asm):00155 * break; 0091 203F ( calc.c.6809.asm):00156 BRA calc_if00_end ( calc.c.6809.asm):00157 * case '/' : 0093 ( calc.c.6809.asm):00158 calc_if00_c03 ( calc.c.6809.asm):00159 * result /= num; 0093 AE44 ( calc.c.6809.asm):00160 LDX result,U 0095 EC42 ( calc.c.6809.asm):00161 LDD num,U 0097 3616 ( calc.c.6809.asm):00162 PSHU D,X 0099 170046 ( calc.c.6809.asm):00163 LBSR IDIV 009C 3706 ( calc.c.6809.asm):00164 PULU D ( calc.c.6809.asm):00165 * break; 009E 2032 ( calc.c.6809.asm):00166 BRA calc_if00_end ( calc.c.6809.asm):00167 * case '*' : 00A0 ( calc.c.6809.asm):00168 calc_if00_c04 ( calc.c.6809.asm):00169 * result *= num; 00A0 AE44 ( calc.c.6809.asm):00170 LDX result,U 00A2 EC42 ( calc.c.6809.asm):00171 LDD num,U 00A4 3616 ( calc.c.6809.asm):00172 PSHU D,X 00A6 170039 ( calc.c.6809.asm):00173 LBSR IMUL 00A9 3706 ( calc.c.6809.asm):00174 PULU D ( calc.c.6809.asm):00175 * break; 00AB 2025 ( calc.c.6809.asm):00176 BRA calc_if00_end ( calc.c.6809.asm):00177 * case '%' : 00AD ( calc.c.6809.asm):00178 calc_if00_c05 ( calc.c.6809.asm):00179 * result %= num; 00AD AE44 ( calc.c.6809.asm):00180 LDX result,U 00AF EC42 ( calc.c.6809.asm):00181 LDD num,U 00B1 3616 ( calc.c.6809.asm):00182 PSHU D,X 00B3 17002C ( calc.c.6809.asm):00183 LBSR IMOD 00B6 3706 ( calc.c.6809.asm):00184 PULU D ( calc.c.6809.asm):00185 * break; 00B8 2018 ( calc.c.6809.asm):00186 BRA calc_if00_end ( calc.c.6809.asm):00187 * case '&' : 00BA ( calc.c.6809.asm):00188 calc_if00_c06 ( calc.c.6809.asm):00189 * result &= num; 00BA EC44 ( calc.c.6809.asm):00190 LDD result,U 00BC E443 ( calc.c.6809.asm):00191 ANDB num+1,U 00BE A442 ( calc.c.6809.asm):00192 ANDA num,U ( calc.c.6809.asm):00193 * break; 00C0 2010 ( calc.c.6809.asm):00194 BRA calc_if00_end ( calc.c.6809.asm):00195 * case '|' : 00C2 ( calc.c.6809.asm):00196 calc_if00_c07 ( calc.c.6809.asm):00197 * result |= num; 00C2 EC44 ( calc.c.6809.asm):00198 LDD result,U 00C4 EA43 ( calc.c.6809.asm):00199 ORB num+1,U 00C6 AA42 ( calc.c.6809.asm):00200 ORA num,U ( calc.c.6809.asm):00201 * break; 00C8 2008 ( calc.c.6809.asm):00202 BRA calc_if00_end ( calc.c.6809.asm):00203 * case '^' : 00CA ( calc.c.6809.asm):00204 calc_if00_c08 ( calc.c.6809.asm):00205 * result ^= num; 00CA EC44 ( calc.c.6809.asm):00206 LDD result,U 00CC E843 ( calc.c.6809.asm):00207 EORB num+1,U 00CE A842 ( calc.c.6809.asm):00208 EORA num,U ( calc.c.6809.asm):00209 * break; 00D0 2000 ( calc.c.6809.asm):00210 BRA calc_if00_end ( calc.c.6809.asm):00211 * Code duplicate of case 0 ( calc.c.6809.asm):00212 * default: ( calc.c.6809.asm):00213 * calc_if00_else ( calc.c.6809.asm):00214 * *status = CALC_BAD_OP; ( calc.c.6809.asm):00215 * return 0; ( calc.c.6809.asm):00216 * break; ( calc.c.6809.asm):00217 * } 00D2 ( calc.c.6809.asm):00218 calc_if00_end 00D2 ED44 ( calc.c.6809.asm):00219 STD result,U 00D4 16FF4D ( calc.c.6809.asm):00220 LBRA calc_lp00 ( calc.c.6809.asm):00221 * } 00D7 ( calc.c.6809.asm):00222 calc_lx00 ( calc.c.6809.asm):00223 * *status = CALC_SUCCESS; 00D7 CC0001 ( calc.c.6809.asm):00224 LDD #CALC_NO_OP 00DA EDD809 ( calc.c.6809.asm):00225 STD [status+_LOCSZ,U] ( calc.c.6809.asm):00226 * return result; 00DD EC44 ( calc.c.6809.asm):00227 LDD result,U 00DF 3606 ( calc.c.6809.asm):00228 PSHU D 00E1 39 ( calc.c.6809.asm):00229 RTS ( calc.c.6809.asm):00230 * } ( calc.c.6809.asm):00231 ( calc.c.6809.asm):00232 * Leave it possible to assemble, if not run: 00E2 ( calc.c.6809.asm):00233 IMUL 00E2 ( calc.c.6809.asm):00234 IDIV 00E2 ( calc.c.6809.asm):00235 IMOD 00E2 ( calc.c.6809.asm):00236 strlen 00E2 ( calc.c.6809.asm):00237 next_num 00E2 ( calc.c.6809.asm):00238 find_match 00E2 ( calc.c.6809.asm):00239 read_num 00E2 ( calc.c.6809.asm):00240 next_tok 00E2 ( calc.c.6809.asm):00241 read_var EQU * 00E2 ( calc.c.6809.asm):00242 total_trim ( calc.c.6809.asm):00243 END