Kestrel-3

Check-in [88de4ec636]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:String expression support
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 88de4ec6367ece1ea0e9a7464a10e7828d4f8b5b88152e3d16893f194f010449
User & Date: kc5tja 2019-09-03 02:07:29.253
Context
2019-09-03
02:12
Remove debugging code check-in: 233d4785af user: kc5tja tags: trunk
02:07
String expression support check-in: 88de4ec636 user: kc5tja tags: trunk
01:29
Basic .dword primitive check-in: 0dda2d09e7 user: kc5tja tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to dev/src/bcpl/assemrv/globals_utils.h.
1
2
3
4
5

6
GLOBAL {
    zerovec : g_utils;
    max;
    streq;
    copystr;

}





>

1
2
3
4
5
6
7
GLOBAL {
    zerovec : g_utils;
    max;
    streq;
    copystr;
    replacestr;
}
Changes to dev/src/bcpl/assemrv/manifest.h.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
MANIFEST {
    // By default, we want failed unit tests to die with CLI result 20.
    // This might one day be a parameter.
    failat           = 20;

    // These are stuffed into result2 to give the developer a crude
    // indication of why a test failed.  Ideally, these should be
    // taken from standard BCPL/Tripos error result codes as much as
    // possible.  For now, though, they're proprietary.
    err_no_memory        = 1;
    err_overflow         = 2;
    err_syntax_error     = 100;		// Generic syntax error
    err_int_expr_expected;

    err_field            = 50000;	// Record field (n - err_field) not of expected value

    // Hunk format executables use these constants.
    HUNK_END         = 5000;
    HUNK_CODE;

    // Global Vector Constants












|
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
MANIFEST {
    // By default, we want failed unit tests to die with CLI result 20.
    // This might one day be a parameter.
    failat           = 20;

    // These are stuffed into result2 to give the developer a crude
    // indication of why a test failed.  Ideally, these should be
    // taken from standard BCPL/Tripos error result codes as much as
    // possible.  For now, though, they're proprietary.
    err_no_memory        = 1;
    err_overflow         = 2;
    err_syntax_error     = 100;		// Generic syntax error
    err_int_expr_expected;		// Int expression expected
    err_int_str_expr_expected;		// Int *or* string expression expected
    err_field            = 50000;	// Record field (n - err_field) not of expected value

    // Hunk format executables use these constants.
    HUNK_END         = 5000;
    HUNK_CODE;

    // Global Vector Constants
64
65
66
67
68
69
70

71
72
73
74
75

76
77
78
79
80
81
82
    ed_col;
    ed_code;
    ed_sizeof;

    // Expression Descriptor fields
    expr_type = 0;
    expr_value;

    expr_sizeof;

    // Expression Types
    et_unknown = 0;
    et_integer;


    // Scanner symbol types
    scs_char_upb = 255;
    scs_identifier;
    scs_byte;
    scs_2byte;
    scs_4byte;







>
|




>







65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
    ed_col;
    ed_code;
    ed_sizeof;

    // Expression Descriptor fields
    expr_type = 0;
    expr_value;
    expr_string;
    expr_sizeof = expr_string + (256 >> B2Wsh) + 1;

    // Expression Types
    et_unknown = 0;
    et_integer;
    et_string;

    // Scanner symbol types
    scs_char_upb = 255;
    scs_identifier;
    scs_byte;
    scs_2byte;
    scs_4byte;
92
93
94
95
96
97
98

99
100
101
102
103
104
105
    scs_equ;
    scs_include;
    scs_file;
    scs_line;
    scs_gv;
    scs_gref;
    scs_integer;

    scs_endstreamch = endstreamch;

    // Intermediate Representation order codes
    IR_LIT = 1000;
    IR_DWORD;
}








>







95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
    scs_equ;
    scs_include;
    scs_file;
    scs_line;
    scs_gv;
    scs_gref;
    scs_integer;
    scs_string;
    scs_endstreamch = endstreamch;

    // Intermediate Representation order codes
    IR_LIT = 1000;
    IR_DWORD;
}

Changes to dev/src/bcpl/assemrv/parser.b.
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
		IF !errp DO RETURN
	}
}

AND dword_part(s, d, errp, expr) BE {
	expression(s, d, errp, expr)
	IF !errp DO RETURN
	IF expr!expr_type ~= et_integer DO error(errp, s, err_int_expr_expected) <> RETURN


	dynvec_put_at(d, IR_LIT, d!dv_length)
	dynvec_put_at(d, expr!expr_value, d!dv_length)
	dynvec_put_at(d, IR_DWORD, d!dv_length)















}

AND expression(s, d, errp, expr) BE {
	LET sym = scanner_sym(s)

	IF sym = scs_integer DO {
		expr!expr_type := et_integer
		expr!expr_value := scanner_value(s)
		scanner_next(s)
		RETURN
	}








	error(errp, s, err_syntax_error)
}







