-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathparser.f90
More file actions
345 lines (326 loc) · 13.4 KB
/
parser.f90
File metadata and controls
345 lines (326 loc) · 13.4 KB
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
module PARSER
! Parser for 1401 Autocoder
use BCD_TO_ASCII_m, only: Char_To_Digit
use ERROR_M, only: DO_ERROR
use FLAGS, only: TRACES
use LEXER, only: LEX, T_AT, T_CHARS, T_COMMA, T_DEVICE, T_DONE, T_HASH, &
& T_MINUS, T_NAME, T_NUMBER, T_OTHER, T_PLUS, T_STAR
use LITERALS_M, only: CREATE_LIT, L_ADCON_LIT, L_ADDR_CON, L_AREA_DEF, &
& L_CHAR_LIT, L_NUM_LIT, LITERALS
use OPERAND_M, only: K_ACTUAL, K_ADCON_LIT, K_ADDR_CON, K_AREA_DEF, &
& K_ASTERISK, K_BLANK_CON, K_CHAR_LIT, K_DEVICE, K_NONE, &
& K_NUM_LIT, K_OTHER, K_SYMBOLIC, NUM_OPERANDS, OPERAND, OPERANDS, &
& OPERANDNAMES, X00
use SYMTAB_M, only: ENTER, REF
implicit NONE
private
public :: ADJUST, PARSE
character, public, save :: SFX = ''
contains
subroutine PARSE ( LINE, START, STATUS, ENTER_NAME, LC, NO_LIT, ORG )
! Parse one operand, starting at Start in Line. Set Start = 1 + end of
! last token. Status = <0 -> Error,
! 0 -> Got a good operand ending with comma,
! 1 -> got a good operand ending with blank
! >1 -> Done
character(len=*), intent(in) :: LINE ! of input
integer, intent(inout) :: START ! of next possible token
integer, intent(out) :: STATUS
logical, intent(in) :: ENTER_NAME ! Enter a name into symtab
integer, intent(in), optional :: LC ! Location counter, unless NO_LIT=T
logical, intent(in), optional :: NO_LIT ! Don't do Create_lit
logical, intent(in), optional :: ORG ! Working on ORG or LTORG;
! otherwise X00 offset is zero
integer :: Begin ! Start of operand, not token
logical :: Do_Lit ! Do create_lit?
integer :: End, Fin ! of a token
character(6) :: LitText ! for adcon
integer :: Next ! Num_Operands + 1
integer :: Num
integer :: Token, Token2 ! T_... from Lexer module
integer :: Width ! of an area-defining literal
do_lit = .true.
if ( present(no_lit) ) do_lit = .not. no_lit
status = 0
next = num_operands + 1
! addr kind offset D index label
operands(next) = operand(0,k_none, 0,' ', ' ',' ')
call lex ( line, start, end, token )
operands(next)%d = line(start:end)
select case ( token )
case ( t_at )
num_operands = next
operands(next)%addr = 0
operands(next)%kind = k_other
status = 2 ! Can only get t_at if it's the last thing
case ( t_chars ) ! @...@
num_operands = next
operands(next)%kind = k_char_lit
if ( do_lit ) then
call create_lit ( l_char_lit, end-start-1, line(start+1:end-1), lc, num )
operands(next)%addr = num
else
operands(next)%addr = end - start - 1 ! don't count the @ signs in width
end if
call finish ( 'Character literals' )
case ( t_comma ) ! ,
start = end + 1
call lex ( line, start, end, token )
if ( token == t_done .or. line(start:end) == ' ' ) then ! , at end is OK
num_operands = next
operands(next)%kind = k_other
else
call parseError ( 'Operand missing', next )
end if
case ( t_device ) ! device
num_operands = next
! addr kind offset D index label
operands(next) = operand(0,k_device, 0,' ', ' ',line(start:end))
call finish ( line(start:end) )
case ( t_done ) ! done
status = 2
if ( num_operands > 0 ) then ! DONE makes an operand only if it's
num_operands = next ! not the first thing, so BCE X,Y, works
! addr kind offset D index label
operands(next) = operand(0,k_other, 0,' ', ' ',' ')
end if
case ( t_other ) ! other
num_operands = next
operands(next)%addr = 0
operands(next)%kind = k_other
call finish ( line(start:end) )
case ( t_hash ) ! #
start = end + 1
call lex ( line, start, end, token )
if ( token == t_number ) then
num_operands = next
read ( line(start:end), * ) operands(next)%addr
operands(next)%kind = k_blank_con
else if ( token == t_done ) then
num_operands = next
operands(next)%addr = 0
operands(next)%kind = k_other
else
call parseError ( 'Area definitions cannot have offset or indexing', &
& next )
end if
call finish ( 'Area definitions' )
case ( t_minus, t_plus ) ! +/-
begin = start
start = end + 1
call lex ( line, start, end, token )
select case ( token )
case ( t_chars ) ! +/- @...@
num_operands = next
operands(next)%kind = k_adcon_lit
if ( do_lit ) then
call create_lit ( l_char_lit, end-start-1, line(start+1:end-1), lc, num )
call create_lit ( l_adcon_lit, end-start+2, line(start-1:end), lc, &
& operands(next)%addr )
literals(operands(next)%addr)%width = num
else
operands(next)%addr = end-start-1
end if
case ( t_done )
num_operands = next
operands(next)%kind = k_other
case ( t_name ) ! +/- name
if ( end - start > 5 ) call parseError ( "Name too long", next )
start = end + 1
operands(next)%offset = 0
litText = line(begin+1:end)
if ( litText(6:6) == ' ' ) litText(6:6) = sfx
call lex ( line, start, fin, token2 )
if ( token2 == t_plus .or. token2 == t_minus ) then
end = fin ! +/- name +/-
call adjust ( line, start, end, token, next, status )
else
fin = end + 2
end if
num_operands = next
operands(next)%kind = k_addr_con
operands(next)%label = litText
if ( do_lit ) then
call create_lit ( l_addr_con, 3, &
& line(begin:begin) // trim(litText) // line(fin:end-1), lc, &
& num, operands(next)%offset, operands(next)%index )
operands(next)%addr = num
call enter ( litText, ref, 0, 0, num )
operands(next)%offset = 0 ! Offset and index are part of adcon,
operands(next)%index = ' ' ! not operand
else
operands(next)%addr = 3
end if
case ( t_number ) ! +/- number
num_operands = next
operands(next)%kind = k_num_lit
if ( do_lit ) then
call create_lit ( l_num_lit, end-begin, line(begin:end), lc, num )
operands(next)%addr = num
else
operands(next)%addr = end - begin
end if
case default
call parseError ( '+ or - must be followed by name or number', next )
end select
call finish ( 'Numeric literals and address constants' )
case ( t_name, t_number, t_star ) ! name, number, *
select case ( token )
case ( t_name )
operands(next)%label = line(start:end)
if ( line(start:end) == '' ) then
operands(next)%kind = k_other
else
if ( end - start > 5 ) call parseError ( "Name too long", next )
operands(next)%kind = k_symbolic
if ( operands(next)%label(6:6) == '' ) &
& operands(next)%label(6:6) = sfx
if ( enter_name ) &
& call enter ( operands(next)%label, ref, 0, 0, operands(next)%addr )
end if
case ( t_number )
operands(next)%kind = k_actual
if ( do_lit ) then
operands(next)%addr = 0
if ( end > start ) read ( line(start:end-1), * ) operands(next)%addr
num = char_to_digit(line(end:end))
operands(next)%addr = 10 * sign(operands(next)%addr,num) + num
else
operands(next)%addr = end - start + 1
end if
case default
operands(next)%kind = k_asterisk
end select
begin = start
start = end + 1
call lex ( line, start, end, token )
select case ( token )
case ( t_chars, t_star ) ! name @...@ or name *
call parseError ( 'Name must not be followed by * or character literal', &
& next )
case ( t_comma, t_done ) ! name ,
num_operands = next
case ( t_name, t_number, t_other )
call parseError ( 'Missing punctuation', next )
case ( t_hash ) ! name #
if ( line(begin:begin) == '*' ) then
call parseError ( 'Asterisk cannot be followed by #', next )
else
start = end + 1
call lex ( line, start, end, token )
if ( token == t_number ) then
read ( line(start:end), * ) width
litText = line(begin:start-2)
if ( litText(6:6) == '' ) litText(6:6) = sfx
call create_lit ( l_area_def, width, litText, lc, num )
num_operands = next
operands(next)%addr = num
operands(next)%kind = k_area_def
else
call parseError ( '# must be followed by a number', next )
end if
end if
call finish ( 'Area-defining literal' )
case ( t_minus, t_plus ) ! name +/-
call adjust ( line, start, end, token, next, status, org )
num_operands = next
end select
call finish ( 'Offset or indexed name' )
if ( status /= 0 ) num_operands = num_operands - 1
end select
start = end + 1
if ( token == t_done ) then
if ( status == 0 ) status = 1
end if
if ( index(traces,'p') /= 0 .and. num_operands > 0 ) &
print *, 'Parser: operands(', num_operands, ')', &
& '%addr = ', operands(num_operands)%addr, &
& ', %kind = ', trim(operandNames(operands(num_operands)%kind)), &
& ', %offset = ', operands(num_operands)%offset, &
& ', %d = ', operands(num_operands)%d, &
& ', %index = ', operands(num_operands)%index, &
& ', %label = ', trim(operands(num_operands)%label), &
& ', status = ', status
contains
subroutine Finish ( What )
character(len=*), intent(in) :: What ! are we working on
if ( token == t_done ) return
start = end + 1
if ( token == t_comma ) return
do
call lex ( line, start, end, token )
if ( token == t_done ) return
start = end + 1
if ( token == t_comma ) return
if ( token == t_name ) then
if ( line(start:end) == ' ' ) token = t_done
end if
if ( status == 0 ) call parseError ( &
& what // ' must be last thing in operand', next )
end do
end subroutine Finish
subroutine ParseError ( Message, Field )
character(len=*), intent(in) :: Message
integer, intent(in) :: Field
call do_error ( message, field )
status = -1
end subroutine ParseError
end subroutine PARSE
subroutine ADJUST ( LINE, START, END, TOKEN, NEXT, STATUS, ORG )
! Process the stuff after + or - after a name, number or *
! Can be number + index, index, or x00.
use BCD_TO_ASCII_M, only: ASCII_to_BCD
character(len=*), intent(in) :: LINE
integer, intent(inout) :: START, END, STATUS
integer, intent(out) :: TOKEN
integer, intent(in) :: NEXT
logical, intent(in), optional :: ORG ! Working on ORG or LTORG;
! otherwise X00 offset is zero
integer :: I
integer :: Offset ! number after &/-
start = end + 1
operands(next)%offset = 0
! Get the token after +/-
do
call lex ( line, start, end, token, nosign=.true., offset=.true. )
select case ( token )
case ( t_name, t_number ) ! name +/- number
select case ( line(start:end) )
case ( 'X0', 'X1', 'X2', 'X3' )
if ( operands(next)%index == '' ) operands(next)%index = line(end:end)
if ( line(start-1:start-1) == '-' ) then
call do_error ( 'Index cannot be subtracted', next )
status = -1
end if
case ( 'X00' )
operands(next)%offset = merge(x00,0,present(org))
case default
offset = 0
do i = start, end
offset = 10 * offset + mod(iand(ascii_to_bcd(iachar(line(i:i))),15),10)
end do
if ( line(start-1:start-1) == '-' ) offset = -offset
operands(next)%offset = operands(next)%offset + offset
end select
start = end + 1
call lex ( line, start, end, token )
select case ( token )
case ( t_comma, t_done )
exit
case ( t_plus, t_minus )
start = end + 1
case default
call do_error ( 'Missing punctuation here', next )
status = -1
exit
end select
case default
call do_error ( 'Offset or index must be number or X#', next )
status = -1
exit
end select
end do
end subroutine ADJUST
end module PARSER
!>> 2011-08-14 ENTER wants a location counter number
!>> 2012-09-27 Fix bug in ORG -- not sending ORG to ADJUST