|
|
1.1 root 1: data("b(op,l,r)")
2: data("u(op,r)")
3: data("i_fcall(name,head,tail)")
4: data("fcall(name,args,l,r)")
5: data("argexp(exp,next)")
6: data("binfo(in,out,lp,rp,slp,srp,fn)")
7:
8: stack = table()
9: bconv = table()
10: deflist = table(50)
11: inctab = table()
12: stno_tab = table(100)
13:
14: bconv['('] = binfo('(','',0)
15:
16: bconv['='] = binfo('=','=',1,2,0,1)
17: bconv['?'] = binfo('?','?',2,2,1,1)
18: bconv['|'] = binfo('|','|',3,3,2,2)
19: bconv['||'] = or_binfo = binfo('||','',4,4,0,0,1)
20: bconv['&&'] = cat_binfo = binfo('&&',' ',5,5,4,4)
21: bconv['>'] = binfo('>','GT',6,6,0,0,1)
22: bconv['<'] = binfo('<','LT',6,6,0,0,1)
23: bconv['>='] = binfo('>=','GE',6,6,0,0,1)
24: bconv['<='] = binfo('<=','LE',6,6,0,0,1)
25: bconv['=='] = binfo('==','EQ',6,6,0,0,1)
26: bconv['!='] = binfo('!=','NE',6,6,0,0,1)
27: bconv['::'] = binfo('::','IDENT',6,6,0,0,1)
28: bconv[':!:'] = binfo(':!:','DIFFER',6,6,0,0,1)
29: bconv[':>:'] = binfo(':>:','LGT',6,6,0,0,1)
30: bconv[':<:'] = binfo(':<:','LLT',6,6,0,0,1)
31: bconv[':>=:'] = binfo(':>=:','LGE',6,6,0,0,1)
32: bconv[':<=:'] = binfo(':<=:','LLE',6,6,0,0,1)
33: bconv[':==:'] = binfo(':==:','LEQ',6,6,0,0,1)
34: bconv[':!=:'] = binfo(':!=:','LNE',6,6,0,0,1)
35: bconv['+'] = binfo('+','+',7,7,5,5)
36: bconv['-'] = binfo('-','-',7,7,5,5)
37: bconv['/'] = binfo('/','/',8,8,7,7)
38: bconv['*'] = binfo('*','*',8,8,8,8)
39: bconv['%'] = binfo('%','REMDR',8,8,0,0,1)
40: bconv['^'] = binfo('^','**',9,10,10,11)
41: bconv['.'] = binfo('.','.',10,10,11,11)
42: bconv['$'] = binfo('$','$',10,10,11,11)
43:
44: ht = char(9)
45: optblank = nspan(" " && ht)
46: blank = span(" " && ht)
47: digits = "0123456789"
48: letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_"
49:
50: integer = span(digits)
51: exponent = any("eEdD") && (any("+-") | "") && integer
52: real = integer && "." && (integer | "") && (exponent | "") |
53: integer && exponent | "." && integer && (exponent | "")
54: number = real | integer
55:
56: string = any("'" && '"') $ squote && break(*squote) && len(1)
57:
58: constant = number | string
59: identifier = any(letters) && nspan(letters && digits)
60: unaryop = any("+-*&@~?.$")
61: binaryop = any("+-*/<>=^.$?|%") | "==" | "!=" | "<=" | ">=" | "&&" |
62: "||" | ":==:" | ":!=:" | ":>:" | ":<:" | ":>=" | ":<=:" |
63: "::" | ":!:"
64:
65: fcall = identifier . *mkfcall() && optblank &&
66: (("(" && list(*exp . *invoke(.mkarg), optblank && ",") &&
67: optblank && ")" . *invoke(.endfc)) |
68: ("[" && list(*exp . *invoke(.mkarg), optblank && ",") &&
69: optblank && "]" . *invoke(.endfc) . *invoke(.mkarray)))
70:
71: term = optblank && (constant . *push() . *dotck() |
72: identifier . *push() | "(" && *exp && optblank && ")" | fcall)
73: operand = term | optblank && unaryop . *push() &&
74: *operand . *invoke(.unop)
75: exp = "" . *begexp() && *operand &&
76: arbno(optblank && binaryop . *push() . *invoke(.mkbinfo) &&
77: *operand . *invoke(.binop)) && "" . *endexp()
78:
79: label = optblank && identifier . lab . *emitlab(lab) && optblank && ":"
80:
81: clause = fence && arbno(label) && optblank &&
82: ("if" . cl_type && optblank && "(" && *exp && optblank && ")" |
83: "while" . cl_type && optblank && "(" && *exp && optblank && ")" |
84: (kw("return") | kw("freturn") | kw("nreturn")) . cl_type && optblank &&
85: ("" . *push() | *exp) &&
86: optblank && (any("{}") . del | rpos(0)) |
87: "go" && optblank && "to" && blank &&
88: identifier . dest . *invoke(.gocl) |
89: ("{" | "}") . cl_type |
90: ("do" | kw("else")) . cl_type && (span(" " && ht) | rpos(0)) |
91: "procedure" . cl_type && blank && identifier . fname |
92: "struct" . cl_type && blank && identifier . stname |
93: "for" . cl_type && optblank &&
94: "(" && *exp && optblank && "," && *exp && optblank &&
95: "," && *exp && optblank && ")" |
96: rpos(0) . cl_type && *invoke(.emiteos) |
97: *exp && optblank && (any("{}") . del | rpos(0)) . *invoke(.expcl))
98:
99: gl_files = table()
100: gl_lines = table()
101: gl_vars = table()
102: gl_index = -1
103:
104: emit_stno = 0
105:
106: &stlimit = 1000000000
107: #
108: # save the current state -- we really begin execution here.
109: exit(3)
110: #
111: # establish the "object" file
112: outfile = "a.out"
113: output(.outf,0,outfile)
114: outf = "#!/usr/bin/spitbol -s16k"
115: #
116: # Establish a starting point for input files
117: gl_arg = host(3) - 1
118: if (~host (2, host(3))) {
119: output = "no files"
120: go to end
121: }
122:
123: if (~gl_nextfile()) {
124: go to end
125: }
126: #
127: # Prologue
128: emitlab("MAIN.")
129: #
130: # The main loop. We expect to read a series of statements.
131: while (nclause (1)) {
132: if (ident (cl_type, "procedure"))
133: funct()
134: else if (ident (cl_type, "struct"))
135: dostruct()
136: else
137: dostmt()
138: }
139:
140:
141: # Epilogue
142: exit:
143: emitg("END")
144: emitlab("START.")
145: emit("CODE('START.')")
146: for (i = 1, i <= deflist[0], i = i + 1) {
147: emiteos()
148: emit(deflist[i])
149: }
150:
151: emitg("MAIN.")
152: emitlab("END")
153: emit("START.")
154: emiteos()
155: endfile(0)
156: host (1, "chmod +x " && outfile)
157:
158:
159:
160: # subroutines
161:
162:
163:
164:
165: # like span, but the pattern returned
166: # can also match the null string
167: procedure nspan (str) {
168: return span (str) | ""
169: }
170:
171: # a pattern that matches a list of zero or more
172: # "item"s separated by "delim"s
173: procedure list (item, delim) {
174: return item && arbno (delim && item) | ""
175: }
176:
177: # a pattern that matches the keyword given by the
178: # argument, insisting that it be followed by a non-letter.
179: procedure kw (s) {
180: return span(letters) $ dummy &&
181: convert("ident(dummy,'" && s && "')", "EXPRESSION")
182: }
183:
184: # return the name of the (new) top stack element
185: procedure push() {
186: stackptr = stackptr + 1
187: nreturn .stack[stackptr]
188: }
189:
190: # return the value of the (old) top stack element
191: procedure pop() {
192: pop = stack[stackptr]
193: stack[stackptr] = ""
194: stackptr = stackptr - 1
195: }
196:
197: # return the name of the stack element n away from the top
198: procedure peek (n) {
199: if (n >= stackptr)
200: go to err
201: nreturn .stack[stackptr - n]
202: }
203:
204: # top()
205: # return the name of the top stack element
206: procedure top() {
207: nreturn .stack[stackptr]
208: }
209:
210: # isbin(x)
211: # is x a structure describing a binary operator?
212: # things like == and ||, which syntactically look
213: # more like functions than operators in their snobol form,
214: # are considered not to be operators.
215: procedure isbin (x) {
216: if (differ (datatype (x), 'B') || differ (fn (op (x))))
217: freturn
218: }
219:
220: # isneg(x)
221: # is x a structure describing a unary negation operator?
222: procedure isneg (x) {
223: if (differ (datatype (x), 'U') || differ (op (x), '~'))
224: freturn
225: }
226:
227: #
228: # print an expression in snobol form
229: procedure dprint (x) op, l, r, d, i, del {
230: d = datatype(x)
231: if (ident (d, 'STRING')) {
232: emit (x)
233: return
234: }
235:
236: if (ident (d, 'U')) {
237: # unary operator
238: emit (op (x))
239: if (isbin(r(x)))
240: emit('(')
241: dprint(r(x))
242: if (isbin(r(x)))
243: emit(')')
244: return
245: }
246:
247:
248: if (ident (d, 'FCALL')) {
249: # function call or array reference
250: emit (name (x))
251: emit (l (x))
252: r = args (x)
253: while (differ (r)) {
254: emit (del)
255: dprint (exp (r))
256: del = ','
257: r = next (r)
258: }
259: emit (r (x))
260: return
261: }
262:
263: if (ident (d, 'B')) {
264: # binary operator
265: op = op (x)
266: if (ident (op, or_binfo)) {
267: emit ('(')
268: bprint (x)
269: emit (')')
270: return
271: }
272: l = isbin(l(x)) && slp(op(l(x))) < srp(op) && 1 || ""
273: r = isbin(r(x)) && slp(op) > srp(op(r(x))) && 1 || ""
274:
275: # check for [f](a,b)
276: if (differ (fn (op))) {
277: emit(out(op))
278: emit('(')
279: dprint(l(x))
280: emit(',')
281: dprint(r(x))
282: emit(')')
283: return
284: }
285:
286: # ordinary binary operator
287: if (differ (l))
288: emit ('(')
289: dprint(l(x))
290: if (differ (l))
291: emit (')')
292: emitb(out(op))
293: if (differ(r))
294: emit('(')
295: dprint(r(x))
296: if (differ(r))
297: emit(')')
298: return
299: }
300:
301: # unknown datatype
302: i = 1
303: emit(d)
304: emit ('(')
305: while (dprint (apply (field (d, i), x))) {
306: i = i + 1
307: emit (',')
308: }
309: emit (')')
310: }
311:
312: # bprint(x)
313: # subroutine of dprint -- used to handle printing of
314: # things of the form (a,b), which are inherently
315: # associative and can therefore be grouped as follows
316: # ((a,b),c) <=> (a,(b,c)) <=> (a,b,c)
317: procedure bprint (x) {
318: if (differ (datatype(x), 'B') || differ (op(x), or_binfo)) {
319: dprint (x)
320: return
321: }
322: bprint(l(x))
323: emit(',')
324: bprint(r(x))
325: }
326:
327: # sprint(x)
328: # like dprint, but print in a form appropriate for
329: # an entire statement. Problem: if the top level
330: # operator is a concatenation, it is necessary to
331: # enclose the whole thing in parentheses, because
332: # otherwise it would be mistaken for a pattern match.
333: procedure sprint (x) {
334: if (ident(datatype(x),'B') && ident(op(x),cat_binfo))
335: emit('(')
336: dprint(x)
337: if (ident(datatype(x),'B') && ident(op(x),cat_binfo))
338: emit(')')
339: emiteob()
340: }
341:
342: # invoke(f)
343: # call an argument-free function in a context where
344: # a name is required, such as arb . *invoke(.foo)
345: procedure invoke (f) {
346: apply (f)
347: nreturn .dummy
348: }
349:
350: # a unary operator has been detected during parsing
351: procedure unop() r, op {
352: r = pop()
353: op = pop()
354: push() = u(op,r)
355: }
356:
357: # mkfcall()
358: # Parsing has detected the beginning of a function call
359: procedure mkfcall() {
360: push() = i_fcall()
361: nreturn .name(top())
362: }
363:
364: # parsing has detected an argument to a function
365: procedure mkarg() x, f {
366: x = argexp(pop(),"")
367: f = top()
368: if (differ(tail(f)))
369: next(tail(f)) = x
370: tail(f) = x
371: head(f) = ident(head(f)) && x
372: }
373:
374: # parsing has detected the end of a function call
375: procedure endfc() f {
376: f = pop()
377: push() = fcall(name(f),head(f),'(',')')
378: }
379:
380: # the fcall at the head of the stack is really an array
381: procedure mkarray() t {
382: t = top()
383: l(t) = '<'
384: r(t) = '>'
385: }
386:
387: # the beginning of an expression has been detected
388: procedure begexp() {
389: push() = bconv['(']
390: nreturn .dummy
391: }
392:
393: # a binary operator has been detected. We handle
394: # precedence here rather than in the grammar
395: # because it is less work.
396: procedure binop() l, r, op, newr, newop {
397: while (lp(peek(3)) >= rp(peek(1))) {
398: newr = pop()
399: newop = pop()
400: r = pop()
401: op = pop()
402: l = pop()
403: push() = b(op,l,r)
404: push() = newop
405: push() = newr
406: }
407: }
408:
409: # the end of an expression has been detected
410: procedure endexp() l, r, op {
411: while (differ (in (peek (1)), '(')) {
412: r = pop()
413: op = pop()
414: l = pop()
415: push() = b(op,l,r)
416: }
417: r = pop()
418: pop()
419: push() = r
420: nreturn .dummy
421: }
422:
423: # catenate x and y, making sure that at least one
424: # blank separate them.
425: procedure bcat (x, y) {
426: if (ident (x))
427: return y
428: if (ident (y))
429: return x
430: if (substr (x, size(x), 1) :==: ' ' || substr (y, 1, 1) :==: ' ')
431: return x && y
432: return x && ' ' && y
433: }
434:
435: # locate the binfo structure that describes the
436: # binary operator whose input character representation
437: # has been placed on the top of the stack.
438: procedure mkbinfo() op {
439: op = bconv[pop()]
440: if (ident(op))
441: go to err
442: push() = op
443: }
444:
445: # dotck()
446: # if necessary, append a leading zero to a floating-point
447: # constant that begins with a decimal point. The idea
448: # that .5 is syntactically correct but semantically illegal
449: # is just too scary to leave in.
450: procedure dotck() {
451: top() ? fence && '.' = '0.'
452: nreturn .dummy
453: }
454:
455: # write label l to the output
456: procedure emitlab (l) {
457: if (differ(l)) {
458: emiteos()
459: st_lab = l
460: }
461: nreturn .dummy
462: }
463:
464: # put string s in the output
465: procedure emit (s) {
466: if (differ(emit_eob))
467: emiteos()
468: st_body = st_body && s
469: }
470:
471: # we are done with the body of the generated statement
472: procedure emiteob() {
473: emit_eob = 1
474: stno_tab[emit_stno] = gl_file && "(" && gl_line && ")"
475: }
476:
477: # write success branch l
478: procedure emits (l) {
479: emiteob()
480: st_s = l
481: }
482:
483: # emitf(l)
484: # write failure branch l
485: procedure emitf (l) {
486: emiteob()
487: st_f = l
488: }
489:
490: # write unconditional branch l
491: procedure emitg (l) {
492: emiteob()
493: st_s = ident(st_s) && l
494: st_f = ident(st_f) && l
495: }
496:
497: # write s surrounded by blanks
498: procedure emitb (s) {
499: emit(' ')
500: if (differ (s, ' ')) {
501: emit (s)
502: emit(' ')
503: }
504: }
505:
506: # emiteos()out,goto
507: # we are done with the entire statement
508: procedure emiteos() out, goto, s, del {
509: emit_eob = ""
510: emit_stno = emit_stno + 1
511: if (differ(st_lab) || differ(st_body) || differ(st_s) || differ(st_f)) {
512: out = st_lab && ht && st_body
513: out = out && dupl (ht,5 - size(st_lab) / 8 - size(st_body) / 8)
514: if (differ (st_s) || differ (st_f)) {
515: goto = ht && ':'
516: if (ident (st_s, st_f))
517: goto = goto && "(" && st_s && ")"
518: else {
519: if (differ (st_s))
520: goto = goto && "S(" && st_s && ")"
521: if (differ (st_f))
522: goto = goto && "F(" && st_f && ")"
523: }
524: }
525: out = out && goto
526: while (size(out) >= 70) {
527: out ? fence &&
528: (arbno(break(" '" && '"') &&
529: (" " | any("'" && '"') $ del &&
530: break(*del) && len(1))) $ s &&
531: *(size(s) > 50)) . outf = "+ "
532: }
533: outf = out
534: st_lab = st_body = st_s = st_f = ""
535: }
536: }
537:
538: # attempt to read an input line, taking #include into account
539: procedure getline() x, file, del, dir {
540: do {
541: # Try to read a line from the current file
542: while (x = $gl_var) {
543:
544: # We have a line: count it
545: gl_line = gl_line + 1
546:
547: # If it's not an include statement, we're done.
548: if (~(x ? fence && "#" && *optblank && "include" &&
549: *optblank && any('"<{' && "'") $ del &&
550: break(*replace(del,'<{','>}')) . file &&
551: len (1) && *optblank && rpos(0)))
552: return x
553:
554: # If the name is enclosed in quotes and
555: # relative, then it is relative to the
556: # directory containing the currently included
557: # file, if any. If it is enclosed in brackets,
558: # it is relative to a canonical directory.
559: if ("'" && '"' ? del) {
560: if (substr (file, 1, 1) :!=: '/') {
561: if ((gl_file && '/') ? fence &&
562: (breakx('/') && len(1)) . dir &&
563: break('/') && len(1) && rpos(0))
564: file = dir && file
565: }
566: } else
567: file = "/usr/lib/snocone/" && file
568:
569: # If the name was enclosed by single quotes
570: # or set brackets, ensure the particular file
571: # was included only once. Right now, we're pretty
572: # literal-minded about when two files are really
573: # the same: 'x' and './x' are different, for instance.
574: if (('"<' ? del) || ident (inctab[file])) {
575: inctab[file] = 1
576: gl_open (file)
577: }
578: }
579:
580: # We've reached the end of this file.
581: gl_close()
582: } while (gl_index >= 0 || gl_nextfile());
583:
584: freturn
585: }
586:
587: procedure gl_nextfile() {
588: gl_arg = gl_arg + 1
589: if (~gl_open (host (2, gl_arg)))
590: freturn
591: }
592:
593: procedure gl_close() {
594: &errlimit = &errlimit + 1
595: if (endfile (gl_var))
596: &errlimit = &errlimit - 1
597: gl_index = gl_index - 1
598: gl_file = gl_files[gl_index]
599: gl_line = gl_lines[gl_index]
600: gl_var = gl_vars[gl_index]
601: gl_files[gl_index] = gl_lines[gl_index] = gl_vars[gl_index] = ""
602: }
603:
604: procedure gl_open (file) {
605: gl_files[gl_index] = gl_file
606: gl_lines[gl_index] = gl_line
607: gl_vars[gl_index] = gl_var
608: gl_index = gl_index + 1
609: gl_count = gl_count + 1
610: gl_var = .$("GL_" && gl_count)
611: gl_line = 0
612: gl_file = file
613: input (gl_var, gl_var, file)
614: &errlimit = &errlimit + 1
615: if (rewind (gl_var)) {
616: &errlimit = &errlimit - 1
617: return
618: }
619: gl_close()
620: output = "cannot open " && file
621: freturn
622: }
623:
624: # attempt to read an input line, return on ultimate failure
625: procedure getinput() del, line {
626:
627: # have we already encountered the last EOF?
628: if (differ (gi_eof))
629: freturn
630:
631: if (line = line && getline()) {
632:
633: # strip comments
634: line ?
635: fence &&
636: (arbno (break ("'" && '"') &&
637: len(1) $ del && break (*del) && len(1)) &&
638: break ("'" && '"#')) . line && "#"
639:
640: # check for continuation
641: if (line? any("@$%^&*(-+=[<>|~,?:") && optblank && rpos(0))
642: line = line && getinput()
643:
644: return line
645: }
646:
647: # we're out of input - signal final eof
648: gi_eof = 1
649: freturn
650: }
651:
652: # phrase()
653: # return the next phrase from the input
654: procedure phrase() del {
655: if (ph_buf ? fence && optblank && rpos(0)) {
656: if (ph_buf = phbuf && getinput())
657: return phrase()
658: else
659: freturn
660: }
661:
662: if (ph_buf ? fence && arbno(break('"' && "';") && fence &&
663: (any('"' && "'")$del && break(*del) && len(1) |
664: "")).phrase && ';' = '')
665: return
666: phrase = ph_buf
667: ph_buf = ''
668: }
669:
670: # return a new label
671: procedure newlab() {
672: nl_count = nl_count + 1
673: return "L." && nl_count
674: }
675:
676: # return a new label and place it on the current statement.
677: # If the current statement already has a label, use that.
678: procedure marklab() {
679: if (differ (st_lab) && ident (emit_eob))
680: return st_lab
681: marklab = newlab()
682: emitlab (marklab)
683: }
684:
685: # little routines to indicate what type of clause was read
686:
687: # expression clause
688: procedure expcl() {
689: cl_type = "exp"
690: }
691:
692: # goto clause
693: procedure gocl() {
694: cl_type = "goto"
695: }
696:
697: # read a new clause and classify it
698: # if end of input, error unless "okeof" argument is non-null,
699: # in which case we merely fail
700: # if rep_clause is set, give us the last clause again
701: procedure nclause (okeof) del {
702: nclause_start:
703: if (differ (rep_clause)) {
704: rep_clause = ""
705: if (ident (eof))
706: return
707: else
708: freturn
709: }
710: if (linebuf ? fence && *optblank && rpos(0)) {
711: if (linebuf = phrase())
712: go to nclause_start
713:
714: # end of input
715: if (ident(okeof)) {
716: error ('premature EOF')
717: go to exit
718: }
719: eof = 1
720: freturn
721: }
722:
723: # we really have some input
724: if (linebuf ? clause = del)
725: return
726: error("syntax error")
727: linebuf = ""
728: go to nclause_start
729: }
730:
731: procedure error (msg) {
732: terminal = gl_file && "(" && gl_line && "): " && msg
733: &code = 1
734: }
735:
736: # handle a statement
737: procedure dostmt() lab, lab2, e1, e2, e3, flip {
738: if (ident(cl_type,"exp")) {
739: # The clause is an expression,
740: # so that's the whole statement
741: sprint(pop())
742: return
743: }
744:
745: # It might be a sequence of statements in braces
746: if (ident(cl_type,"{")) {
747: nclause()
748: while (differ (cl_type, "}")) {
749: dostmt()
750: nclause()
751: }
752: return
753: }
754:
755: # It might be a goto statement
756: if (ident (cl_type, "goto")) {
757: emitg (dest)
758: return
759: }
760:
761: # It might be an if statement
762: if (ident(cl_type,"if")) {
763: e1 = pop()
764:
765: # optimize "if (~expr)"
766: if (isneg (e1)) {
767: flip = 1
768: e1 = r(e1)
769: }
770:
771: sprint(e1)
772:
773: # Check for if(...)goto
774: nclause()
775: if (ident(cl_type,"goto")) {
776: if (ident (flip))
777: emits(dest)
778: else
779: emitf(dest)
780:
781: # In the case of if (e) goto l; else ...
782: # we can pretend the else wasn't there
783: if (~nclause(1) || differ (cl_type, "else")) {
784: rep_clause = 1
785: emitlab (lab)
786: return
787: }
788: nclause()
789: dostmt()
790: return
791: }
792:
793: # Not if...goto, emit conditional jump over
794: # the statement which follows.
795: lab = newlab()
796: if (ident (flip))
797: emitf(lab)
798: else
799: emits(lab)
800: dostmt()
801:
802: # Check for else clause
803: if (nclause (1) && ident (cl_type, "else")) {
804:
805: # There is indeed an else clause
806: lab2 = newlab()
807: emitg(lab2)
808: emitlab(lab)
809: nclause()
810: dostmt()
811: emitlab(lab2)
812: return
813: }
814:
815: # No else clause; we must look at this clause again later
816: rep_clause = 1
817: emitlab(lab)
818: return
819: }
820:
821: # Check for a while clause
822: if (ident(cl_type,"while")) {
823: lab = marklab()
824:
825: # optimize "while(~exp)"
826: e1 = pop()
827: if (isneg (e1)) {
828: flip = 1
829: e1 = r(e1)
830: }
831:
832: sprint(e1)
833: lab2 = newlab()
834: if (ident (flip))
835: emitf(lab2)
836: else
837: emits(lab2)
838: nclause()
839: dostmt()
840: emitg(lab)
841: emitlab(lab2)
842: return
843: }
844:
845: # Check for a do clause
846: if (ident(cl_type,"do")) {
847: lab = marklab()
848: nclause()
849: dostmt()
850: nclause()
851: if (differ(cl_type,"while")) {
852: error ("expected 'while', found " && cl_type)
853: rep_clause = 1
854: return
855: }
856: e1 = pop()
857: if (isneg (e1)) {
858: flip = 1
859: e1 = r (e1)
860: }
861: sprint(e1)
862: if (ident (flip))
863: emits (lab)
864: else
865: emitf (lab)
866: return
867: }
868:
869: # Check for a "for" clause
870: if (ident(cl_type,"for")) {
871: e3 = pop()
872: e2 = pop()
873: e1 = pop()
874: sprint(e1)
875: emiteob()
876: lab = marklab()
877: lab2 = newlab()
878: if (isneg (e2)) {
879: flip = 1
880: e2 = r (e2)
881: }
882: sprint(e2)
883: if (ident (flip))
884: emitf (lab2)
885: else
886: emits (lab2)
887: nclause()
888: dostmt()
889: sprint(e3)
890: emitg(lab)
891: emitlab(lab2)
892: return
893: }
894:
895: # could be some kind of return statement
896: if (cl_type ? "return") {
897: e1 = pop()
898: if (differ(e1)) {
899: if (differ(fname))
900: e1 = b(bconv["="],fname,e1)
901: sprint(e1)
902: }
903: emitg (replace(cl_type,
904: "abcdefghijklmnopqrstuvwxyz",
905: "ABCDEFGHIJKLMNOPQRSTUVWXYZ"))
906: return
907: }
908:
909: # could even be a null statement
910: if (ident(cl_type))
911: return
912:
913: error("bad " && cl_type && " clause, ignored")
914: }
915:
916: # We have seen "struct" -- parse the 'declaration'
917: procedure dostruct() args {
918: if (expect ('{')) {
919: args = getlist ('}')
920: deflist[deflist[0] = deflist[0] + 1] =
921: "DATA('" && stname && "(" && args && ")')"
922: } else
923: error ("bad structure definition")
924: expect ('}')
925: }
926:
927: # We have seen "procedure" -- we must now parse the header
928: procedure funct() args, locals, flabel {
929: if (expect('(')) {
930: if (~(args = getlist(')')))
931: go to fu_error
932: expect(')')
933: if (~(locals = getlist('{')))
934: go to fu_error
935: }
936:
937: deflist[deflist[0] = deflist[0] + 1] =
938: "DEFINE('" && fname && '(' && args && ')' && locals && "')"
939:
940: # if we just emitted the end of a previous procedure,
941: # we can jump around this one in one go
942: if (ident (emit_eob) && st_lab ? ".END") {
943: flabel = st_lab
944: st_lab = ""
945: emitlab(fname)
946: nclause()
947: dostmt()
948: emitg("RETURN")
949: emitlab(flabel)
950: return
951: }
952:
953: emitg(fname && '.END')
954: emitlab(fname)
955: nclause()
956: dostmt()
957: emitg("RETURN")
958: emitlab(fname && '.END')
959: return
960:
961: fu_error:
962: error("bad function definition")
963: }
964:
965: # the input should now contain something matching "p"
966: # possibly surrounded by white space. If not, fail
967: procedure expect (p) {
968:
969: # throw away blank lines
970: while (linebuf ? fence && optblank && rpos (0)) {
971: if (~(linebuf = phrase()))
972: freturn
973: }
974:
975: # try to match the given pattern, possibly preceded by white space
976: if (linebuf ? fence && optblank && *p = "")
977: return
978:
979: # didn't match: fail
980: freturn
981: }
982:
983: # expect an identifier in the input; return it.
984: procedure getid() {
985: if (expect (*identifier . getid))
986: return
987: freturn
988: }
989:
990: # expect a list of identifiers followed by tail
991: procedure getlist (tail) del {
992: getlist_start:
993: if (expect(tail)) {
994: linebuf = tail && linebuf
995: return
996: }
997: if (getlist = getlist && del && getid()) {
998: expect(',')
999: del = ','
1000: go to getlist_start
1001: }
1002: if (expect(tail))
1003: return
1004: freturn
1005: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.