<

>
|
|
|
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>











>
>
>
>
>
>
>



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
		IF !errp DO RETURN
	}
}

AND dword_part(s, d, errp, expr) BE {
	expression(s, d, errp, expr)
	IF !errp DO RETURN


	IF expr!expr_type = et_integer DO {
		dynvec_put_at(d, IR_LIT, d!dv_length)
		dynvec_put_at(d, expr!expr_value, d!dv_length)
		dynvec_put_at(d, IR_DWORD, d!dv_length)
		RETURN
	}

	IF expr!expr_type = et_string DO {
		LET s = @expr!expr_string

		FOR i = 1 TO s%0 DO {
			dynvec_put_at(d, IR_LIT, d!dv_length)
			dynvec_put_at(d, s%i, d!dv_length)
			dynvec_put_at(d, IR_DWORD, d!dv_length)
		}
		RETURN
	}

	error(errp, s, err_int_str_expr_expected) <> RETURN
}

AND expression(s, d, errp, expr) BE {
	LET sym = scanner_sym(s)

	IF sym = scs_integer DO {
		expr!expr_type := et_integer
		expr!expr_value := scanner_value(s)
		scanner_next(s)
		RETURN
	}

	IF sym = scs_string DO {
		expr!expr_type := et_string
		replacestr(@expr!expr_string, scanner_label(s))
		scanner_next(s)
		RETURN
	}

	error(errp, s, err_syntax_error)
}
Changes to dev/src/bcpl/assemrv/scanner.b.
103
104
105
106
107
108
109
















110
111
112
113
114
115
116

