forked from microsoft/GW-BASIC
-
Notifications
You must be signed in to change notification settings - Fork 0
/
GWEVAL.ASM
1647 lines (1555 loc) · 49.1 KB
/
GWEVAL.ASM
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
; [ This translation created 10-Feb-83 by Version 4.3 ]
.RADIX 8 ; To be safe
CSEG SEGMENT PUBLIC 'CODESG'
ASSUME CS:CSEG
INCLUDE BINTRP.H
TITLE GWEVAL Copied from BINTRP.MAC
.RADIX 10
.XLIST
FETOK=0 ;For FE extended tokens
FDTOK=0 ;For FD tokens too. (Must have
;FETOK==1.)
;tokens.
INTDEX=0 ;For Intelledex version.
NMPAGE=1 ;Number of text pages (for GW
;Multi-page)
;KPOS, etc.
LNREAD=0 ;For LINE READ statement
MELCO=0 ;Mitsubishi Electronics Co.
SIRIUS=0
MCI=0
ZENITH=0 ;ZENITH 8086
TETRA=0
CPM86=0
HAL=0
GENFLS=0
PANDBL=0
TSHIBA=0
SGS=0
ALPS=0
ALPCPM=0
GENWID=0
NNECBS=0
CAN8=0
PC8A=0
FN2SW=0 ;IBMTOK versions dispatch from IBMRES.MAC
_LABEL=PC8A
HLPEDT=PC8A
OKI=0
BUBL=0
NORNF=0
IEESLV=0
TRSHHC=0
OLVPPC=0
NECPPC=0
USA=0 ;For HHC-USA version
EUROPE=0 ;For HHC-EUROPE version
.LIST
;Local Switches
;
LTRACE=ALPCPM ;trace output selectable
_LABEL=PC8A
HLPEDT=PC8A
UCEMSG=NNECBS ;Upper case error messages.
OLD86=MELCO AND CPM86 ;For "old" 8086 error messages (prior
;to alignment for IBM compatibility).
OLDBLD=ALPCPM OR ALPS OR OKI OR HAL OR PC8A OR BUBL OR GW OR TSHIBA
INCLUDE GIO86U
INCLUDE MSDOSU ;MSDOS constants
EXTRN INIT:NEAR
EXTRN SETGSB:NEAR
DSEG SEGMENT PUBLIC 'DATASG'
ASSUME DS:DSEG
EXTRN ONGSBF:WORD
DSEG ENDS
BUFOFS=0
BUFOFS=2 ;MUST CRUNCH INTO ERALIER PLACE FOR
; SINGLE QUOTE
KBFLEN=BUFLEN+(BUFLEN/4) ;MAKE KRUNCH BUFFER SOMEWHAT
; LARGER THAN SOURCE BUFFER (BUF)
EXTRN _NAME:NEAR
EXTRN INLIN:NEAR,CRDO:NEAR,CRDONZ:NEAR,STRCMP:NEAR,FININL:NEAR
EXTRN PPSWRT:NEAR
EXTRN OUTDO:NEAR
EXTRN BLTU:NEAR,CLEARC:NEAR,GTMPRT:NEAR,ISLET:NEAR,ISLET2:NEAR
EXTRN PTRGET:NEAR
EXTRN QINLIN:NEAR,SCRTCH:NEAR,STKINI:NEAR,RUNC:NEAR,RESFIN:NEAR
EXTRN PTRGT2:NEAR,STPEND:NEAR,DIM:NEAR
EXTRN DCOMPR:NEAR,SYNCHR:NEAR
EXTRN SIGN:NEAR
EXTRN PRGFIN:NEAR,FILIND:NEAR
EXTRN FILINP:NEAR,CLSALL:NEAR,INDSKC:NEAR
EXTRN LRUN:NEAR
EXTRN FILGET:NEAR
EXTRN INXHRT:NEAR
EXTRN SGN:NEAR,ABSFN:NEAR,SQR:NEAR,_FDIV:NEAR,_FSUB:NEAR
EXTRN FMULT:NEAR,RND:NEAR ;MATHPK INTERNALS
EXTRN ZERO:NEAR,MOVE:NEAR,FOUT:NEAR,FIN:NEAR,_FCOMP:NEAR
EXTRN _FADD:NEAR,_PUSHF:NEAR,_INT:NEAR
EXTRN MOVFR:NEAR,MOVRF:NEAR,MOVRM:NEAR,INPRT:NEAR,LINPRT:NEAR
EXTRN FDIVT:NEAR
EXTRN MOVFM:NEAR,MOVMF:NEAR,FADDS:NEAR
EXTRN INRART:NEAR,_NEG:NEAR
EXTRN BSERR:NEAR
EXTRN CAT:NEAR,FREFAC:NEAR,FRESTR:NEAR,FRETMP:NEAR,FRETMS:NEAR
EXTRN STRCPY:NEAR,GETSTK:NEAR
EXTRN STRLIT:NEAR,STRLT2:NEAR,STRLT3:NEAR,STRLTI:NEAR,STROUT:NEAR
EXTRN STRPRT:NEAR,STROUI:NEAR
EXTRN GETSPA:NEAR,PUTNEW:NEAR,STOP:NEAR,OMERR:NEAR,REASON:NEAR
EXTRN GARBA2:NEAR ;We have our own G. C.
EXTRN _INSTR:NEAR
EXTRN PRINUS:NEAR,PUTTMP:NEAR
EXTRN FOUTH:NEAR,FOUTO:NEAR,STRO$:NEAR,STRH$:NEAR
EXTRN STRNG$:NEAR
EXTRN TON:NEAR,TOFF:NEAR
EXTRN SPACE$:NEAR
EXTRN SIGNS:NEAR
EXTRN UMULT:NEAR
EXTRN SIGNC:NEAR,POPHRT:NEAR
EXTRN FINLPT:NEAR
EXTRN CONSIH:NEAR,VMOVFA:NEAR,VMOVAF:NEAR,ISIGN:NEAR,CONIA:NEAR
EXTRN VSIGN:NEAR,VDFACS:NEAR
EXTRN VMOVMF:NEAR,VMOVFM:NEAR,FRCINT:NEAR,FRCSNG:NEAR,FRCDBL:NEAR
EXTRN VNEG:NEAR,PUFOUT:NEAR,DCXBRT:NEAR,IADD:NEAR
EXTRN ISUB:NEAR,IMULT:NEAR,ICOMP:NEAR,INEG:NEAR,DADD:NEAR
EXTRN DSUB:NEAR,DMULT:NEAR,DDIV:NEAR,DCOMP:NEAR,VINT:NEAR
EXTRN FINDBL:NEAR,INEG2:NEAR
EXTRN _IDIV:NEAR,IMOD:NEAR
EXTRN VMOVE:NEAR,VALINT:NEAR,VALSNG:NEAR,FRCSTR:NEAR,CHKSTR:NEAR
EXTRN MAKINT:NEAR
EXTRN MOVE1:NEAR
EXTRN SCNSEM:NEAR
EXTRN _WHILE:NEAR,WEND:NEAR
EXTRN CALLS:NEAR
EXTRN PROCHK:NEAR
;The following block of externals was added on Dec 19, 1982 when BINTRP was
; Split up after the freeze of GW-BASIC Version 1.0
; This Split-up was not reflected in the PS1:<BASIC>BINTRP.MAC source.
; See Tom Corbett if you have any questions.
;
DSEG SEGMENT PUBLIC 'DATASG'
EXTRN MEMSIZ:WORD,FRETOP:WORD,VARTAB:WORD,STREND:WORD,TXTTAB:WORD
EXTRN ARYTAB:WORD
EXTRN CURLIN:WORD,DOT:WORD,DATLIN:WORD,NLONLY:WORD,ERRLIN:WORD
EXTRN ERRTXT:WORD
EXTRN MRGFLG:WORD,CHNFLG:WORD
EXTRN SAVSTK:WORD,SAVTXT:WORD,OLDLIN:WORD,NXTLIN:WORD,OLDTXT:WORD
EXTRN ONELIN:WORD,ONEFLG:WORD
EXTRN CNTOFL:WORD,TRCFLG:WORD,CONSAV:WORD,CONTXT:WORD,CONTYP:WORD
EXTRN NUMCON:WORD,CONLO:WORD
EXTRN AUTFLG:WORD,AUTLIN:WORD,AUTINC:WORD
EXTRN KBUF:WORD,BUFMIN:WORD,BUF:WORD
EXTRN PTRFIL:WORD,PTRFLG:WORD,DORES:WORD,VALTYP:WORD,FACLO:WORD
EXTRN DFACLO:WORD,FAC:WORD
EXTRN TEMP:WORD,TEMP2:WORD,TEMP3:WORD,TEMPA:WORD
EXTRN DSCTMP:WORD,TEMPST:WORD
EXTRN OPRTYP:WORD
EXTRN SUBFLG:WORD,FVALSV:WORD,DEFTBL:WORD,FLGINP:WORD,FLGSCN:WORD
EXTRN OVCSTR:WORD,INPPAS:WORD
EXTRN USRTAB:WORD,DONUM:WORD,ENDPRG:WORD,ENDFOR:WORD,DATPTR:WORD
EXTRN FLGOVC:WORD
EXTRN ERRFLG:WORD,SAVSEG:WORD,PRMLN2:WORD,PARM2:WORD,PRMLEN:WORD
EXTRN PRMSTK:WORD,PARM1:WORD
EXTRN FUNACT:WORD,NOFUNS:WORD,OPTVAL:WORD,OPTFLG:WORD,RNDX:WORD
DSEG ENDS
EXTRN OPTAB:NEAR,OPCNT:NEAR,INTDSP:NEAR,SNGDSP:NEAR,DBLDSP:NEAR
EXTRN FRCTBL:NEAR,PRMSIZ:NEAR
EXTRN $OVMSG:NEAR,ERRTAB:NEAR,LSTERR:NEAR,DSKERR:NEAR,NONDSK:NEAR
EXTRN REDDY:NEAR
EXTRN ERRSN:NEAR,ERRDV0:NEAR,ERRRE:NEAR,ERROV:NEAR,ERRMO:NEAR
EXTRN ERRTM:NEAR,ERRNF:NEAR
EXTRN ERRNR:NEAR,ERRLBO:NEAR,ERRDD:NEAR,ERRUF:NEAR,ERRUE:NEAR
EXTRN ERRFC:NEAR
EXTRN ERRIFN:NEAR,ERRFNO:NEAR,ERRDNA:NEAR,ERRFDR:NEAR,ERRRAD:NEAR
EXTRN ERRDFL:NEAR
EXTRN ERRIOE:NEAR,ERRBFM:NEAR,ERRFNF:NEAR,ERRBFN:NEAR,ERRIER:NEAR
EXTRN ERRRPE:NEAR
EXTRN ERRFAO:NEAR,ERRNMF:NEAR,ERRWH:NEAR,ERRBRN:NEAR,ERRFOV:NEAR
EXTRN ERRTMF:NEAR
EXTRN ERRFAE:NEAR,ERRUS:NEAR,ERRRG:NEAR,ERROD:NEAR,ERRID:NEAR
EXTRN ERRFN:NEAR
EXTRN ERRUE1:NEAR ;ERRUE+DSKERR-NONDSK
EXTRN DSKER1:NEAR ;DSKERR-NONDSK
;The following externs are defined in GWMAIN.MAC
;
EXTRN TMERR:NEAR,SNERR:NEAR,CHRGTR:NEAR,MOERR:NEAR,OVERR:NEAR
EXTRN FCERR:NEAR,ERROR:NEAR
EXTRN CONFAC:NEAR,FRMQNT:NEAR,DATA:NEAR,LETCN4:NEAR,$STPRN:NEAR
EXTRN ONECON:NEAR,DBLCON:NEAR
EXTRN FRQINT:NEAR,LINGET:NEAR,UFERR:NEAR
;
; The reserved word tables are in another module. Consequently
; many things must be declared external. All of these things
; are in the code segement or are absolutes (like tokens).
; I.e., they are not in the data segment.
;
EXTRN CLINTK:NEAR
EXTRN EQULTK:NEAR,ERCTK:NEAR,ERLTK:NEAR
EXTRN FNTK:NEAR,FUNDSP:NEAR
EXTRN GREATK:NEAR
EXTRN INSRTK:NEAR
EXTRN LESSTK:NEAR,LSTOPK:NEAR
EXTRN MIDTK:NEAR,MINUTK:NEAR
EXTRN NMREL:NEAR,NOTTK:NEAR
EXTRN ONEFUN:NEAR
EXTRN PLUSTK:NEAR
EXTRN USRTK:NEAR
EXTRN $INKEY$:NEAR,$INPUT:NEAR
EXTRN $POINT:NEAR
EXTRN $SCREEN:NEAR,$STRING$:NEAR
EXTRN $VARPTR:NEAR
;
; Since the dispatch table is also no longer in BINTRP many
; addresses need to be declared internal.
;
PUBLIC DEF
PUBLIC FNINP,FNOUT,FNWAIT
PUBLIC LABBCK
SUBTTL FORMULA EVALUATION CODE
;
; THE FORMULA EVALUATOR STARTS WITH
; [H,L] POINTING TO THE FIRST CHARACTER OF THE FORMULA.
; AT THE END [H,L] POINTS TO THE TERMINATOR.
; THE RESULT IS LEFT IN THE FAC.
; ON RETURN [A] DOES NOT REFLECT THE TERMINATING CHARACTER
;
; THE FORMULA EVALUATOR USES THE OPERATOR TABLE (OPTAB)
; TO DETERMINE PRECEDENCE AND DISPATCH ADDRESSES FOR
; EACH OPERATOR.
; A TEMPORARY RESULT ON THE STACK HAS THE FOLLOWING FORMAT
;
; THE ADDRESS OF 'RETAOP' -- THE PLACE TO RETURN ON COMPLETION
; OF OPERATOR APPLICATION
;
; THE FLOATING POINT TEMPORARY RESULT
;
; THE ADDRESS OF THE OPERATOR ROUNTINE
;
; THE PRECEDENCE OF THE OPERATOR
;
; TOTAL 10 BYTES
;
PUBLIC FRMEQL
FRMEQL: CALL SYNCHR
DW OFFSET EQULTK ;CHECK FOR EQUAL SIGN
JMP FRMEVL
PUBLIC FRMPRN
FRMPRN: CALL SYNCHR
DB OFFSET "(" ;GET PAREN BEFORE FORMULA
PUBLIC FRMEVL
FRMEVL: DEC BX ;BACK UP CHARACTER POINTER
PUBLIC FRMCHK
FRMCHK: MOV DH,LOW 0 ;INITIAL DUMMY PRECEDENCE IS 0
LPOPER: PUSH DX ;SAVE PRECEDENCE
MOV CL,LOW 1 ;EXTRA SPACE NEEDED FOR RETURN ADDRESS
CALL GETSTK ;MAKE SURE THERE IS ROOM FOR RECURSIVE CALLS
CALL EVAL ;EVALUATE SOMETHING
;RESET OVERFLOW PRINTING BACK TO NORMAL
XOR AL,AL ;(SET TO 1 AT FUNDSP TO SUPPRESS
MOV BYTE PTR FLGOVC,AL ;MULTIPLE OVERFLOW MESSAGES)
PUBLIC TSTOP
TSTOP: MOV TEMP2,BX ;SAVE TEXT POINTER
RETAOP: MOV BX,TEMP2 ;RESTORE TEXT PTR
POP CX ;POP OFF THE PRECEDENCE OF OLDOP
NOTSTV: MOV AL,BYTE PTR [BX] ;GET NEXT CHARACTER
MOV TEMP3,BX ;SAVE UPDATED CHARACTER POINTER
CMP AL,LOW OFFSET GREATK ;IS IT AN OPERATOR?
JNB SHORT $+3
RET ;NO, ALL DONE (THIS CAN RESULT IN OPERATOR
;APPLICATION OR ACTUAL RETURN)
CMP AL,LOW OFFSET LESSTK+1 ;SOME KIND OF RELATIONAL?
JB SHORT DORELS ;YES, DO IT
SUB AL,LOW OFFSET PLUSTK ;SUBTRACT OFFSET FOR FIRST ARITHMETIC
MOV DL,AL ;MUST MULTIPLY BY 3 SINCE
;OPTAB ENTRIES ARE 3 LONG
JNZ SHORT NTPLUS ;NOT ADDITION OP
MOV AL,BYTE PTR VALTYP ;SEE IF LEFT PART IS STRING
CMP AL,LOW 3 ;SEE IF ITS A STRING
MOV AL,DL ;REFETCH OP-VALUE
JNZ SHORT ??L000
JMP CAT ;MUST BE CAT
??L000:
NTPLUS:
CMP AL,LOW OFFSET LSTOPK ;HIGHER THAN THE LAST OP?
JNAE SHORT $+3
RET ;YES, MUST BE TERMINATOR
MOV BX,OFFSET OPTAB ;CREATE INDEX INTO OPTAB
MOV DH,LOW 0 ;MAKE HIGH BYTE OF OFFSET=0
ADD BX,DX ;ADD IN CALCULATED OFFSET
MOV AL,CH ;[A] GETS OLD PRECEDENCE
INS86 56 ;CODE SEGMENT FETCH
MOV DH,BYTE PTR [BX] ;REMEMBER NEW PRECEDENCE
CMP AL,DH ;OLD-NEW
JNAE SHORT $+3
RET ;MUST APPLY OLD OP
;IF HAS GREATER OR = PRECEDENCE
;NEW OPERATOR
PUSH CX ;SAVE THE OLD PRECEDENCE
MOV CX,OFFSET RETAOP ;PUT ON THE ADDRESS OF THE
PUSH CX ;PLACE TO RETURN TO AFTER OPERATOR APPLICATION
MOV AL,DH ;SEE IF THE OPERATOR IS EXPONENTIATION
CMP AL,LOW 127 ;WHICH HAS PRECEDENCE 127
JZ SHORT EXPSTK ;IF SO, "FRCSNG" AND MAKE A SPECIAL STACK ENTRY
CMP AL,LOW 81 ;SEE IF THE OPERATOR IS "AND" OR "OR"
JB SHORT ANDORD ;AND IF SO "FRCINT" AND
;MAKE A SPECIAL STACK ENTRY
AND AL,LOW 254 ;MAKE 123 AND 122 BOTH MAP TO 122
CMP AL,LOW 122 ;MAKE A SPECIAL CHECK FOR "MOD" AND "IDIV"
JZ SHORT ANDORD ;IF SO, COERCE ARGUMENTS TO INTEGER
; THIS CODE PUSHES THE CURRENT VALUE IN THE FAC
; ONTO THE STACK, EXCEPT IN THE CASE OF STRINGS IN WHICH IT CALLS
; TYPE MISMATCH ERROR. [D] AND [E] ARE PRESERVED.
;
NUMREL:
MOV AL,BYTE PTR VALTYP ;FIND OUT WHAT TYPE OF VALUE WE ARE SAVING
SUB AL,LOW 3 ;SETUP THE CONDITION CODES
;SET ZERO FOR STRINGS
JNZ SHORT ??L001
JMP TMERR
??L001:
INS86 377,66,FACLO ;PUSH FACLO
JNS SHORT ??L002
JMP VPUSHD ;ALL DONE IF THE DATA WAS AN INTEGER
??L002:
INS86 377,66,FACLO+2 ;PUSH FAC-1,0 ON THE STACK
JP SHORT ??L003
JMP VPUSHD ;ALL DONE IF WE HAD A SNG
??L003:
INS86 377,66,DFACLO ;PUSH ON LOW BYTES OF DP FAC
INS86 377,66,DFACLO+2 ;PUSH ON NEXT TWO BYES OF DP FAC
VPUSHD:
ADD AL,LOW 3 ;FIX [A] TO BE THE VALTYP OF THE NUMBER
;JUST PUSHED ON THE STACK
MOV CL,DL ;[C]=OPERATOR NUMBER
MOV CH,AL ;[B]=TYPE OF VALUE ON THE STACK
PUSH CX ;SAVE THESE THINGS FOR APPLOP
MOV CX,OFFSET APPLOP ;GENERAL OPERATOR APPLICATION
;ROUTINE -- DOES TYPE CONVERSIONS
FINTMP: PUSH CX ;SAVE PLACE TO GO
MOV BX,TEMP3 ;REGET THE TEXT POINTER
JMP LPOPER
DORELS: MOV DH,LOW 0 ;ASSUME NO RELATION OPS
;ALSO SETUP THE HIGH ORDER OF THE INDEX INTO OPTAB
LOPREL: SUB AL,LOW OFFSET GREATK ;IS THIS ONE RELATION?
JB SHORT FINREL ;RELATIONS ALL THROUGH
CMP AL,LOW OFFSET NMREL ;IS IT REALLY RELATIONAL?
JAE SHORT FINREL ;NO JUST BIG
CMP AL,LOW 1 ;SET UP BITS BY MAPPING
RCL AL,1 ;0 TO 1 1 TO 2 AND 2 TO 4
XOR AL,DH ;BRING IN THE OLD BITS
CMP AL,DH ;MAKE SURE RESULT IS BIGGER
MOV DH,AL ;SAVE THE MASK
JAE SHORT ??L004
JMP SNERR ;DON'T ALLOW TWO OF THE SAME
??L004:
MOV TEMP3,BX ;SAVE CHARACTER POINTER
CALL CHRGTR ;GET THE NEXT CANDIDATE
JMP SHORT LOPREL
;
; FOR EXPONENTIATION WE WANT TO FORCE THE CURRENT VALUE IN THE FAC
; TO BE SINGLE PRECISION. WHEN APPLICATION TIME COMES WE FORCE
; THE RIGHT HAND OPERAND TO SINGLE PRECISION AS WELL
;
EXTRN FPWRQ:NEAR
EXPSTK: CALL FRCSNG ;COERCE LEFT HAND OPERAND
CALL _PUSHF ;PUT IT ON THE STACK
MOV CX,OFFSET FPWRQ ;PLACE TO COERCE RIGHT HAND
;OPERAND AND DO EXPONENTIATION
MOV DH,LOW 127 ;RESTORE THE PRECEDENCE
JMP SHORT FINTMP ;FINISH ENTRY AND EVALUATE MORE FORMULA
;
; FOR "AND" AND "OR" AND "\" AND "MOD" WE WANT TO FORCE THE CURRENT VALUE
; IN THE FAC TO BE AN INTEGER, AND AT APPLICATION TIME FORCE THE RIGHT
; HAND OPERAND TO BE AN INTEGER
;
ANDORD: PUSH DX ;SAVE THE PRECEDENCE
CALL FRCINT
POP DX ;[D]=PRECEDENCE
PUSH BX ;PUSH THE LEFT HAND OPERAND
MOV CX,OFFSET DANDOR ;"AND" AND "OR" DOER
JMP SHORT FINTMP ;PUSH ON THIS ADDRESS,PRECEDENCE
;AND CONTINUE EVALUATION
;
; HERE TO BUILD AN ENTRY FOR A RELATIONAL OPERATOR
; STRINGS ARE TREATED SPECIALLY. NUMERIC COMPARES ARE DIFFERENT
; FROM MOST OPERATOR ENTRIES ONLY IN THE FACT THAT AT THE
; BOTTOM INSTEAD OF HAVING RETAOP, DOCMP AND THE RELATIONAL
; BITS ARE STORED. STRINGS HAVE STRCMP,THE POINTER AT THE STRING DESCRIPTOR,
; DOCMP AND THE RELATIONAL BITS.
;
FINREL: MOV AL,CH ;[A]=OLD PRECEDENCE
CMP AL,LOW 100 ;RELATIONALS HAVE PRECEDENCE 100
JNAE SHORT $+3
RET ;APPLY EARLIER OPERATOR IF IT HAS
;HIGHER PRECEDENCE
PUSH CX ;SAVE THE OLD PRECEDENCE
PUSH DX ;SAVE [D]=RELATIONAL BITS
MOV DX,OFFSET 256*100+OPCNT ;[D]=PRECEDENCE=100
;[E]=DISPATCH OFFSET FOR
;COMPARES IN APPLOP=4
;IN CASE THIS IS A NUMERIC COMPARE
MOV BX,OFFSET DOCMP ;ROUTINE TO TAKE COMPARE ROUTINE RESULT
;AND RELATIONAL BITS AND RETURN THE ANSWER
PUSH BX ;DOES A JMP TO RETAOP WHEN DONE
CALL GETYPR ;SEE IF WE HAVE A NUMERIC COMPARE
JZ SHORT ??L005
JMP NUMREL ;YES, BUILD AN APPLOP ENTRY
??L005:
MOV BX,FACLO ;GET THE POINTER AT THE STRING DESCRIPTOR
PUSH BX ;SAVE IT FOR STRCMP
MOV CX,OFFSET STRCMP ;STRING COMPARE ROUTINE
JMP SHORT FINTMP ;PUSH THE ADDRESS, REGET THE TEXT POINTER
;SAVE THE PRECEDENCE AND SCAN
;MORE OF THE FORMULA
;
; APPLOP IS RETURNED TO WHEN IT IS TIME TO APPLY AN ARITHMETIC
; OR NUMERIC COMPARISON OPERATION.
; THE STACK HAS A DOUBLE BYTE ENTRY WITH THE OPERATOR
; NUMBER AND THE VALTYP OF THE VALUE ON THE STACK.
; APPLOP DECIDES WHAT VALUE LEVEL THE OPERATION
; WILL OCCUR AT, AND CONVERTS THE ARGUMENTS. APPLOP
; USES DIFFERENT CALLING CONVENTIONS FOR EACH VALUE TYPE.
; INTEGERS: LEFT IN [D,E] RIGHT IN [H,L]
; SINGLES: LEFT IN [B,C,D,E] RIGHT IN THE FAC
; DOUBLES: LEFT IN FAC RIGHT IN ARG
;
APPLOP: POP CX ;[B]=STACK OPERAND VALUE TYPE
;[C]=OPERATOR OFFSET
MOV AL,CL ;SAVE IN MEMORY SINCE THE STACK WILL BE BUSY
MOV BYTE PTR OPRTYP,AL ;A RAM LOCATION
MOV AL,BYTE PTR VALTYP ;GET VALTYP OF FAC
CMP AL,CH ;ARE VALTYPES THE SAME?
JNZ SHORT VALNSM ;NO
CMP AL,LOW 2 ;INTEGER?
JZ SHORT INTDPC ;YES, DISPATCH!!
CMP AL,LOW 4 ;SINGLE?
JNZ SHORT ??L006
JMP SNGDPC ;YES, DISPATCH!!
??L006:
JAE SHORT DBLDPC ;MUST BE DOUBLE, DISPATCH!!
VALNSM: MOV DH,AL ;SAVE IN [D]
MOV AL,CH ;CHECK FOR DOUBLE
CMP AL,LOW 8 ;PRECISION ENTRY ON THE STACK
JZ SHORT STKDBL ;FORCE FAC TO DOUBLE
MOV AL,DH ;GET VALTYPE OF FAC
CMP AL,LOW 8 ;AND IF SO, CONVERT THE STACK OPERAND
JZ SHORT FACDBL ;TO DOUBLE PRECISION
MOV AL,CH ;SEE IF THE STACK ENTRY IS SINGLE
CMP AL,LOW 4 ;PRECISION AND IF SO, CONVERT
JZ SHORT STKSNG ;THE FAC TO SINGLE PRECISION
MOV AL,DH ;SEE IF THE FAC IS SINGLE PRECISION
CMP AL,LOW 3 ;AND IF SO CONVERT THE STACK TO SINGLE
JNZ SHORT ??L007
JMP TMERR ;BLOW UP ON RIGHT HAND STRING OPERAND
??L007:
JAE SHORT FACSNG ;PRECISION
;NOTE: THE STACK MUST BE INTEGER AT THIS POINT
INTDPC: MOV BX,OFFSET INTDSP ;INTEGER INTEGER CASE
MOV CH,LOW 0 ;SPECIAL DISPATCH FOR SPEED
ADD BX,CX ;[H,L] POINTS TO THE ADDRESS TO GO TO
ADD BX,CX
INS86 56 ;FETCH FROM CODE SEGMENT
MOV CL,BYTE PTR [BX] ;[B,C]=ROUTINE ADDRESS
INC BX
INS86 56 ;FETCH FROM CODE SEGMENT
MOV CH,BYTE PTR [BX]
POP DX ;[D,E]=LEFT HAND OPERAND
MOV BX,FACLO ;[H,L]=RIGHT HAND OPERAND
PUSH CX ;DISPATCH
RET
;
; THE STACK OPERAND IS DOUBLE PRECISION, SO
; THE FAC MUST BE FORCED TO DOUBLE PRECISION, MOVED INTO ARG
; AND THE STACK VALUE POPED INTO THE FAC
;
STKDBL: CALL FRCDBL ;MAKE THE FAC DOUBLE PRECISION
DBLDPC: CALL VMOVAF ;MOVE THE FAC INTO ARG
POP BX ;POP OFF THE STACK OPERAND INTO THE FAC
MOV DFACLO+2,BX
POP BX
MOV DFACLO,BX ;STORE LOW BYTES AWAY
SNGDBL: POPR ;POP OFF A FOUR BYTE VALUE
CALL MOVFR ;INTO THE FAC
SETDBL: CALL FRCDBL ;MAKE SURE THE LEFT OPERAND IS
;DOUBLE PRECISION
MOV BX,OFFSET DBLDSP ;DISPATCH TO A DOUBLE PRECISION ROUTINE
DODSP: MOV AL,BYTE PTR OPRTYP ;RECALL WHICH OPERAND IT WAS
ROL AL,1 ;CREATE A DISPATCH OFFSET, SINCE
;TABLE ADDRESSES ARE TWO BYTES
ADD AL,BL ;ADD LOW BYTE OF ADDRESS
MOV BL,AL ;SAVE BACK
ADC AL,BH ;ADD HIGH BYTE
SUB AL,BL ;SUBTRACT LOW
MOV BH,AL ;RESULT BACK
INS86 56 ;FETCH FROM CODE SEGMENT
MOV BX,[BX] ;FETCH THE ADDRESS
JMP BX ;AND PERFORM THE OPERATION, RETURNING
;TO RETAOP, EXCEPT FOR COMPARES WHICH
;RETURN TO DOCMP
;
; THE FAC IS DOUBLE PRECISION AND THE STACK IS EITHER
; INTEGER OR SINGLE PRECISION AND MUST BE CONVERTED
;
FACDBL: MOV AL,CH ;GET THE VALUE TYPE INTO [A]
PUSH AX ;SAVE THE STACK VALUE TYPE
CALL VMOVAF ;MOVE THE FAC INTO ARG
POP AX ;POP THE STACK VALUE TYPE INTO [A]
MOV BYTE PTR VALTYP,AL ;PUT IT IN VALTYP FOR THE FORCE
;ROUTINE
CMP AL,LOW 4 ;SEE IF ITS SINGLE, SO WE KNOW
;HOW TO POP THE VALUE OFF
JZ SHORT SNGDBL ;IT'S SINGLE PRECISION
;SO DO A POPR / CALL MOVFR
POP BX ;POP OFF THE INTEGER VALUE
MOV FACLO,BX ;SAVE IT FOR CONVERSION
JMP SHORT SETDBL ;SET IT UP
;
; THIS IS THE CASE WHERE THE STACK IS SINGLE PRECISION
; AND THE FAC IS EITHER SINGLE PRECISION OR INTEGER
;
STKSNG: CALL FRCSNG ;CONVERT THE FAC IF NECESSARY
SNGDPC: POPR ;PUT THE LEFT HAND OPERAND IN THE REGISTERS
SNGDO: MOV BX,OFFSET SNGDSP ;SETUP THE DISPATCH ADDRESS
;FOR THE SINGLE PRECISION OPERATOR ROUTINES
JMP SHORT DODSP ;DISPATCH
;
; THIS IS THE CASE WHERE THE FAC IS SINGLE PRECISION AND THE STACK
; IS AN INTEGER.
;
FACSNG: POP BX ;POP OFF THE INTEGER ON THE STACK
CALL _PUSHF ;SAVE THE FAC ON THE STACK
CALL CONSIH ;CONVERT [H,L] TO A SINGLE PRECISION
;NUMBER IN THE FAC
CALL MOVRF ;PUT THE LEFT HAND OPERAND IN THE REGISTERS
POP BX ;RESTORE THE FAC
MOV FAC-1,BX ;FROM THE STACK
POP BX
MOV FACLO,BX
JMP SHORT SNGDO ;PERFORM THE OPERATION
;
; HERE TO DO INTEGER DIVISION. SINCE WE WANT 1/3 TO BE
; .333333 AND NOT ZERO WE HAVE TO FORCE BOTH ARGUMENTS
; TO BE SINGLE-PRECISION FLOATING POINT NUMBERS
; AND USE FDIV
;
PUBLIC INTDIV
INTDIV: PUSH BX ;SAVE THE RIGHT HAND ARGUMENT
XCHG BX,DX ;[H,L]=LEFT HAND ARGUMENT
CALL CONSIH ;CONVERT [H,L] TO A SINGLE-PRECISION
;NUMBER IN THE FAC
POP BX ;GET BACK THE RIGHT HAND ARGUMENT
CALL _PUSHF ;PUSH THE CONVERTED LEFT HAND ARGUMENT
;ONTO THE STACK
CALL CONSIH ;CONVERT THE RIGHT HAND ARGUMENT TO A
;SINGLE PRECISION NUMBER IN THE FAC
JMP FDIVT
;REGISTERS THE LEFT HAND ARGUMENT
PAGE
SUBTTL EVAL - EVALUATE VARIABLE, CONSTANT, FUNCTION CALL
PUBLIC EVAL
EVAL:
CALL CHRGTR
JNZ SHORT ??L008
JMP MOERR ;TEST FOR MISSING OPERAND - IF NONE GIVE ERROR
??L008:
JAE SHORT ??L009
JMP FIN ;IF NUMERIC, INTERPRET CONSTANT
??L009:
CALL ISLET2 ;VARIABLE NAME?
JNAE SHORT ??L010
JMP ISVAR ;AN ALPHABETIC CHARACTER MEANS YES
??L010:
CMP AL,LOW OFFSET DBLCON+1 ;IS IT AN EMBEDED CONSTANT
JAE SHORT ??L011
JMP CONFAC ;RESCAN THE TOKEN & RESTORE OLD TEXT PTR
??L011:
EXTRN EVALX:NEAR
CALL EVALX ;Handle extended functions.
INC AL ;IS IT A FUNCTION CALL (PRECEDED BY 377)
JNZ SHORT ??L012
JMP ISFUN ;YES, DO IT
??L012:
DEC AL ;FIX A BACK
CMP AL,LOW OFFSET PLUSTK ;IGNORE "+"
JZ SHORT EVAL
CMP AL,LOW OFFSET MINUTK ;NEGATION?
JNZ SHORT ??L013
JMP DOMIN
??L013:
CMP AL,LOW 34 ;STRING CONSTANT?
JNZ SHORT ??L014
JMP STRLTI ;IF SO BUILD A DESCRIPTOR IN A TEMPORARY
??L014:
;DESCRIPTOR LOCATION AND PUT A POINTER TO THE
;DESCRIPTOR IN FACLO.
CMP AL,LOW OFFSET NOTTK ;CHECK FOR "NOT" OPERATOR
JNZ SHORT ??L015
JMP NOTER
??L015:
CMP AL,LOW "&" ;OCTAL CONSTANT?
JNZ SHORT ??L016
JMP OCTCNS
??L016:
CMP AL,LOW OFFSET ERCTK
JNZ SHORT NTERC ;NO, TRY OTHER POSSIBILITIES
CALL CHRGTR ;GRAB FOLLOWING CHAR
MOV AL,BYTE PTR ERRFLG ;GET THE ERROR CODE.
NTDERC: PUSH BX ;SAVE TEXT POINTER
CALL SNGFLT ;RETURN THE VALUE
POP BX ;RESTORE TEXT POINTER
RET ;ALL DONE.
NTERC: CMP AL,LOW OFFSET ERLTK ;ERROR LINE NUMBER VARIABLE.
JNZ SHORT NTERL ;NO, TRY MORE THINGS.
CALL CHRGTR ;GET FOLLOWING CHARACTER
PUSH BX ;SAVE TEXT POINTER
MOV BX,ERRLIN ;GET THE OFFENDING LINE #
CALL INEG2 ;FLOAT 2 BYTE UNSINGED INT
POP BX ;RESTORE TEXT POINTER
RET ;RETURN
NTERL:
CMP AL,LOW OFFSET $VARPTR ;VARPTR CALL?
JNZ SHORT NTVARP ;NO
CALL CHRGTR ;EAT CHAR AFTER
EXTRN VARPT2:NEAR
CMP AL,LOW "$"
JNZ SHORT ??L017
JMP VARPT2 ;branch if VARPTR$(x)
??L017:
CALL SYNCHR
DB OFFSET "(" ;EAT LEFT PAREN
EXTRN GETPTR:NEAR
CMP AL,LOW "#" ;WANT POINTER TO FILE?
JNZ SHORT NVRFIL ;NO, MUST BE VARIABLE
CALL GTBYTC ;READ FILE #
PUSH BX ;SAVE TEXT PTR
CALL GETPTR ;GET PTR TO FILE
POP BX ;RESTORE TEXT PTR
JMP VARRET
NVRFIL:
EXTRN PTRGTN:NEAR
CALL PTRGTN ;GET ADDRESS OF VARIABLE
VARRET: CALL SYNCHR
DB OFFSET ")" ;EAT RIGHT PAREN
PUSH BX ;SAVE TEXT POINTER
XCHG BX,DX ;GET VALUE TO RETURN IN [H,L]
OR BX,BX ;MAKE SURE NOT UNDEFINED VAR
;SET CC'S. ZERO IF UNDEF
JNZ SHORT ??L018
JMP FCERR ;ALL OVER IF UNDEF (DONT WANT
??L018:
;USER POKING INTO ZERO IF HE'S
;TOO LAZY TO CHECK
CALL MAKINT ;MAKE IT AN INT
POP BX ;RESTORE TEXT POINTER
RET
NTVARP:
CMP AL,LOW OFFSET USRTK ;USER ASSEMBLY LANGUAGE ROUTINE??
JNZ SHORT ??L019
JMP USRFN ;GO HANDLE IT
??L019:
CMP AL,LOW OFFSET INSRTK ;IS IT THE INSTR FUNCTION??
JNZ SHORT ??L020
JMP _INSTR ;DISPATCH
??L020:
CMP AL,LOW OFFSET $SCREEN
JNZ SHORT ??L021
EXTRN SCRENF:NEAR
JMP SCRENF
??L021:
CMP AL,LOW OFFSET $POINT
JNZ SHORT ??L022
EXTRN POINT:NEAR
JMP POINT
??L022:
EXTRN INKEY:NEAR
CMP AL,LOW OFFSET $INKEY$ ;INKEY$ FUNCTION?
JNZ SHORT ??L023
JMP INKEY
??L023:
CMP AL,LOW OFFSET $STRING$ ;STRING FUNCTION?
JNZ SHORT ??L024
JMP STRNG$ ;YES, GO DO IT
??L024:
EXTRN FIXINP:NEAR
CMP AL,LOW OFFSET $INPUT ;FIXED LENGTH INPUT?
JNZ SHORT ??L025
JMP FIXINP ;YES
??L025:
CMP AL,LOW OFFSET CLINTK ;WANT TO KNOW CURRENT LINE ON SCREEN?
JNZ SHORT ??L026
EXTRN GETLIN:NEAR
JMP GETLIN ;YES
??L026:
CMP AL,LOW OFFSET FNTK ;USER-DEFINED FUNCTION?
JNZ SHORT ??L027
JMP FNDOER
??L027:
;
; ONLY POSSIBILITY LEFT IS A FORMULA IN PARENTHESES
;
PUBLIC PARCHK
PARCHK: CALL FRMPRN ;RECURSIVELY EVALUATE THE FORMULA
CALL SYNCHR
DB OFFSET ")"
RET
DOMIN:
MOV DH,LOW 125 ;A PRECEDENCE BELOW ^
;BUT ABOVE ALL ELSE
CALL LPOPER ;SO ^ GREATER THAN UNARY MINUS
MOV BX,TEMP2 ;GET TEXT POINTER
PUSH BX
CALL VNEG
LABBCK: ;FUNCTIONS THAT DON'T RETURN
;STRING VALUES COME BACK HERE
POP BX
RET
PUBLIC ISVAR
ISVAR: CALL PTRGET ;GET A POINTER TO THE
;VARIABLE IN [D,E]
PUBLIC RETVAR
RETVAR: PUSH BX ;SAVE THE TEXT POINTER
XCHG BX,DX ;PUT THE POINTER TO THE VARIABLE VALUE
;INTO [H,L]. IN THE CASE OF A STRING
;THIS IS A POINTER TO A DESCRIPTOR AND NOT
;AN ACTUAL VALUE
MOV FACLO,BX ;IN CASE IT'S STRING STORE THE POINTER
;TO THE DESCRIPTOR IN FACLO.
CALL GETYPR ;FOR STRINGS WE JUST LEAVE
JZ SHORT ??L028
CALL VMOVFM ;A POINTER IN THE FAC
??L028:
;THE FAC USING [H,L] AS THE POINTER.
POP BX ;RESTORE THE TEXT POINTER
RET
PUBLIC MAKUPL
MAKUPL: MOV AL,BYTE PTR [BX] ;GET CHAR FROM MEMORY
PUBLIC MAKUPS
MAKUPS: CMP AL,LOW OFFSET "A"+40O ;IS IT LOWER CASE RANGE
JNB SHORT $+3
RET ;LESS
CMP AL,LOW OFFSET "Z"+41O ;GREATER
JNAE SHORT $+3
RET ;TEST
AND AL,LOW 137O ;MAKE UPPER CASE
RET ;DONE
PUBLIC CNSGET
CNSGET:
CMP AL,LOW "&" ;OCTAL PERHAPS?
JZ SHORT ??L029
JMP LINGET
??L029:
PUBLIC $OHCNS
$OHCNS:
PUBLIC OCTCNS
OCTCNS: MOV DX,0 ;INITIALIZE TO ZERO AND IGNORE OVERFLOW
CALL CHRGTR ;GET FIRST CHAR
CALL MAKUPS ;MAKE UPPER IF NESC.
CMP AL,LOW "O" ;OCTAL?
JZ SHORT LOPOCT ;IF SO, DO IT
CMP AL,LOW "H" ;HEX?
JNZ SHORT LOPOC2 ;THEN DO IT
MOV CH,LOW 5 ;INIT DIGIT COUNT
LOPHEX: INC BX ;BUMP POINTER
MOV AL,BYTE PTR [BX] ;GET CHAR
CALL MAKUPS ;MAKE UPPER CASE
CALL ISLET2 ;FETCH CHAR, SEE IF ALPHA
XCHG BX,DX ;SAVE [H,L]
JAE SHORT ALPTST ;YES, MAKE SURE LEGAL HEC
CMP AL,LOW OFFSET "9"+1 ;IS IT BIGGER THAN LARGEST DIGIT?
JAE SHORT OCTFIN ;YES, BE FORGIVING & RETURN
SUB AL,LOW "0" ;CONVERT DIGIT, MAKE BINARY
JB SHORT OCTFIN ;BE FORGIVING IF NOT HEX DIGIT
JMP SHORT NXTHEX ;ADD IN OFFSET
ALPTST: CMP AL,LOW OFFSET "F"+1 ;IS IT LEGAL HEX?
JAE SHORT HEXFIN ;YES, TERMINATE
SUB AL,LOW OFFSET "A"-10 ;MAKE BINARY VALUE
NXTHEX: ADD BX,BX ;SHIFT RIGHT FOUR BITS
ADD BX,BX
ADD BX,BX
ADD BX,BX
OR AL,BL ;OR ON NEW DIGIT
MOV BL,AL ;SAVE BACK
XCHG BX,DX ;GET TEXT POINTER BACK IN [H,L]
DEC CH
JNZ SHORT LOPHEX ;KEEP EATING IF NOT TOO MANY DIGITS
;IF NOT INPUT STATEMENT GOTO OVFLW ERROR FROM HERE, ELSE PASS BACK ERROR
CKOVER: MOV AL,BYTE PTR FLGSCN
OR AL,AL
JNZ SHORT ??L030
JMP OVERR ;IF NOT INPUT STATEMENT, THIS IS ERROR
??L030:
PUSH BX
MOV BX,OFFSET $OVMSG
CALL $STPRN ;PRINT OVERFLOW MESSAGE
CALL CRDO
POP BX
CONER2: MOV AL,BYTE PTR FLGOVC
INC AL
MOV BYTE PTR FLGOVC,AL ;TELL INPUT CODE THAT ERROR OCCURED
RET
CONERR: MOV AL,BYTE PTR FLGSCN
OR AL,AL
JZ SHORT ??L031
JMP CONER2 ;IF INPUT CODE ERROR, RETURN ERROR CODE
??L031:
JMP SNERR ;ELSE GOTO ERROR FROM HERE
LOPOC2: DEC BX ;REGET LAST CHARACTER
LOPOCT: CALL CHRGTR ;READ A DIGIT
XCHG BX,DX ;RESULT INTO [H,L]
JAE SHORT OCTFIN ;OUT OF DIGITS MEANS DONE
CMP AL,LOW "8" ;IS THIS AN OCTAL DIGIT
JNAE SHORT ??L032
JMP CONERR ;NO, TOO BAD YOU WILL LOSE
??L032:
MOV CX,OFFSET CKOVER ;WHERE TO GO ON OVERFLOW ERROR
PUSH CX ;SAVE ADDR ON STACK
ADD BX,BX ;MULTIPLY BY EIGHT
JNB SHORT $+3
RET ;OVERFLOW ERROR
ADD BX,BX
JNB SHORT $+3
RET ;OVERFLOW ERROR
ADD BX,BX
JNB SHORT $+3
RET ;OVERFLOW ERROR
POP CX ;GET RID OF OVERR ADDR
MOV CH,LOW 0 ;SETUP TO ADD [B,C]
SUB AL,LOW "0"
MOV CL,AL
ADD BX,CX ;ADD IN THE DIGIT
XCHG BX,DX ;PUT TEXT POINTER BACK IN [H,L]
JMP SHORT LOPOCT ;SCAN MORE DIGITS
HEXFIN:
OCTFIN:
PUBLIC HOCFIN
HOCFIN:
CALL MAKINT ;SAVE AS AN INTEGER
XCHG BX,DX ;[H,L]-TEXT POINTER
RET
ISFUN:
INC BX ;BUMP SOURCE TEXT POINTER
MOV AL,BYTE PTR [BX] ;GET THE ACTUAL TOKEN FOR FN
SUB AL,LOW OFFSET ONEFUN ;MAKE INTO OFFSET
EXTRN RNDMON:NEAR
EXTRN $RNDFN:NEAR
CMP AL,LOW OFFSET $RNDFN ;IS IT RND?
JNZ SHORT NTMRND ;IF NOT NO NEED TO CHECK MONADIC
PUSH BX ;SAVE TEXT POINTER
CALL CHRGTR ;SEE IF NEXT CHAR IS "("
CMP AL,LOW "("
POP BX ;GET BACK THE OLD TEXT POINTER
JZ SHORT ??L033
JMP RNDMON ;HANDLE MONADIC CASE
??L033:
MOV AL,LOW OFFSET $RNDFN
NTMRND:
MOV CH,LOW 0
ROL AL,1 ;MULTIPLY BY 2
MOV CL,AL
PUSH CX ;SAVE THE FUNCTION # ON THE STACK
CALL CHRGTR
MOV AL,CL ;LOOK AT FUNCTION #
EXTRN NUMGFN:NEAR
CMP AL,LOW OFFSET NUMGFN ;IS IT PAST LASNUM?
JAE SHORT OKNORM ;NO, MUST BE A NORMAL FUNCTION
;
; MOST FUNCTIONS TAKE A SINGLE ARGUMENT.
; THE RETURN ADDRESS OF THESE FUNCTIONS IS A SMALL ROUTINE
; THAT CHECKS TO MAKE SURE VALTYP IS 0 (NUMERIC) AND POPS OFF
; THE TEXT POINTER. SO NORMAL FUNCTIONS THAT RETURN STRING RESULTS (I.E. CHR$)
; MUST POP OFF THE RETURN ADDRESS OF LABBCK, AND POP OFF THE
; TEXT POINTER AND THEN RETURN TO FRMEVL.
;
; THE SO CALLED "FUNNY" FUNCTIONS CAN TAKE MORE THAN ONE ARGUMENT.
; THE FIRST OF WHICH MUST BE STRING AND THE SECOND OF WHICH
; MUST BE A NUMBER BETWEEN 0 AND 256. THE TEXT POINTER IS
; PASSED TO THESE FUNCTIONS SO ADDITIONAL ARGUMENTS
; CAN BE READ. THE TEXT POINTER IS PASSED IN [D,E].
; THE CLOSE PARENTHESIS MUST BE CHECKED AND RETURN IS DIRECTLY
; TO FRMEVL WITH [H,L] SETUP AS THE TEXT POINTER POINTING BEYOND THE ")".
; THE POINTER TO THE DESCRIPTOR OF THE STRING ARGUMENT
; IS STORED ON THE STACK UNDERNEATH THE VALUE OF THE INTEGER
; ARGUMENT (2 BYTES)
;
; FIRST ARGUMENT ALWAYS STRING -- SECOND INTEGER
;
CALL FRMPRN ;EAT OPEN PAREN AND FIRST ARG
CALL SYNCHR
DB OFFSET 44 ;TWO ARGS SO COMMA MUST DELIMIT
CALL CHKSTR ;MAKE SURE THE FIRST ONE WAS STRING
XCHG BX,DX ;[D,E]=TXTPTR
MOV BX,FACLO ;GET PTR AT STRING DESCRIPTOR
POP SI ;XTHL
XCHG SI,BX
PUSH SI ;GET FUNCTION #
;SAVE THE STRING PTR
PUSH BX ;PUT THE FUNCTION # ON
XCHG BX,DX ;[H,L]=TXTPTR
CALL GETBYT ;[E]=VALUE OF FORMULA
XCHG BX,DX ;TEXT POINTER INTO [D,E]
;[H,L]=INT VALUE OF SECOND ARGUMENT
POP SI ;XTHL
XCHG SI,BX
PUSH SI ;SAVE INT VALUE OF SECOND ARG
;[H,L]=FUNCTION NUMBER
JMP SHORT FINGO ;DISPATCH TO FUNCTION
OKNORM:
CALL PARCHK ;CHECK OUT THE ARGUMENT
;AND MAKE SURE ITS FOLLOWED BY ")"
POP SI ;XTHL
XCHG SI,BX
PUSH SI ;[H,L]=FUNCTION # AND SAVE TEXT POINTER
;
; CHECK IF SPECIAL COERCION MUST BE DONE FOR ONE OF THE TRANSCENDENTAL
; FUNCTIONS (RND, SQR, COS, SIN, TAN, ATN, LOG, AND EXP)
; THESE FUNCTIONS DO NOT LOOK AT VALTYP, BUT RATHER ASSUME THE
; ARGUMENT PASSED IN THE FAC IS SINGLE PRECISION, SO FRCSNG
; MUST BE CALLED BEFORE DISPATCHING TO THEM.
;
MOV AL,BL ;[A]=FUNCTION NUMBER
EXTRN BOTCON:NEAR,TOPCON:NEAR
CMP AL,LOW OFFSET BOTCON ;LESS THAN SQUARE ROOT?
JB SHORT NOTFRF ;DON'T FORCE THE ARGUMENT
CMP AL,LOW OFFSET TOPCON ;BIGGER THAN ARC-TANGENT?
PUSH BX ;SAVE THE FUNCTION NUMBER
JNB SHORT ??L034
CALL FRCSNG ;IF NOT, FORCE FAC TO SINGLE-PRECISION
??L034:
POP BX ;RESTORE THE FUNCTION NUMBER
NOTFRF:
MOV DX,OFFSET LABBCK ;RETURN ADDRESS
PUSH DX ;MAKE THEM REALLY COME BACK
MOV AL,LOW 1 ;FUNCTION SHOULD ONLY PRINT OVERFLOW ONCE
MOV BYTE PTR FLGOVC,AL
FINGO:
MOV CX,OFFSET FUNDSP ;FUNCTION DISPATCH TABLE
DISPAT: ADD BX,CX ;ADD ON THE OFFSET
INS86 56 ;FETCH FROM CODE SEGMENT
INS86 377,047 ;JMPI 0(.BX)
; THE FOLOWING ROUTINE IS CALLED FROM FIN IN F4
; TO SCAN LEADING SIGNS FOR NUMBERS. IT WAS MOVED