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