AND next_sym(s) BE {
	LET n, i, ch, label = 0, 0, ?, s!sc_label

	skip_blanks(s)

	ch := s!sc_ch

















	IF ch = '0' DO {
		ch := rdch()
		TEST (ch = 'x') | (ch = 'X')
		THEN {
			// Hex constant
			ch := rdch()







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







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

AND next_sym(s) BE {
	LET n, i, ch, label = 0, 0, ?, s!sc_label

	skip_blanks(s)

	ch := s!sc_ch

	IF ch = '"' DO {
		ch := rdch()
		i := 1
		WHILE (i < 256) & (ch ~= '"') DO {
			label%i := ch
			i := i + 1
			ch := rdch()
			s!sc_col := s!sc_col + 1
		}
		IF ch = '"' DO ch := rdch() <> s!sc_col := s!sc_col + 1
		s!sc_ch := ch
		label%0 := i-1
		s!sc_sym := scs_string
		RETURN
	}

	IF ch = '0' DO {
		ch := rdch()
		TEST (ch = 'x') | (ch = 'X')
		THEN {
			// Hex constant
			ch := rdch()
Changes to dev/src/bcpl/assemrv/test_parser.b.
60
61
62
63
64
65
66
67
68
69
70
71

72
73
74
75
76
77
78
GET "globals_dynvec"
GET "globals_scanner"
GET "globals_utils"
GET "globals_parser"


LET testlist() = VALOF {
	MANIFEST { ntests = 2 }
	LET tl = getvec(ntests)
	tl!0 := ntests
	tl!1 := test_single_dword
	tl!2 := test_single_dword_chain

	RESULTIS tl
}


// Parser Tests: Simple listings

AND test_single_dword(r) = VALOF {







|




>







60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
GET "globals_dynvec"
GET "globals_scanner"
GET "globals_utils"
GET "globals_parser"


LET testlist() = VALOF {
	MANIFEST { ntests = 3 }
	LET tl = getvec(ntests)
	tl!0 := ntests
	tl!1 := test_single_dword
	tl!2 := test_single_dword_chain
	tl!3 := test_single_dword_string
	RESULTIS tl
}


// Parser Tests: Simple listings

AND test_single_dword(r) = VALOF {
119
120
121
122
123
124
125

126
127
128
129
130
131
132
	IF scb DO endstream(scb)
	RESULTIS err
}

AND free_errors(p) BE {
	WHILE p DO {
		LET dsc = p

		p := dsc!ed_next
		IF dsc!ed_filename DO freevec(dsc!ed_filename)
		freevec(dsc)
	}
}

AND test_single_dword_chain(r) = VALOF {







>







120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
	IF scb DO endstream(scb)
	RESULTIS err
}

AND free_errors(p) BE {
	WHILE p DO {
		LET dsc = p
		writef("%s:%n:%n:%n*n", dsc!ed_filename, dsc!ed_line, dsc!ed_col, dsc!ed_code)
		p := dsc!ed_next
		IF dsc!ed_filename DO freevec(dsc!ed_filename)
		freevec(dsc)
	}
}

AND test_single_dword_chain(r) = VALOF {
165
166
167
168
169
170
171

172
173
174
175
176
177




















































	UNLESS EQ(d!dv_length, 12, 100) DO GOTO unwind
	FOR i = 0 TO 11 DO UNLESS EQ(dynvec_at(d, i), expected!i, 200+i) DO GOTO unwind

	err := 0

unwind:

	IF d DO dynvec_free(d)
	IF s DO scanner_free(s)
	IF scb DO endstream(scb)
	RESULTIS err
}



























































>






>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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

	UNLESS EQ(d!dv_length, 12, 100) DO GOTO unwind
	FOR i = 0 TO 11 DO UNLESS EQ(dynvec_at(d, i), expected!i, 200+i) DO GOTO unwind

	err := 0

unwind:
	IF errlist DO free_errors(errlist)
	IF d DO dynvec_free(d)
	IF s DO scanner_free(s)
	IF scb DO endstream(scb)
	RESULTIS err
}

AND test_single_dword_string(r) = VALOF {
	LET err = failat
	LET scb, s, d = 0, 0, 0
	LET expected = TABLE IR_LIT, 6, IR_DWORD,
	                     IR_LIT, 'A', IR_DWORD,
	                     IR_LIT, 'b', IR_DWORD,
	                     IR_LIT, 'a', IR_DWORD,
	                     IR_LIT, 'c', IR_DWORD,
	                     IR_LIT, 'a', IR_DWORD,
	                     IR_LIT, 'b', IR_DWORD
	LET errlist = 0

	IF r DO RESULTIS r
	testid := "test_single_dword_string"

	writef("============*n")
	scb := findinoutput("RAM:")
	UNLESS NEQ(scb, 0, 0) DO GOTO unwind
	{
		LET outs = output()
		selectoutput(scb)
		writef(".dword 6, *"Abacab*"*n")
		selectoutput(outs)
		rewindstream(scb)
	}

	s := make_scanner()
	UNLESS NEQ(s, 0, 1) DO GOTO unwind
	UNLESS EQ(scanner_get_stream(s, scb, "RAM:"), TRUE, 3) DO GOTO unwind
	scanner_nextchar(s)
	scanner_next(s)

	d := make_dynvec()
	UNLESS NEQ(d, 0, 4) DO GOTO unwind

	parse(s, d, @errlist)
	UNLESS EQ(errlist, 0, 5) DO GOTO unwind

	UNLESS EQ(d!dv_length, 21, 100) DO GOTO unwind
	FOR i = 0 TO 20 DO UNLESS EQ(dynvec_at(d, i), expected!i, 200+i) DO GOTO unwind

	err := 0

unwind:
	IF errlist DO free_errors(errlist)
	IF d DO dynvec_free(d)
	IF s DO scanner_free(s)
	IF scb DO endstream(scb)
	RESULTIS err
}

Changes to dev/src/bcpl/assemrv/test_scanner.b.
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
GET "libhdr"
GET "manifest"
GET "globals_bud"
GET "globals_scanner"


LET testlist() = VALOF {
	MANIFEST { ntests = 10 }
	LET tl = getvec(ntests)
	tl!0 := ntests
	tl!1 := test_new_scanner
	tl!2 := test_get_file
	tl!3 := test_get_sym_eof
	tl!4 := test_get_sym_ident
	tl!5 := test_get_keyword
	tl!6 := test_get_decimal_literal
	tl!7 := test_get_hex_literal
	tl!8 := test_get_binary_literal
	tl!9 := test_get_octal_literal
	tl!10 := test_get_punctuation

	RESULTIS tl
}

// Scanner Tests: Creation

AND test_new_scanner(r) = VALOF {
	LET err, s = failat, ?







|












>







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
GET "libhdr"
GET "manifest"
GET "globals_bud"
GET "globals_scanner"


LET testlist() = VALOF {
	MANIFEST { ntests = 11 }
	LET tl = getvec(ntests)
	tl!0 := ntests
	tl!1 := test_new_scanner
	tl!2 := test_get_file
	tl!3 := test_get_sym_eof
	tl!4 := test_get_sym_ident
	tl!5 := test_get_keyword
	tl!6 := test_get_decimal_literal
	tl!7 := test_get_hex_literal
	tl!8 := test_get_binary_literal
	tl!9 := test_get_octal_literal
	tl!10 := test_get_punctuation
	tl!11 := test_get_string
	RESULTIS tl
}

// Scanner Tests: Creation

AND test_new_scanner(r) = VALOF {
	LET err, s = failat, ?
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
}

AND test_get_punctuation(r) = VALOF {
	LET s, scb, err = 0, 0, failat
	LET syms = TABLE '`', '~', '!', '@', '#', '$', '%', '^',
	                 '&', '**', '(', ')', '-', '=', '+', '[',
	                 '{', ']', '}', '\', '|', ';', ':', '*'',
	                 '"', ',', '/', '?'
	IF r DO RESULTIS r
	testid := "test_get_punctuation"

	s := make_scanner()
	UNLESS NEQ(s, 0, 0) DO GOTO unwind

	scb := findinoutput("RAM:")
	UNLESS NEQ(scb, 0, 1) DO GOTO unwind
	{
		LET outs = output()
		selectoutput(scb)
		writef("` ~ ! @ # $ %% ^ ")
		writef("& ** ( ) - = + [ ")
		writef("{ ] } \ | ; : ' ")
		writef("*" , / ?")
		selectoutput(outs)
		rewindstream(scb)
	}
	UNLESS EQ(scanner_get_stream(s, scb, "RAM:"), TRUE, 2) DO GOTO unwind
	scanner_nextchar(s)

	FOR i = 0 TO 23 DO {
		scanner_next(s)
		UNLESS EQ(scanner_sym(s), syms!i, 100+i) DO GOTO unwind
	}


































	err := 0

unwind:
	IF scb DO endstream(scb)
	IF s DO scanner_free(s)
	RESULTIS err
}







|














|






|



>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>








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
}

AND test_get_punctuation(r) = VALOF {
	LET s, scb, err = 0, 0, failat
	LET syms = TABLE '`', '~', '!', '@', '#', '$', '%', '^',
	                 '&', '**', '(', ')', '-', '=', '+', '[',
	                 '{', ']', '}', '\', '|', ';', ':', '*'',
	                 ',', '/', '?'
	IF r DO RESULTIS r
	testid := "test_get_punctuation"

	s := make_scanner()
	UNLESS NEQ(s, 0, 0) DO GOTO unwind

	scb := findinoutput("RAM:")
	UNLESS NEQ(scb, 0, 1) DO GOTO unwind
	{
		LET outs = output()
		selectoutput(scb)
		writef("` ~ ! @ # $ %% ^ ")
		writef("& ** ( ) - = + [ ")
		writef("{ ] } \ | ; : ' ")
		writef(", / ?")
		selectoutput(outs)
		rewindstream(scb)
	}
	UNLESS EQ(scanner_get_stream(s, scb, "RAM:"), TRUE, 2) DO GOTO unwind
	scanner_nextchar(s)

	FOR i = 0 TO 22 DO {
		scanner_next(s)
		UNLESS EQ(scanner_sym(s), syms!i, 100+i) DO GOTO unwind
	}

	err := 0

unwind:
	IF scb DO endstream(scb)
	IF s DO scanner_free(s)
	RESULTIS err
}

AND test_get_string(r) = VALOF {
	LET s, scb, err = 0, 0, failat
	LET expected = "Hello world"

	IF r DO RESULTIS r
	testid := "test_get_string"

	s := make_scanner()
	UNLESS NEQ(s, 0, 0) DO GOTO unwind

	scb := findinoutput("RAM:")
	UNLESS NEQ(scb, 0, 1) DO GOTO unwind
	{
		LET outs = output()
		selectoutput(scb)
		writef("*"Hello world*"")
		selectoutput(outs)
		rewindstream(scb)
	}
	UNLESS EQ(scanner_get_stream(s, scb, "RAM:"), TRUE, 2) DO GOTO unwind
	scanner_nextchar(s)
	scanner_next(s)
	UNLESS EQ(scanner_sym(s), scs_string, 100) DO GOTO unwind
	FOR i = 0 TO expected%0 DO UNLESS EQ(expected%i, scanner_label(s)%i, 101) DO GOTO unwind

	err := 0

unwind:
	IF scb DO endstream(scb)
	IF s DO scanner_free(s)
	RESULTIS err
}
Changes to dev/src/bcpl/assemrv/utils.b.
15
16
17
18
19
20
21
22
23
24


    UNLESS actual%0 = expected%0 DO RESULTIS FALSE
    FOR i = 1 TO actual%0 DO UNLESS actual%i = expected%i DO RESULTIS FALSE
    RESULTIS TRUE
}

AND copystr(src) = VALOF {
    LET dst = getvec((src%0 >> B2Wsh)+1)
    IF dst DO FOR i = 0 TO src%0 DO dst%i := src%i
    RESULTIS dst
}









|


>
>
15
16
17
18
19
20
21
22
23
24
25
26
    UNLESS actual%0 = expected%0 DO RESULTIS FALSE
    FOR i = 1 TO actual%0 DO UNLESS actual%i = expected%i DO RESULTIS FALSE
    RESULTIS TRUE
}

AND copystr(src) = VALOF {
    LET dst = getvec((src%0 >> B2Wsh)+1)
    IF dst DO replacestr(dst, src)
    RESULTIS dst
}

AND replacestr(dst, src) BE FOR i = 0 TO src%0 DO dst%i := src%i