Mercurial > hg > index.cgi
changeset 75:5f8f0b0781e8
Split some code into separate files for easier management (3)
Because the source for lwbasic is so large, split it into several
different files to make it easier to navigate and modify. This is
part three of the split. Includes a file missing from part one.
author | William Astle <lost@l-w.ca> |
---|---|
date | Sun, 06 Aug 2023 00:41:26 -0600 |
parents | e74d00ac6b79 |
children | eb2681108660 |
files | Makefile src/error.s src/expr.s src/interp.s src/lwbasic.s src/print.s |
diffstat | 6 files changed, 364 insertions(+), 236 deletions(-) [+] |
line wrap: on
line diff
--- a/Makefile Sun Aug 06 00:36:48 2023 -0600 +++ b/Makefile Sun Aug 06 00:41:26 2023 -0600 @@ -1,7 +1,7 @@ .PHONY: all all: bin/lwbasic.rom bin/lwbasic-coco2b.rom bin/lwbasic-coco3.rom bin/coco2.zip bin/coco2b.zip bin/coco3.zip -lwb_srcs := consscr.s defs.s genio.s init.s interp.s irq.s keyb.s miscdata.s print.s progctrl.s vars.s +lwb_srcs := consscr.s defs.s error.s expr.s genio.s init.s interp.s irq.s keyb.s miscdata.s print.s progctrl.s vars.s lwb_srcs := $(addprefix src/,$(lwb_srcs)) bin/lwbasic.rom: src/lwbasic.s $(lwb_srcs)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/error.s Sun Aug 06 00:41:26 2023 -0600 @@ -0,0 +1,64 @@ + *pragmapush list + *pragma list +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; The error handler +; +; Enter with the error number in B. This routine will do some cleanup and handle any ON ERROR GOTO handler that +; may be active. +; +; Note the error message lookup does not need to be efficient which is why the lookup just runs through the list +; of error messages in sequence looking for NUL terminators. The specific handling of B (error number) below avoids +; issues if there happen to be error codes above 128. +ERROR clr filenum ; reset display device to console + jsr writecondnl ; do a newline if needed (will preserve B) + ldx #errormsg ; point to error message list + incb ; account for decb below + bra ERROR1 ; go search for correct message +ERROR0 lda ,x+ ; end of message? + bne ERROR0 ; brif not end of message +ERROR1 decb ; at the correct one? + bne ERROR0 ; brif not - skip to next one +ERROR2 jsr writestrconduc ; output error message + ldu curline ; are we in immediate mode? + beq ERROR3 ; brif so + ldx #inmsg ; point to " in " + jsr writestrconduc ; output " in " + ldd 2,u ; get line number + jsr print_uint16d ; display the line number +ERROR3 lds freetop ; reset the stack pointer (error routine could be called anywhere) + clr ,-s ; reset the call stack + sts stackptr + jmp immediate ; go back to immediate mode +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Error messages +; +; Each error begins with a deferr macro invocation which will define a symbol err_slug with the next error number +; +; deferr slug +; +; This is then followed by the error message defined with fcn. +; +; Real error numbers start at 1; 0 is used to indicate no error. + *pragmapush list + *pragma nolist +__errnum set 0 +deferr macro noexpand +err_{1} equ __errnum +__errnum set __errnum+1 + endm + *pragmapop list +errormsg deferr none + fcn 'No error' + deferr nf + fcn 'NEXT without FOR' + deferr sn + fcn 'Syntax error' + deferr ul + fcn 'Undefined line number' + deferr rg + fcn 'RETURN without GOSUB' + deferr ov + fcn 'Overflow' + deferr tm + fcn 'Type mismatch' + *pragmapop list
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/expr.s Sun Aug 06 00:41:26 2023 -0600 @@ -0,0 +1,176 @@ + *pragmapush list + *pragma list +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; The LET command which is the default if no token begins a statement +cmd_let jmp SNERROR ; not yet implemented +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Expression Evaluation Package +; +; This is the expression evaluator. It handles everything from parsing numbers to dispatching function calls. The main +; entry point is eval_expr which will evaluate an arbitrary expression. It returns as soon as it reaches something it +; doesn't understand as part of an expression. +; +; The special handling for relational operators is required because Basic allows them in all +eval_expr clrb ; flag previous operator as minimum precdence (end of expression) +eval_expraux jsr eval_term ; evaluate the first term of the expression +eval_expr0 jsr curchar ; fetch current input + beq eval_expr1 ; brif end of expression - we're done + cmpa #tok_or ; is it above operators? + bhi eval_expr1 ; brif so + suba #tok_plus ; offset to zero for first operator token + bcc eval_expr2 ; brif it is an operator +eval_expr1 rts +eval_expr2 pshs b ; save previous operator precedence + ldx #oper_tab ; point to operator table + tfr a,b ; shift to B for "ABX" + abx ; add three times (3 bytes per entry) + abx ; OBS: TFR + ABX + ABX + ABX is faster than LDB + MUL + ABX + abx ; now X points to the operator entry in the table + ldb ,x ; get precedence of current operation + cmpb ,s ; is it higher than the current operation? + bhi eval_expr3 ; brif so - process this operator + puls b,pc ; return current value to complete previous operation +eval_expr3 jsr nextchar ; eat the operator token + ldx 1,x ; get handler address of this operator + leas -val.size,s ; make room for the result accumulator + pshs x ; save handler address for later + lda val0+val.type ; get current value type + ldx val0 ; get value accumlator contents (6 bytes) + ldy val0+2 + ldu val0+4 + pshs a,x,y,u ; save it on the stack + jsr eval_expraux ; evaluate the following term and higher precedence expressions + puls a,x,y,u ; get back saved value + stx val1 ; save it to the second value accumulator + sty val1+2 + stu val1+4 + sta val1+val.type ; save previous value type + ldx #val1 ; point to left operand + ldu #val0 ; point to right operand + leay 2,s ; point to return value location + jsr [,s++] ; go handle the operator + puls a,x,y,u ; get return value + sta val0 + stx val0+1 + sty val0+3 + stu val0+5 + puls b ; get back the previous operator precedence + bra eval_expr0 ; go process another operator or end of expression +eval_term jsr curchar ; get current input character + beq eval_term0 ; brif end of input - this is an error + bcs eval_number ; brif digit - we have a number +; bmi eval_func ; brif we have a token - handle function call + cmpa #'. ; decimal point? + beq eval_number ; brif so - evaluate number + cmpa #'- ; negative sign? + beq eval_number ; brif so - evaluate number + cmpa #'+ ; positive sign? + beq eval_number ; brif so - evaluate number +eval_term0 jmp SNERROR ; we have something unrecognized - raise error +; Evaluate a number constant. Currently this only handles 32 bit integers. +eval_number ldb #valtype_int ; start with integer value + stb val0+val.type ; set return value + ldx zero ; blank out the value + stx val0 + stx val0+2 + stx val0+4 + bra eval_number1 ; go do the parsing +eval_number0 jsr nextchar ; fetch next input + beq eval_numberr ; brif end of expression - bail +eval_number1 cmpa #'- ; negative (ascii sign)? + beq eval_number3 ; brif so + cmpa #tok_minus ; negative (operator negative)? + bne eval_number2 ; brif not +eval_number3 com val0+val.fpsign ; invert sign + bra eval_number0 ; deal with next input +eval_number2 cmpa #'+ ; unary +? + beq eval_number0 ; brif so - skip it +eval_number5 cmpa #'. ; decimal point? + beq eval_float ; brif decimal - force float + cmpa #'0 ; is it a number? + blo eval_numberr ; brif below digit + cmpa #'9 ; is it still a number? + bhi eval_numberr ; brif above digit + suba #'0 ; offset to binary digit value + pshs a ; save digit value + ldx val0+val.int ; get current value for later (for quick multiply by 10) + ldd val0+val.int+2 + pshs d,x ; stored with words swapped on stack for efficiency for later + lsl val0+val.int+3 ; times 2 + rol val0+val.int+2 + rol val0+val.int+1 + rol val0+val.int + bcs OVERROR ; brif overflowed + lsl val0+val.int+3 ; times 4 + rol val0+val.int+2 + rol val0+val.int+1 + rol val0+val.int + bcs OVERROR ; brif overflowed + ldd val0+val.int+2 ; times 5 (add original value) + addd ,s++ + std val0+val.int+2 + ldd val0+val.int + adcb 1,s + adca ,s++ + std val0+val.int + bcs OVERROR + lsl val0+val.int+3 ; times 10 + rol val0+val.int+2 + rol val0+val.int+1 + rol val0+val.int + bcs OVERROR ; brif overflowed + ldd val0+val.int+2 ; get low word + addb ,s+ ; add in current digit + adca #0 + std val0+val.int+2 + ldd val0+val.int + adcb #0 + adca #0 + std val0+val.int + bcs OVERROR ; brif overflowed + bpl eval_number4 ; brif we haven't wrapped negative + cmpd #0x8000 ; is it valid negative two's complement? + bhi OVERROR ; brif not + ldd val0+val.int+2 ; is it still valid two's complement (max negative)? + bne OVERROR ; brif so +eval_number4 jsr nextchar ; fetch next input character + bra eval_number5 ; go handle it +OVERROR ldb #err_ov ; flag overflow + jmp ERROR +eval_numberr ldb val0+val.fpsign ; is the number we want negative? + beq eval_numberr0 ; brif not + jsr val_negint32 ; negate the integer +eval_numberr0 rts +eval_float jmp SNERROR ; we don't handle floating point yet +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Operator table +; +; Each entry starts with the precedence value followed by the handler routine. Each handler will receive its left +; operand in val1 and its right operand in val0 and should return its result in val0. +oper_tab fcb 0x79 ; addition + fdb oper_plus + fcb 0x79 ; subtraction + fdb oper_minus + fcb 0x7b ; multiplication + fdb SNERROR + fcb 0x7b ; division + fdb SNERROR + fcb 0x7f ; exponentiation + fdb SNERROR + fcb 0x64 ; less than + fdb SNERROR + fcb 0x64 ; equal to + fdb SNERROR + fcb 0x64 ; greater than + fdb SNERROR + fcb 0x64 ; less than or equal to + fdb SNERROR + fcb 0x64 ; greater than or equal to + fdb SNERROR + fcb 0x64 ; not equal to + fdb SNERROR + fcb 0x50 ; boolean AND + fdb SNERROR + fcb 0x46 ; boolean OR + fdb SNERROR + *pragmapop list
--- a/src/interp.s Sun Aug 06 00:36:48 2023 -0600 +++ b/src/interp.s Sun Aug 06 00:41:26 2023 -0600 @@ -43,35 +43,6 @@ suba #-'0 curcharraw0 rts ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; The error handler -; -; Enter with the error number in B. This routine will do some cleanup and handle any ON ERROR GOTO handler that -; may be active. -; -; Note the error message lookup does not need to be efficient which is why the lookup just runs through the list -; of error messages in sequence looking for NUL terminators. The specific handling of B (error number) below avoids -; issues if there happen to be error codes above 128. -ERROR clr filenum ; reset display device to console - jsr writecondnl ; do a newline if needed (will preserve B) - ldx #errormsg ; point to error message list - incb ; account for decb below - bra ERROR1 ; go search for correct message -ERROR0 lda ,x+ ; end of message? - bne ERROR0 ; brif not end of message -ERROR1 decb ; at the correct one? - bne ERROR0 ; brif not - skip to next one -ERROR2 jsr writestrconduc ; output error message - ldu curline ; are we in immediate mode? - beq ERROR3 ; brif so - ldx #inmsg ; point to " in " - jsr writestrconduc ; output " in " - ldd 2,u ; get line number - jsr print_uint16d ; display the line number -ERROR3 lds freetop ; reset the stack pointer (error routine could be called anywhere) - clr ,-s ; reset the call stack - sts stackptr - ; fall through to immediate mode intentional -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Immediate mode handler immediate jsr writecondnl ; do newline if required ldx #prompt ; point to prompt string
--- a/src/lwbasic.s Sun Aug 06 00:36:48 2023 -0600 +++ b/src/lwbasic.s Sun Aug 06 00:41:26 2023 -0600 @@ -45,215 +45,12 @@ include interp.s include progctrl.s include print.s - + include error.s + include expr.s + include miscdata.s *pragmapop list ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Error messages -; -; Each error begins with a deferr macro invocation which will define a symbol err_slug with the next error number -; -; deferr slug -; -; This is then followed by the error message defined with fcn. -; -; Real error numbers start at 1; 0 is used to indicate no error. - *pragmapush list - *pragma nolist -__errnum set 0 -deferr macro noexpand -err_{1} equ __errnum -__errnum set __errnum+1 - endm - *pragmapop list -errormsg deferr none - fcn 'No error' - deferr nf - fcn 'NEXT without FOR' - deferr sn - fcn 'Syntax error' - deferr ul - fcn 'Undefined line number' - deferr rg - fcn 'RETURN without GOSUB' - deferr ov - fcn 'Overflow' - deferr tm - fcn 'Type mismatch' -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; The LET command which is the default if no token begins a statement -cmd_let jmp SNERROR ; not yet implemented -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Expression Evaluation Package -; -; This is the expression evaluator. It handles everything from parsing numbers to dispatching function calls. The main -; entry point is eval_expr which will evaluate an arbitrary expression. It returns as soon as it reaches something it -; doesn't understand as part of an expression. -; -; The special handling for relational operators is required because Basic allows them in all -eval_expr clrb ; flag previous operator as minimum precdence (end of expression) -eval_expraux jsr eval_term ; evaluate the first term of the expression -eval_expr0 jsr curchar ; fetch current input - beq eval_expr1 ; brif end of expression - we're done - cmpa #tok_or ; is it above operators? - bhi eval_expr1 ; brif so - suba #tok_plus ; offset to zero for first operator token - bcc eval_expr2 ; brif it is an operator -eval_expr1 rts -eval_expr2 pshs b ; save previous operator precedence - ldx #oper_tab ; point to operator table - tfr a,b ; shift to B for "ABX" - abx ; add three times (3 bytes per entry) - abx ; OBS: TFR + ABX + ABX + ABX is faster than LDB + MUL + ABX - abx ; now X points to the operator entry in the table - ldb ,x ; get precedence of current operation - cmpb ,s ; is it higher than the current operation? - bhi eval_expr3 ; brif so - process this operator - puls b,pc ; return current value to complete previous operation -eval_expr3 jsr nextchar ; eat the operator token - ldx 1,x ; get handler address of this operator - leas -val.size,s ; make room for the result accumulator - pshs x ; save handler address for later - lda val0+val.type ; get current value type - ldx val0 ; get value accumlator contents (6 bytes) - ldy val0+2 - ldu val0+4 - pshs a,x,y,u ; save it on the stack - jsr eval_expraux ; evaluate the following term and higher precedence expressions - puls a,x,y,u ; get back saved value - stx val1 ; save it to the second value accumulator - sty val1+2 - stu val1+4 - sta val1+val.type ; save previous value type - ldx #val1 ; point to left operand - ldu #val0 ; point to right operand - leay 2,s ; point to return value location - jsr [,s++] ; go handle the operator - puls a,x,y,u ; get return value - sta val0 - stx val0+1 - sty val0+3 - stu val0+5 - puls b ; get back the previous operator precedence - bra eval_expr0 ; go process another operator or end of expression -eval_term jsr curchar ; get current input character - beq eval_term0 ; brif end of input - this is an error - bcs eval_number ; brif digit - we have a number -; bmi eval_func ; brif we have a token - handle function call - cmpa #'. ; decimal point? - beq eval_number ; brif so - evaluate number - cmpa #'- ; negative sign? - beq eval_number ; brif so - evaluate number - cmpa #'+ ; positive sign? - beq eval_number ; brif so - evaluate number -eval_term0 jmp SNERROR ; we have something unrecognized - raise error -; Evaluate a number constant. Currently this only handles 32 bit integers. -eval_number ldb #valtype_int ; start with integer value - stb val0+val.type ; set return value - ldx zero ; blank out the value - stx val0 - stx val0+2 - stx val0+4 - bra eval_number1 ; go do the parsing -eval_number0 jsr nextchar ; fetch next input - beq eval_numberr ; brif end of expression - bail -eval_number1 cmpa #'- ; negative (ascii sign)? - beq eval_number3 ; brif so - cmpa #tok_minus ; negative (operator negative)? - bne eval_number2 ; brif not -eval_number3 com val0+val.fpsign ; invert sign - bra eval_number0 ; deal with next input -eval_number2 cmpa #'+ ; unary +? - beq eval_number0 ; brif so - skip it -eval_number5 cmpa #'. ; decimal point? - beq eval_float ; brif decimal - force float - cmpa #'0 ; is it a number? - blo eval_numberr ; brif below digit - cmpa #'9 ; is it still a number? - bhi eval_numberr ; brif above digit - suba #'0 ; offset to binary digit value - pshs a ; save digit value - ldx val0+val.int ; get current value for later (for quick multiply by 10) - ldd val0+val.int+2 - pshs d,x ; stored with words swapped on stack for efficiency for later - lsl val0+val.int+3 ; times 2 - rol val0+val.int+2 - rol val0+val.int+1 - rol val0+val.int - bcs OVERROR ; brif overflowed - lsl val0+val.int+3 ; times 4 - rol val0+val.int+2 - rol val0+val.int+1 - rol val0+val.int - bcs OVERROR ; brif overflowed - ldd val0+val.int+2 ; times 5 (add original value) - addd ,s++ - std val0+val.int+2 - ldd val0+val.int - adcb 1,s - adca ,s++ - std val0+val.int - bcs OVERROR - lsl val0+val.int+3 ; times 10 - rol val0+val.int+2 - rol val0+val.int+1 - rol val0+val.int - bcs OVERROR ; brif overflowed - ldd val0+val.int+2 ; get low word - addb ,s+ ; add in current digit - adca #0 - std val0+val.int+2 - ldd val0+val.int - adcb #0 - adca #0 - std val0+val.int - bcs OVERROR ; brif overflowed - bpl eval_number4 ; brif we haven't wrapped negative - cmpd #0x8000 ; is it valid negative two's complement? - bhi OVERROR ; brif not - ldd val0+val.int+2 ; is it still valid two's complement (max negative)? - bne OVERROR ; brif so -eval_number4 jsr nextchar ; fetch next input character - bra eval_number5 ; go handle it -OVERROR ldb #err_ov ; flag overflow - jmp ERROR -eval_numberr ldb val0+val.fpsign ; is the number we want negative? - beq eval_numberr0 ; brif not - jsr val_negint32 ; negate the integer -eval_numberr0 rts -eval_float jmp SNERROR ; we don't handle floating point yet -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Operator table -; -; Each entry starts with the precedence value followed by the handler routine. Each handler will receive its left -; operand in val1 and its right operand in val0 and should return its result in val0. -oper_tab fcb 0x79 ; addition - fdb oper_plus - fcb 0x79 ; subtraction - fdb oper_minus - fcb 0x7b ; multiplication - fdb SNERROR - fcb 0x7b ; division - fdb SNERROR - fcb 0x7f ; exponentiation - fdb SNERROR - fcb 0x64 ; less than - fdb SNERROR - fcb 0x64 ; equal to - fdb SNERROR - fcb 0x64 ; greater than - fdb SNERROR - fcb 0x64 ; less than or equal to - fdb SNERROR - fcb 0x64 ; greater than or equal to - fdb SNERROR - fcb 0x64 ; not equal to - fdb SNERROR - fcb 0x50 ; boolean AND - fdb SNERROR - fcb 0x46 ; boolean OR - fdb SNERROR -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Set carry if upper/lower case alpha setcifalpha cmpa #'z+1 ; is it above lower case Z? bhs setcifalpha0 ; brif so, C clear
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/print.s Sun Aug 06 00:41:26 2023 -0600 @@ -0,0 +1,120 @@ + *pragmapush list + *pragma list +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Print out an unsigned 16 bit value in D to the selected output stream +print_uint16d pshs d,x,y,u ; save number and make some temporaries on the stack + leay 2,s ; point to start of buffer + ldu #10000 ; do the 10000s digit + bsr print_uint16d4 + ldu #1000 ; do the 1000s digit + bsr print_uint16d4 + ldu #100 ; do the 100s digit + bsr print_uint16d4 + ldu #10 ; do the 10s digit + bsr print_uint16d4 + puls d ; get back number residue and clean up stack + addb #0x30 ; convert 1s digit to number + stb ,y ; stash it + clr 1,y ; NUL terminate it + leay ,s ; point to start of converted number +print_uint16d0 lda ,y ; get digit at start + cmpa #0x30 ; zero digit? + bne print_uint16d1 ; brif not - we can just show the number from here + ldb 1,y ; end of number? + beq print_uint16d1 ; brif so - show the zero anyway + leay 1,y ; move past the zero + bra print_uint16d0 ; see if we have more zeroes to skip +print_uint16d1 lda ,y+ ; get number digit + beq print_uint16d2 ; brif end of number + jsr writechr ; output the digit + bra print_uint16d1 ; handle next digit +print_uint16d2 leas 6,s ; clean up the stack + rts +print_uint16d4 lda #0x30-1 ; init digit value + pshs a,u ; save the digit position and digit value + ldd 5,s ; get back residue +print_uint16d5 inc ,s ; bump digit + subd 1,s ; subtract out place value + bcc print_uint16d5 ; brif we haven't got the right digit yet + addd 1,s ; restore residue + std 5,s ; save new residue + puls a,u ; get back digit and place value off stack + sta ,y+ ; save digit in buffer + rts + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; PRINT command +cmd_print beq cmd_printeol ; brif no argument - do a newline +cmd_print0 cmpa #'; ; semicolon? + bne cmd_print1 ; brif not + jsr nextchar ; skip the semicolon + bne cmd_print0 ; brif not end of the statement + rts +cmd_print1 jsr eval_expr ; evaluate the expression + ldb val0+val.type ; get value type + cmpb #valtype_int ; integer? + beq cmd_printint ; brif so - print integer + lda #'! ; flag unknown expression type + jsr console_outchr + jsr console_outchr + jsr console_outchr +cmd_printnext jsr curchar ; see what we have here + bra cmd_print ; and go process +cmd_printeol jmp console_outnl ; do a newline and return +cmd_printint leas -12,s ; make a buffer + leay ,s ; point to buffer + lda #0x20 ; default sign (positive) + ldb val0+val.int ; is it negative? + bpl cmd_printint0 ; brif not + jsr val_negint32 ; negate the integer + lda #'- ; negative sign +cmd_printint0 sta ,y+ ; save sign + ldu #cmd_printintpc ; point to positive constant table + ldx #10 ; there are 10 constants to process +; subtraction loop - positive residue +cmd_printint1 lda #'0-1 ; initialize digit + sta ,y +cmd_printint2 inc ,y ; bump digit + ldd val0+val.int+2 ; subtract constant + subd 2,u + std val0+val.int+2 + ldd val0+val.int + sbcb 1,u + sbca ,u + std val0+val.int + bcc cmd_printint2 ; brif we didn't go negative + ldd val0+val.int+2 ; undo last subtract + addd 2,u + std val0+val.int+2 + ldd val0+val.int + adcb 1,u + adca ,u + std val0+val.int + leay 1,y ; move to next digit in buffer + leau 4,u ; move to next constant + leax -1,x ; done all constants? + bne cmd_printint1 ; brif not - done all +cmd_printint5 clr ,y ; NUL terminate the string + leax 1,s ; point past the sign +cmd_printint6 lda ,x+ ; get digit + beq cmd_printint8 ; brif end of number + cmpa #'0 ; is it a zero? + beq cmd_printint6 ; brif so - skip it +cmd_printint7 lda ,s ; get the sign + sta ,--x ; put it at the start of the number + jsr console_outstr ; display the number + leas 12,s ; clean up stack + bra cmd_printnext ; go print the next thing +cmd_printint8 leax -1,x ; restore one of the zeros + bra cmd_printint7 ; go finish up +cmd_printintpc fqb 1000000000 ; 10^9 + fqb 100000000 ; 10^8 + fqb 10000000 ; 10^7 + fqb 1000000 ; 10^6 + fqb 100000 ; 10^5 + fqb 10000 ; 10^4 + fqb 1000 ; 10^3 + fqb 100 ; 10^2 + fqb 10 ; 10^1 + fqb 1 ; 10^0 + *pragmapop list