-
Notifications
You must be signed in to change notification settings - Fork 1
/
toyg.bas
1957 lines (1729 loc) · 62.4 KB
/
toyg.bas
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
' Toy GUI version for FreeBASIC, floating point, includes math functions.
' by Ed_Davis - 2004 - 2019
' GUI functions taken from awin by Aurel.
'
' This is based on my Visual Basic Script version of Toy - circa 2004
' Which is in turn based on my C version of Toy - circa 2003
' There are also versions for Euphoria, BCX and Pascal
'------------------------------------------------------------------------
' fbc -s gui toyg.bas
'------------------------------------------------------------------------
#define WIN_INCLUDEALL
#include once "windows.bi"
dim shared frontColor as long
dim shared backColor as long
dim shared ghwnd as HWND
declare sub FillSolidRect(wID as HWND, x As integer, Y As integer, cx As integer, cy As integer, bbColor as integer)
function file_getname( byval hWnd as HWND ) as string
''fill structure for dialog box
dim ofn as OPENFILENAME
dim filename as zstring * MAX_PATH+1
with ofn
.lStructSize = sizeof( OPENFILENAME )
.hwndOwner = hWnd
.hInstance = GetModuleHandle( NULL )
.lpstrFilter = strptr( !"All Files, (*.*)\0*.*\0Bas Files, (*.BAS)\0*.bas\0\0" )
.lpstrCustomFilter = NULL
.nMaxCustFilter = 0
.nFilterIndex = 1
.lpstrFile = @filename
.nMaxFile = sizeof( filename )
.lpstrFileTitle = NULL
.nMaxFileTitle = 0
.lpstrInitialDir = NULL
.lpstrTitle = @"File Open Test"
.Flags = OFN_EXPLORER or OFN_FILEMUSTEXIST or OFN_PATHMUSTEXIST
.nFileOffset = 0
.nFileExtension = 0
.lpstrDefExt = NULL
.lCustData = 0
.lpfnHook = NULL
.lpTemplateName = NULL
end with
''call open file dialog, return empty string if no file selected, else return file name
if( GetOpenFileName( @ofn ) = FALSE ) then
return ""
else
return filename
end if
end function
sub GetSize(hnd as HWND, hndx as integer, hndy as integer, hndw as integer, hndh as integer)
dim rc As RECT
GetClientRect(hnd, @rc)
'hndx=0:hndy=0:hndw=0:hndh=0
hndx = rc.left
hndy = rc.top
hndw = rc.right
hndh = rc.bottom
end sub
'====================================================================================
sub text_out(wnd as HWND, x as integer, y as integer, txt as string)
dim hdc as HDC
hdc=GetDC(wnd)
TextOut hdc, x, y, txt, Len(txt)
ReleaseDC(wnd, Hdc)
end sub
'====================================================================================
sub xPset(wnd as HWND, x as integer, y as integer, c as integer)
dim hdc as HDC
hdc = GetDC(wnd)
SetPixel(hdc, x, y, c)
ReleaseDC(wnd,Hdc)
end sub
'=================================================
sub DrawLine (wID as HWND,byval x as integer,byval y as integer,byval x1 as integer,byval y1 as integer)
dim hdc as HDC
hdc = GetDC(wID)
'GetSize(wID,0,0,ww,hh)
'SelectObject(hdc, CreatePen(PS_SOLID,1,fColor))
dim as HPEN np = CreatePen(PS_SOLID,1,frontColor)
dim as HGDIOBJ op = SelectObject(hdc, np)
MoveToEx hdc,x,y,Byval 0
LineTo hdc,x1,y1
'BitBlt(hDCmem, 0, 0, ww, hh, hdc, 0, 0, SRCCOPY)
DeleteObject(SelectObject(hdc, op))
ReleaseDC( wID, hdc)
end sub
'-----------------------------------------------------------
sub SetFrontColor (wID as HWND, penr as integer, peng as integer, penb as integer)
dim hdc as HDC
'integer ww,hh : GetSize(wID,0,0,ww,hh)
hdc = GetDC(wID)
frontColor = RGB (penr,peng,penb)
SetTextColor( hDC, frontColor)
SetBkColor( hDC, backColor)
'int np = CreatePen(PS_SOLID,1,frontColor) 'new Pen color
'int op = SelectObject(hdc, np)
'DeleteObject(SelectObject(hdc, op))
ReleaseDC( wID, hdc)
end sub
'-----------------------------------------------------------
' set window color
sub SetWindowColor(wID as HWND,wr as integer,wg as integer,wb as integer)
dim backColor as long
dim ww as integer: dim hh as integer : GetSize(wID,0,0,ww,hh)
backColor = RGB (wr,wg,wb)
FillSolidRect(wID,0,0,ww,hh,backColor)
end sub
'====================================================================================
sub FillSolidRect(wID as HWND, x As integer, Y As integer, cx As integer, cy As integer, bbColor as integer)
dim hdc as HDC
dim hBr as HBRUSH
dim oBr as HBRUSH
dim rc As RECT
hDC=GetDC(wID)
rc.Left = x
rc.Top = Y
rc.right = x + cx
rc.bottom = Y + cy
hBr = CreateSolidBrush(bbColor)
'oBr = SelectObject hdc,hBr
FillRect hDC, @rc, hBr
DeleteObject hBr
'BitBlt(hDCmem, 0, 0, ww, hh, hdc, 0, 0, SRCCOPY)
'DeleteObject(SelectObject(hdc, oBr))
ReleaseDC( wID, hdc)
end sub
'====================================================================================
sub DrawCircle (wID as HWND, cix as integer,ciy as integer,cra as integer)
dim hdc as HDC
hdc = GetDC(wID)
'backColor=rgb(200,200,0) ' for test predefined color / yellow
'SetBkMode( hDC, 1) 'transparent
'SetBkColor(hDC, backColor)
dim as HPEN np = CreatePen(PS_SOLID,1,frontColor) 'new pen with predefined color / red
dim as HGDIOBJ op = SelectObject(hdc, np)
dim as HBRUSH nB = CreateSolidBrush(backColor) 'new Brush
dim as HGDIOBJ oB = SelectObject(hdc, nB)
Ellipse hdc,cix-cra,ciy-cra,cra+cix,cra+ciy
'BitBlt(hDCmem, 0, 0, ww, hh, hdc, 0, 0, SRCCOPY) - not used yet
DeleteObject(SelectObject(hdc, op))
DeleteObject(SelectObject(hdc, oB))
ReleaseDC( wID, hdc)
end sub
'====================================================================================
sub DrawRectangle (wID as HWND,rx1 as integer, ry1 as integer, rx2 as integer, ry2 as integer)
dim hdc as HDC
hdc = GetDC(wID)
'GetSize(wID,0,0,ww,hh)
'SetBkMode( hDC, 1) 'transparent
'SetBkColor(hDC, RGB(220,220,250))
dim as HPEN np = CreatePen(PS_SOLID,1,frontColor) 'new pen
dim as HGDIOBJ op = SelectObject(hdc, np)
dim as HBRUSH nB = CreateSolidBrush( backColor) 'new Brush
dim as HGDIOBJ oB = SelectObject(hdc, nB)
'Rectangle bHdc,x,y,w+x,h+y ...hmmm
Rectangle (hdc,rx1,ry1,rx2+rx1,ry2+ry1)
'BitBlt(hDCmem, 0, 0, ww, hh, hdc, 0, 0, SRCCOPY)
DeleteObject(SelectObject(hdc, op))
DeleteObject(SelectObject(hdc, oB))
ReleaseDC( wID, hdc)
end sub
'===========================================================================================
'===========================================================================================
'===========================================================================================
'toy+ - GUI version, floating point, includes math functions.
'by Ed_Davis - 2019
'above GUI functions taken from awin by Aurel.
'
' Grammar:
'pgm = [subs|functions] stmt_seq [subs|functions] .
'sub = "sub" ident optional_parms stmt_seq "end sub" .
'subs = sub {sub} .
'function = "function" ident optional_parms stmt_seq "end function" .
'functions = function {function} .
'optional_parms = ["(" [float ident {"," ident}] ")"] .
'stmt_seq = {print_stmt | halt_stmt | while_stmt | assign | if_stmt | for_stmt | decl | return_stmt | call_stmt} .
'decl = "float" ident {"," ident} .
'print_stmt = "print" (string | expr) {, (string | expr) } .
'halt_stmt = "halt" .
'while_stmt = "while" expr stmt_seq "wend" .
'for_stmt = "for" ident = expr1 to expr2 [step expr3] stmt_seq next.
'assign = ident "=" expr .
'if_stmt = "if" expr "then" stmt_seq {"elseif" expr "then" stmt_seq} ["else" stmt_seq] "end if" .
'return_stmt = "return" [expr]
'call_stmt = "call" ident optional_args
'optional_args = ["(" [expr {"," expr}] ")"] .
'exp = orexp .
'orexp = andexp {"or" andexp} .
'andexp = eqlexp {"and" eqlexp} .
'eqlexp = relexp {eqlop relexp} .
'relexp = addexp {relop addexp} .
'addexp = mulexp {addop mulexp} .
'mulexp = factor {mulop factor} .
'factor = '(' exp ')' | number | ident | fun([parms]) .
'unary_exp = "not" | "-" .
'eqlop = "=" | "<>"
'relop = "<" | "<=" | ">" | ">="
'addop = "+" | "-"
'mulop = "*" | "/" | "mod" | "\" (integer division) .
'
'Comments are denoted by the single quote, and extend until the end-of-line
'
'Math-functions ->cos(n),sin(n),tan(n),sqr(n),log(n),rnd(n),rand(n),int(n),abs(n),atn(n),rgb(r,g,b)
'
' example program - find primes:
'
' primes(100)
'
' sub primes(float lim)
' float n, k, p
' n = 1
' while n < lim
' k = 3
' p = 1
' n = n + 2
' while k * k <= n and p
' p = n \ k * k <> n
' k = k + 2
' wend
' if p then
' print n, " is prime"
' end if
' wend
' end sub
'
' example program - fibonacci numbers
'
' print fib(10)
'
' function fib(float n)
' if n < 2 then
' return n
' end if
'
' return fib(n - 1) + fib(n - 2)
' end function
'
'
' example program - towers of Hanoi
'
' float FROM_PEG, TO_PEG, USING
' FROM_PEG = 1
' TO_PEG = 3
' USING = 2
'
' hanoi(6, FROM_PEG, TO_PEG, USING, 0)
'
' sub hanoi(float n, from_peg, to_peg, using, level)
' level = level + 1
' if n > 0 then
' hanoi(n - 1, from_peg, using, to_peg, level)
' print "move ", from_peg, " --> ", to_peg, " at level ", level
' hanoi(n - 1, using, to_peg, from_peg, level)
' end if
' level = level - 1
' end sub
'
const DOUBLE_QUOTE as string = chr(34), SINGLE_QUOTE as string = chr(39)
' variables for the lexer
dim shared cur_line as string ' text of current line
dim shared as string cur_ch ' the current character
dim shared as long sym ' the current symbol (keyword, operator, etc)
dim shared as string token ' text version of current symbol
dim shared as long cur_col
dim shared as long cur_line_num
dim shared as long error_line
dim shared as long error_col
type Key_words
keyword as string
sym as long
end type
const as long MAX_KEYWORDS = 33, MAX_GSYMTAB = 300, MAX_LSYMTAB = 100, MAX_CODE = 4000, _
MAX_STACK = 28000, MAX_CNT_STR = 200, MAX_PENDING = 100
dim shared key_words_tab(MAX_KEYWORDS) as Key_words
' symbol table - all program identifiers stored here
type Symbol_table
ident as string
data_offset as long
id_type as long
value as double ' primary datatype
nargs as long
end type
' list of pending (undeclared) functions
type Pending_list
name as string
offset as long
nargs as long ' actual number of arguments in this call
end type
dim shared g_sym_tab(MAX_GSYMTAB) as Symbol_table ' all global symbols
dim shared l_sym_tab(MAX_LSYMTAB) as Symbol_table ' all local symbols
dim shared as long g_sym_tab_used, l_sym_tab_used ' highest used index
dim shared as long g_data_offset, l_data_offset ' highest used data offset - symbol table version
dim shared pending_list(MAX_PENDING) as Pending_list ' sub fixups that need to be applied
dim shared as long pending_list_used ' highest used entry
' Virtual Machine
dim shared as long code_index ' highest used code position
dim shared as long last_label ' last label target
dim shared as long code_start ' first instruction index
dim shared as long g_data_size, l_data_size ' highest used data entry - VM version
dim shared as long code_arr(MAX_CODE) ' code store
dim shared as string string_pool(MAX_CNT_STR)
dim shared as long max_str_pool_used
' Parser
dim shared as long current_scope ' either global or local
dim shared as long is_function ' processing a function - as opposed to a sub
dim shared as long g_nargs ' number of arguments for current sub/function
dim shared as long last_opcode
' Equates for the symbol type, e.g. what type of symbol have we just read
' the lexer sets variable sym to one of these
enum Symbol
sym_unknown ' 0
sym_eoi ' 1
sym_string_const ' 2
sym_lparen ' 3
sym_rparen ' 4
sym_comma ' 5
sym_real_const ' 6
sym_integer_const ' 7
sym_ident ' 8
sym_print ' 9
sym_while '10
sym_wend '11
sym_end '12
sym_halt '13
sym_if '14
sym_then '15
sym_else '16
sym_elseif '17
sym_for '18
sym_to '19
sym_step '20
sym_next '21
sym_float_var '22
sym_whtspc '23
sym_sub '24
sym_call '25
sym_function '26
sym_return '27
sym_exponent 'new '28
sym_neg '29
sym_multiply '30
sym_divide '31
sym_int_div '32
sym_mod '33
sym_plus '34
sym_minus '35
sym_equal '36
sym_neq '37
sym_lss '38
sym_leq '39
sym_gtr '40
sym_geq '41
sym_not '42
sym_and '43
sym_or '44
sym_eqv 'new '45
sym_imp 'new '46
sym_xor 'new '47
sym_exit 'new '48
sym_pset '49
sym_prtc '50
sym_wcolor '51
sym_circle '52
sym_frontpen '53
sym_line '54
sym_rectangle '55
end enum
const as long left_assoc = 1, right_assoc = 0
' Instructions for the virtual machine
enum Instruction
op_push_int
op_load_int_var
op_stor
op_add
op_sub
op_mul
op_div
op_mod
op_lss
op_leq
op_gtr
op_geq
op_equal
op_neq
op_jz
op_jmp
op_neg
op_not
op_and
op_or
op_prt_int
op_prt_ini
op_prt_str
op_prt_fin
op_prtc
op_halt
op_int_div
op_math_fun
op_call
op_ret
op_enter
op_retf
op_pop
op_pow 'new
op_eqv 'new
op_imp 'new
op_xor 'new
op_load_int_var_l
op_load_int_var_g
op_stor_l
op_stor_g
op_pset
op_rgb
op_wcolor
op_circle
op_frontpen
op_line
op_rectangle
end enum
enum math_functions
fun_abs ' 0
fun_acos 'new 1
fun_asin 'new 2
fun_atn ' 3
fun_cos ' 4
fun_exp 'new 5
fun_fix 'new 6
fun_frac 'new 7
fun_int ' 8
fun_log ' 9
fun_rand ' 10
fun_rnd ' 11
fun_sgn 'new 12
fun_sin ' 13
fun_sqr ' 14
fun_tan ' 15
fun_atan2 'new 16
fun_rgb 'new 17
end enum
const as long type_var = 1
const as long type_const_float = 2
const as long type_sub = 3
const as long type_function = 4
const as long global_scope = 1
const as long local_scope = 2
declare function getcmd(st as string) as string
declare sub init_lex(filename as string)
declare sub next_char() ' get the next char
declare sub skip_white_space()
declare sub skip_comment()
declare sub next_sym() ' determine the next symbol
declare function get_string() as long
declare sub get_digits()
declare sub get_ident()
declare function search_key_words() as long
declare sub init_pending_list()
declare function lookup_pending(s as string) as long
declare sub install_pending(s as string, offset as long, nargs as long)
declare sub init_g_sym_tab()
declare sub init_l_sym_tab()
declare function get_data_size() as long
declare function find_sym_tab(ident as string, byref address as long, byref extent as long, byref id_type as long) as long
declare sub insert_sym_tab(the_type as long)
declare sub insert_sym_tab_var(extent as long)
declare sub insert_sym_tab_double()
declare sub insert_sym_tab_sub()
declare sub insert_sym_tab_fun()
declare function is_in_sym_tab(byref address as long, byref extent as long, byref id_type as long) as long
declare sub init_code()
declare sub set_data_size(size_to_set as long)
declare function get_cur_loc() as long
declare sub emit_at(location as long, operand as long)
declare sub emitx(x as long)
declare function emit1(opcode as long) as long
declare function emit2(opcode as long, operand as long) as long
declare function emit3(opcode as long, operand1 as long, operand2 as long) as long
declare sub patch_jmp_to_current(fix_addr as long)
declare sub interpret()
declare sub emit_op(symbol as long)
declare function accept(symbol as long) as integer
declare sub expect(symbol as long)
declare function is_binary_operator(symbol as long) as long
declare function is_relational_operator(symbol as long) as long
declare function unary_prec(symbol as long) as long
declare function binary_prec(symbol as long) as long
declare function associativity(symbol as long) as long
declare sub paren_expr()
declare sub primary()
declare sub expr(p as long)
declare sub return_stmt()
declare sub call_stmt2(id as string, sym_pos as long, address as long, pop_ret as long)
declare sub call_stmt()
declare sub assign_stmt()
declare sub if_stmt()
declare sub halt_stmt()
declare sub while_stmt()
declare sub for_stmt()
declare function add_to_string_tab(s as string) as integer
declare sub print_stmt()
declare sub stmt_seq()
declare sub variable_decl()
declare function fixup_parms() as long
declare sub subs()
declare sub process_pending()
declare sub parse()
declare sub error_msg(msg as string)
declare sub init_keywords()
declare function is_alpha(byval ch as string) as long
declare function is_print(byval ch as string) as long
declare function is_numeric(byval ch as string) as long
declare function is_alnum(byval ch as string) as long
sub program(filename as string)
Randomize()
init_keywords()
if filename = "" then exit sub
init_g_sym_tab()
init_pending_list()
init_code()
init_lex(filename)
parse()
' list_code()
interpret()
end sub
sub init_lex(filename as string)
open filename for input as #1
cur_line_num = 0
cur_col = 0
cur_ch = ""
next_char()
end sub
sub next_line() ' read the next line of input from the source file
cur_ch = "" ' empty cur_ch means end-of-file
cur_line = ""
if eof(1) then exit sub
line input #1, cur_line
cur_line = cur_line + chr(10)
cur_line_num += 1
cur_col = 1
end sub
sub next_char() ' get the next char
cur_col += 1
if cur_col > len(cur_line) then next_line
if cur_col <= len(cur_line) then cur_ch = mid(cur_line, cur_col, 1)
end sub
sub skip_white_space()
do
select case cur_ch
case "": return
case " ", chr(9), chr(10), chr(13): next_char()
case else: return
end select
loop
end sub
sub skip_comment()
do
next_char()
if cur_ch = "" then return
if asc(cur_ch) = 13 or asc(cur_ch) = 10 then return
loop
end sub
sub gobble(if_false as Symbol, second_ch as String, if_true as Symbol)
sym = if_false
next_char()
if cur_ch = second_ch then
sym = if_true
next_sym()
end if
end sub
sub next_sym() ' determine the next symbol
token = ""
skip_white_space()
error_line = cur_line_num: error_col = cur_col
' print cur_line_num; ": "; mid(removeeol(cur_line), cur_col); "***cur_ch:["; cur_ch; "]";
select case cur_ch
case "": sym = sym_eoi
case "+": sym = sym_plus: next_char()
case "-": sym = sym_minus: next_char()
case "*": sym = sym_multiply: next_char()
case "/": sym = sym_divide: next_char()
case "\": sym = sym_int_div: next_char()
case ",": sym = sym_comma: next_char()
case "(": sym = sym_lparen: next_char()
case ")": sym = sym_rparen: next_char()
case "=": sym = sym_equal: next_char()
case "^": sym = sym_exponent: next_char()
case DOUBLE_QUOTE: sym = get_string() ' a double quote
case SINGLE_QUOTE: skip_comment(): next_sym() ' a single quote - comment until the end of line
case "<"
sym = sym_lss
next_char()
if cur_ch = ">" then
sym = sym_neq
next_char()
elseif cur_ch = "=" then
sym = sym_leq
next_char()
end if
case ">": gobble(sym_gtr, "=", sym_geq)
case else
if is_numeric(cur_ch) or cur_ch = "." then
get_digits()
elseif is_alpha(cur_ch) then
get_ident()
else
error_msg("unrecognized character: " & cur_ch & " asc = " & asc(cur_ch))
end if
end select
' print " token:";token; " sym:"; sym
end sub
function get_string() as long
dim as long start_line
token = ""
start_line = error_line
next_char()
while cur_ch <> DOUBLE_QUOTE
if cur_ch = "" then
error_msg("eof found in string")
end if
if error_line > start_line then
error_msg("string must be on one line")
end if
token = token & cur_ch
next_char()
wend
if cur_ch = DOUBLE_QUOTE then next_char()
return sym_string_const
end function
sub get_digits()
dim n_decimals as long
token = ""
n_decimals = 0
while is_numeric(cur_ch) or cur_ch = "."
if cur_ch = "." then n_decimals += 1
token = token & cur_ch
next_char()
wend
if n_decimals > 1 then error_msg("number contains more than 1 decimal point")
sym = sym_real_const
if n_decimals = 0 then
sym = sym_integer_const
end if
end sub
sub get_ident()
token = ""
while is_alnum(cur_ch) or cur_ch = "_"
token = token & cur_ch
next_char()
wend
sym = search_key_words()
end sub
' look for a key word - return either the matching sym or sym_ident
function search_key_words() as long
dim as long i
for i = 1 to MAX_KEYWORDS
if token = key_words_tab(i).keyword then
return key_words_tab(i).sym
end if
next
return sym_ident
end function
'------ Pending list ---------------------------------------------------
sub init_pending_list()
pending_list_used = 0
end sub
function lookup_pending(s as string) as long
dim as long i
for i = 1 to pending_list_used
if s = pending_list(i).name then return i
next
return 0
end function
sub install_pending(s as string, offset as long, nargs as long)
if pending_list_used >= MAX_PENDING then
error_msg("Pending list exhausted")
end if
pending_list_used += 1
pending_list(pending_list_used).name = s
pending_list(pending_list_used).offset = offset
pending_list(pending_list_used).nargs = nargs
end sub
'------ Symbol table ---------------------------------------------------
sub init_g_sym_tab()
g_data_offset = 1
g_sym_tab_used = 0
end sub
sub init_l_sym_tab()
l_data_offset = 1
l_sym_tab_used = 0
end sub
function get_data_size() as long
return g_data_offset
end function
function find_sym_tab(ident as string, byref address as long, byref extent as long, byref id_type as long) as long
dim as long i
for i = 1 to l_sym_tab_used
if ident = l_sym_tab(i).ident then
address = l_sym_tab(i).data_offset
extent = local_scope
id_type = l_sym_tab(i).id_type
return i
end if
next
for i = 1 to g_sym_tab_used
if ident = g_sym_tab(i).ident then
address = g_sym_tab(i).data_offset
extent = global_scope
id_type = g_sym_tab(i).id_type
return i
end if
next
return 0
end function
sub insert_sym_tab(the_type as long)
if g_sym_tab_used >= MAX_GSYMTAB then
error_msg("Symbol table exhausted")
end if
if find_sym_tab(token, 0, 0, 0) > 0 then
error_msg(token & " has already been defined")
end if
g_sym_tab_used += 1
g_sym_tab(g_sym_tab_used).ident = token
g_sym_tab(g_sym_tab_used).id_type = the_type
end sub
sub insert_sym_tab_var(extent as long)
if extent = global_scope then
insert_sym_tab(type_var)
g_sym_tab(g_sym_tab_used).data_offset = g_data_offset
g_data_offset += 1
else
l_sym_tab_used += 1
l_sym_tab(l_sym_tab_used).ident = token
l_sym_tab(l_sym_tab_used).id_type = type_var
l_sym_tab(l_sym_tab_used).data_offset = l_data_offset
l_data_offset += 1
end if
end sub
sub insert_sym_tab_double()
insert_sym_tab(type_const_float)
g_sym_tab(g_sym_tab_used).data_offset = g_data_offset
g_data_offset += 1
g_sym_tab(g_sym_tab_used).value = val(token)
end sub
sub insert_sym_tab_sub()
insert_sym_tab(type_sub)
g_sym_tab(g_sym_tab_used).data_offset = get_cur_loc()
g_sym_tab(g_sym_tab_used).nargs = 0
end sub
sub insert_sym_tab_fun()
insert_sym_tab(type_function)
g_sym_tab(g_sym_tab_used).data_offset = get_cur_loc()
g_sym_tab(g_sym_tab_used).nargs = 0
end sub
' see if an ident exists in the symbol table - long return
function is_in_sym_tab(byref address as long, byref extent as long, byref id_type as long) as long
dim as long i
i = find_sym_tab(token, address, extent, id_type)
if i = 0 then return false
return true
end function
'------ virtual machine -------------------------------------------------------------
' code generator
sub init_code()
code_index = 1
last_label = 0
code_start = 0
g_data_size = 0
l_data_size = 0
max_str_pool_used = 0
end sub
sub set_data_size(size_to_set as long)
g_data_size = size_to_set
end sub
function get_cur_loc() as long
return code_index
end function
sub emit_at(location as long, operand as long)
code_arr(location) = operand
end sub
sub emitx(x as long)
if code_index >= MAX_CODE then
error_msg("code array exhausted: " & str(code_index))
end if
code_arr(code_index) = x
code_index += 1
end sub
function emit1(opcode as long) as long
dim as long location = code_index
last_opcode = opcode
emitx(opcode)
return location
end function
function emit2(opcode as long, operand as long) as long
dim as long location = code_index
emit1(opcode)
emitx(operand)
return location
end function
function emit3(opcode as long, operand1 as long, operand2 as long) as long
dim as long location = code_index
if opcode = op_load_int_var then
if operand1 = global_scope then
emit2(op_load_int_var_g, operand2)
elseif operand1 = local_scope then
emit2(op_load_int_var_l, operand2)
else
error_msg("Error 1 in code generator")
end if
elseif opcode = op_stor then
if operand1 = global_scope then
emit2(op_stor_g, operand2)
elseif operand1 = local_scope then
emit2(op_stor_l, operand2)
else
error_msg("Error 1 in code generator")
end if
else
error_msg("Error 3 in code generator")
emit1(opcode)
emitx(operand1)
emitx(operand2)
end if
return location
end function
sub patch_jmp_to_current(fix_addr as long)
' skip over opcode
last_label = code_index
emit_at(fix_addr + 1, code_index)
end sub
Function rnd_range(first As Double, last As Double) As Double
return Rnd * (last - first) + first
End Function
' virtual machine interpreter
sub interpret()
dim as long pc, sp, bp, i, loop_cnt
dim as long opcode, operand, operand2, retval
dim as double stack(MAX_STACK), argf, argf2, time_lapsed
dim as integer t1,t2
dim prt_st as string
dim as long prt_x, prt_y
' load constant numbers to stack
for i = 1 to g_sym_tab_used
if g_sym_tab(i).id_type = type_const_float then
stack(g_sym_tab(i).data_offset) = g_sym_tab(i).value
end if
next
t1=GetTickCount()
print "code_index|g_data_size: "; code_index; " "; g_data_size; " data: "
for i = 1 to g_data_size
print stack(i)
next
print "Running..."
pc = code_start
sp = g_data_size
bp = &Hffff
loop_cnt = 0
do
loop_cnt += 1
opcode = code_arr(pc)
pc += 1
operand = code_arr(pc)
select case opcode
case op_push_int
sp += 1
stack(sp) = operand
pc += 1
case op_load_int_var_l
sp += 1
stack(sp) = stack(operand + bp)
pc += 1
case op_load_int_var_g
sp += 1
stack(sp) = stack(operand)
pc += 1
case op_stor_l
stack(operand + bp) = stack(sp)
sp -= 1
pc += 1
case op_stor_g