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