|
|
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 &&
105: optblank && ("" . *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: outf = "-in4096"
154: #
155: # Permanent prologue
156: emitlab("MAIN.")
157: #
158: # The main loop. We expect to read a series of statements.
159: while (nclause (1)) {
160: if (IDENT (cl_type, "procedure"))
161: funct()
162: else if (IDENT (cl_type, "struct"))
163: dostruct()
164: else
165: dostmt()
166: }
167:
168:
169: # Epilogue
170: EXIT:
171: emitg("END")
172: emitlab("START.")
173: emit("CODE('START.')")
174: for (i = 1, i <= deflist[0], i = i + 1) {
175: emiteos()
176: emit(deflist[i])
177: }
178:
179: # put out code to trap run-time errors
180: emiteos()
181: emit("&ERRLIMIT = 1")
182: emiteos()
183: emit("SETEXIT(.err.exit)")
184:
185: # put out code to assign the statement map
186: emiteos()
187: emit ("err.map = '")
188: while (bst_stab ? LEN(50) . bst_chunk = "") {
189: emit (bst_chunk && "'")
190: emiteos()
191: emitlab("+")
192: emit("'")
193: }
194: emit (bst_stab && "'")
195:
196: emitg("MAIN.")
197: emiteos()
198:
199: # Epilogue
200: INPUT(.inf,-2,'/usr/lib/snocone/epilogue')
201: while (line = inf)
202: outf = line
203: ENDFILE(-2)
204:
205: ENDFILE(-1)
206: HOST (1, "chmod +x " && outfile)
207:
208:
209:
210: # subroutines
211:
212:
213:
214:
215: # like span, but the pattern returned
216: # can also match the null string
217: procedure nspan (str) {
218: return SPAN (str) | ""
219: }
220:
221: # a pattern that matches a list of zero or more
222: # "item"s separated by "delim"s
223: procedure list (item, delim) {
224: return item && ARBNO (delim && item) | ""
225: }
226:
227: # a pattern that matches the keyword given by the
228: # argument, insisting that it be followed by a non-letter.
229: procedure kw (s) {
230: return SPAN(letters) $ dummy &&
231: CONVERT("ident(dummy,'" && s && "')", "EXPRESSION")
232: }
233:
234: # return the name of the (new) top stack element
235: procedure push() {
236: stackptr = stackptr + 1
237: nreturn .stack[stackptr]
238: }
239:
240: # return the value of the (old) top stack element
241: procedure pop() {
242: pop = stack[stackptr]
243: stack[stackptr] = ""
244: stackptr = stackptr - 1
245: }
246:
247: # return the name of the stack element n away from the top
248: procedure peek (n) {
249: if (n >= stackptr)
250: go to err
251: nreturn .stack[stackptr - n]
252: }
253:
254: # top()
255: # return the name of the top stack element
256: procedure top() {
257: nreturn .stack[stackptr]
258: }
259:
260: # isbin(x)
261: # is x a structure describing a binary operator?
262: # things like == and ||, which syntactically look
263: # more like functions than operators in their snobol form,
264: # are considered not to be operators.
265: procedure isbin (x) {
266: if (DIFFER (DATATYPE (x), 'B') || DIFFER (fn (op (x))))
267: freturn
268: }
269:
270: # isneg(x)
271: # is x a structure describing a unary negation operator?
272: procedure isneg (x) {
273: if (DIFFER (DATATYPE (x), 'U') || DIFFER (op (x), '~'))
274: freturn
275: }
276:
277: #
278: # print an expression in snobol form
279: procedure dprint (x) op, l, r, d, i, del {
280: d = DATATYPE(x)
281: if (IDENT (d, 'STRING')) {
282: emit (x)
283: return
284: }
285:
286: if (IDENT (d, 'U')) {
287: # unary operator
288: emit (op (x))
289: if (isbin(r(x)))
290: emit('(')
291: dprint(r(x))
292: if (isbin(r(x)))
293: emit(')')
294: return
295: }
296:
297:
298: if (IDENT (d, 'FCALL')) {
299: # function call or array reference
300: emit (name (x))
301: emit (l (x))
302: r = args (x)
303: while (DIFFER (r)) {
304: emit (del)
305: dprint (exp (r))
306: del = ','
307: r = next (r)
308: }
309: emit (r (x))
310: return
311: }
312:
313: if (IDENT (d, 'B')) {
314: # binary operator
315: op = op (x)
316: if (IDENT (op, or_binfo)) {
317: emit ('(')
318: bprint (x)
319: emit (')')
320: return
321: }
322: l = isbin(l(x)) && slp(op(l(x))) < srp(op) && 1 || ""
323: r = isbin(r(x)) && slp(op) > srp(op(r(x))) && 1 || ""
324:
325: # check for [f](a,b)
326: if (DIFFER (fn (op))) {
327: emit(out(op))
328: emit('(')
329: dprint(l(x))
330: emit(',')
331: dprint(r(x))
332: emit(')')
333: return
334: }
335:
336: # ordinary binary operator
337: if (DIFFER (l))
338: emit ('(')
339: dprint(l(x))
340: if (DIFFER (l))
341: emit (')')
342: emitb(out(op))
343: if (DIFFER(r))
344: emit('(')
345: dprint(r(x))
346: if (DIFFER(r))
347: emit(')')
348: return
349: }
350:
351: # unknown datatype -- this "shouldn't happen"
352: i = 1
353: emit(d)
354: emit ('(')
355: while (dprint (APPLY (FIELD (d, i), x))) {
356: i = i + 1
357: emit (',')
358: }
359: emit (')')
360: }
361:
362: # bprint(x)
363: # subroutine of dprint -- used to handle printing of
364: # things of the form (a,b), which are inherently
365: # associative and can therefore be grouped as follows
366: # ((a,b),c) <=> (a,(b,c)) <=> (a,b,c)
367: procedure bprint (x) {
368: if (DIFFER (DATATYPE(x), 'B') || DIFFER (op(x), or_binfo)) {
369: dprint (x)
370: return
371: }
372: bprint(l(x))
373: emit(',')
374: bprint(r(x))
375: }
376:
377: # sprint(x)
378: # like dprint, but print in a form appropriate for
379: # an entire statement. This procedure exists
380: # because if the top level operator is a concatenation,
381: # it is necessary to enclose the whole thing in parentheses.
382: # Otherwise it would be mistaken for a pattern match.
383: procedure sprint (x) {
384: if (IDENT(DATATYPE(x),'B') && IDENT(op(x),cat_binfo))
385: emit('(')
386: dprint(x)
387: if (IDENT(DATATYPE(x),'B') && IDENT(op(x),cat_binfo))
388: emit(')')
389: emiteob()
390: }
391:
392: # invoke(f)
393: # call an argument-free function in a context where
394: # a name is required, such as arb . *invoke(.foo)
395: procedure invoke (f) {
396: APPLY (f)
397: nreturn .dummy
398: }
399:
400: # a unary operator has been detected during parsing
401: procedure unop() r, op {
402: r = pop()
403: op = pop()
404: push() = u(op,r)
405: }
406:
407: # mkfcall()
408: # Parsing has detected the beginning of a function call
409: procedure mkfcall() {
410: push() = i_fcall()
411: nreturn .name(top())
412: }
413:
414: # parsing has detected an argument to a function
415: procedure mkarg() x, f {
416: x = argexp(pop(),"")
417: f = top()
418: if (DIFFER(tail(f)))
419: next(tail(f)) = x
420: tail(f) = x
421: head(f) = IDENT(head(f)) && x
422: }
423:
424: # parsing has detected the end of a function call
425: procedure endfc() f {
426: f = pop()
427: push() = fcall(name(f),head(f),'(',')')
428: }
429:
430: # the fcall at the head of the stack is really an array
431: procedure mkarray() t {
432: t = top()
433: l(t) = '<'
434: r(t) = '>'
435: }
436:
437: # the beginning of an expression has been detected
438: procedure begexp() {
439: push() = bconv['(']
440: nreturn .dummy
441: }
442:
443: # a binary operator has been detected. We handle
444: # precedence here rather than in the grammar
445: # because it is less work.
446: procedure binop() l, r, op, newr, newop {
447: while (lp(peek(3)) >= rp(peek(1))) {
448: newr = pop()
449: newop = pop()
450: r = pop()
451: op = pop()
452: l = pop()
453: push() = b(op,l,r)
454: push() = newop
455: push() = newr
456: }
457: }
458:
459: # the end of an expression has been detected
460: procedure endexp() l, r, op {
461: while (DIFFER (peek (1), par_binfo)) {
462: r = pop()
463: op = pop()
464: l = pop()
465: push() = b(op,l,r)
466: }
467: r = pop()
468: pop()
469: push() = r
470: nreturn .dummy
471: }
472:
473: # locate the binfo structure that describes the
474: # binary operator whose input character representation
475: # has been placed on the top of the stack.
476: procedure mkbinfo() op {
477: op = bconv[pop()]
478: if (IDENT(op))
479: go to err
480: push() = op
481: }
482:
483: # dotck()
484: # if necessary, append a leading zero to a floating-point
485: # constant that begins with a decimal point. The idea
486: # that .5 is syntactically correct but semantically illegal
487: # is just too scary to leave in.
488: procedure dotck() {
489: top() ? FENCE && '.' = '0.'
490: nreturn .dummy
491: }
492:
493: # write label l to the output
494: procedure emitlab (l) {
495: if (DIFFER(l)) {
496: emiteos()
497: st_lab = l
498: }
499: nreturn .dummy
500: }
501:
502: # put string s in the output
503: procedure emit (s) {
504: if (DIFFER(emit_eob))
505: emiteos()
506: st_body = st_body && s
507: }
508:
509: # we are done with the body of the generated statement
510: procedure emiteob() {
511: if (IDENT (emit_eob)) {
512: buildstab (emit_stno, gi_file, gi_line)
513: emit_eob = 1
514: }
515: }
516:
517: # write success branch l
518: procedure emits (l) {
519: emiteob()
520: st_s = l
521: }
522:
523: # emitf(l)
524: # write failure branch l
525: procedure emitf (l) {
526: emiteob()
527: st_f = l
528: }
529:
530: # write unconditional branch l
531: procedure emitg (l) {
532: emiteob()
533: st_s = IDENT(st_s) && l
534: st_f = IDENT(st_f) && l
535: }
536:
537: # write s surrounded by blanks
538: procedure emitb (s) {
539: emit(' ')
540: if (DIFFER (s, ' ')) {
541: emit (s)
542: emit(' ')
543: }
544: }
545:
546: # emiteos()out,goto
547: # we are done with the entire statement
548: procedure emiteos() out, goto, s, del {
549: emit_eob = ""
550: if (DIFFER(st_lab) || DIFFER(st_body) || DIFFER(st_s) || DIFFER(st_f)) {
551: emit_stno = emit_stno + 1
552: out = st_lab && " " && st_body
553: if (DIFFER (st_s) || DIFFER (st_f)) {
554: goto = " :"
555: if (IDENT (st_s, st_f))
556: goto = goto && "(" && st_s && ")"
557: else {
558: if (DIFFER (st_s))
559: goto = goto && "S(" && st_s && ")"
560: if (DIFFER (st_f))
561: goto = goto && "F(" && st_f && ")"
562: }
563: }
564: out = out && goto
565: while (SIZE(out) >= 70 && (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 &&
706: (ARBNO(BREAK('"' && "'") && LEN(1) $ del && BREAK(*del) &&
707: LEN(1)) && BREAK('"' && "';")) . phrase && ';' = '')
708: return
709:
710: phrase = ph_buf
711: ph_buf = ''
712: }
713:
714: # return a new label
715: procedure newlab() {
716: nl_count = nl_count + 1
717: return "L." && nl_count
718: }
719:
720: # return a new label and place it on the current statement.
721: # If the current statement already has a label, use that.
722: procedure marklab() {
723: if (DIFFER (st_lab) && IDENT (emit_eob))
724: return st_lab
725: marklab = newlab()
726: emitlab (marklab)
727: }
728:
729: # little routines to indicate what type of clause was read
730:
731: # expression clause
732: procedure expcl() {
733: cl_type = "exp"
734: }
735:
736: # goto clause
737: procedure gocl() {
738: cl_type = "goto"
739: }
740:
741: # read a new clause and classify it
742: # if end of input, error unless "okeof" argument is non-null,
743: # in which case we merely fail
744: # if rep_clause is set, give us the last clause again
745: procedure nclause (okeof) del {
746: nclause_start:
747: if (DIFFER (rep_clause)) {
748: rep_clause = ""
749: if (IDENT (eof))
750: return
751: else
752: freturn
753: }
754: if (linebuf ? FENCE && *optblank && RPOS(0)) {
755: if (linebuf = phrase())
756: go to nclause_start
757:
758: # end of input
759: if (IDENT(okeof)) {
760: error ('premature EOF')
761: go to EXIT
762: }
763: eof = 1
764: freturn
765: }
766:
767: # we really have some input
768: if (linebuf ? clause = del)
769: return
770: error("syntax error")
771: linebuf = ""
772: go to nclause_start
773: }
774:
775: procedure error (msg) prefix {
776: if (IDENT (gl_file))
777: prefix = "snocone"
778: else
779: prefix = gl_file && "(" && gl_line && ")"
780: terminal = prefix && ": " && msg
781: &CODE = 1
782: }
783:
784: # handle a statement
785: procedure dostmt() lab, lab2, e1, e2, e3, flip {
786:
787: if (IDENT(cl_type,"exp")) {
788: # The clause is an expression,
789: # so that's the whole statement
790: sprint(pop())
791: return
792: }
793:
794: # It might be a sequence of statements in braces
795: if (IDENT(cl_type,"{")) {
796: nclause()
797: while (DIFFER (cl_type, "}")) {
798: dostmt()
799: nclause()
800: }
801: return
802: }
803:
804: # It might be a goto statement
805: if (IDENT (cl_type, "goto")) {
806: emitg (dest)
807: return
808: }
809:
810: # It might be an if statement
811: if (IDENT(cl_type,"if")) {
812: e1 = pop()
813:
814: # optimize "if (~expr)"
815: if (isneg (e1)) {
816: flip = 1
817: e1 = r(e1)
818: }
819:
820: sprint(e1)
821:
822: # Check for if(...)goto
823: nclause()
824: if (IDENT(cl_type,"goto")) {
825: if (IDENT (flip))
826: emits(dest)
827: else
828: emitf(dest)
829:
830: # In the case of if (e) goto l; else ...
831: # we can pretend the else wasn't there
832: if (~nclause(1) || DIFFER (cl_type, "else")) {
833: rep_clause = 1
834: emitlab (lab)
835: return
836: }
837: nclause()
838: dostmt()
839: return
840: }
841:
842: # Not if...goto, emit conditional jump over
843: # the statement which follows.
844: lab = newlab()
845: if (IDENT (flip))
846: emitf(lab)
847: else
848: emits(lab)
849: dostmt()
850:
851: # Check for else clause
852: if (nclause (1) && IDENT (cl_type, "else")) {
853:
854: # There is indeed an else clause
855: lab2 = newlab()
856: emitg(lab2)
857: emitlab(lab)
858: nclause()
859: dostmt()
860: emitlab(lab2)
861: return
862: }
863:
864: # No else clause; we must look at this clause again later
865: rep_clause = 1
866: emitlab(lab)
867: return
868: }
869:
870: # Check for a while clause
871: if (IDENT(cl_type,"while")) {
872: lab = marklab()
873:
874: # optimize "while(~exp)"
875: e1 = pop()
876: if (isneg (e1)) {
877: flip = 1
878: e1 = r(e1)
879: }
880:
881: sprint(e1)
882: lab2 = newlab()
883: if (IDENT (flip))
884: emitf(lab2)
885: else
886: emits(lab2)
887: nclause()
888: dostmt()
889: emitg(lab)
890: emitlab(lab2)
891: return
892: }
893:
894: # Check for a do clause
895: if (IDENT(cl_type,"do")) {
896: lab = marklab()
897: nclause()
898: dostmt()
899: nclause()
900: if (DIFFER(cl_type,"while")) {
901: error ("expected 'while', found " && cl_type)
902: rep_clause = 1
903: return
904: }
905: e1 = pop()
906: if (isneg (e1)) {
907: flip = 1
908: e1 = r (e1)
909: }
910: sprint(e1)
911: if (IDENT (flip))
912: emits (lab)
913: else
914: emitf (lab)
915: return
916: }
917:
918: # Check for a "for" clause
919: if (IDENT(cl_type,"for")) {
920: e3 = pop()
921: e2 = pop()
922: e1 = pop()
923: sprint(e1)
924: emiteob()
925: lab = marklab()
926: lab2 = newlab()
927: if (isneg (e2)) {
928: flip = 1
929: e2 = r (e2)
930: }
931: sprint(e2)
932: if (IDENT (flip))
933: emitf (lab2)
934: else
935: emits (lab2)
936: nclause()
937: dostmt()
938: sprint(e3)
939: emitg(lab)
940: emitlab(lab2)
941: return
942: }
943:
944: # could be some kind of return statement
945: if (cl_type ? "return") {
946: e1 = pop()
947: if (DIFFER(e1)) {
948: if (DIFFER(fname))
949: e1 = b(bconv["="],fname,e1)
950: sprint(e1)
951: }
952: emitg (REPLACE(cl_type,
953: "abcdefghijklmnopqrstuvwxyz",
954: "ABCDEFGHIJKLMNOPQRSTUVWXYZ"))
955: return
956: }
957:
958: # could even be a null statement
959: if (IDENT(cl_type))
960: return
961:
962: error("bad " && cl_type && " clause, ignored")
963: }
964:
965: # We have seen "struct" -- parse the 'declaration'
966: procedure dostruct() args {
967: if (expect ('{')) {
968: args = getlist ('}')
969: deflist[deflist[0] = deflist[0] + 1] =
970: "DATA('" && stname && "(" && args && ")')"
971: } else
972: error ("bad structure definition")
973: expect ('}')
974: }
975:
976: # We have seen "procedure" -- we must now parse the header
977: procedure funct() args, locals, flabel {
978: if (expect('(')) {
979: if (~(args = getlist(')')))
980: go to fu_error
981: expect(')')
982: if (~(locals = getlist('{')))
983: go to fu_error
984: }
985:
986: deflist[deflist[0] = deflist[0] + 1] =
987: "DEFINE('" && fname && '(' && args && ')' && locals && "')"
988:
989: # if we just emitted the end of a previous procedure,
990: # we can jump around this one in one go
991: if (IDENT (emit_eob) && st_lab ? ".END") {
992: flabel = st_lab
993: st_lab = ""
994: emitlab(fname)
995: nclause()
996: dostmt()
997: emitg("RETURN")
998: emitlab(flabel)
999: return
1000: }
1001:
1002: emitg(fname && '.END')
1003: emitlab(fname)
1004: nclause()
1005: dostmt()
1006: emitg("RETURN")
1007: emitlab(fname && '.END')
1008: return
1009:
1010: fu_error:
1011: error("bad function definition")
1012: }
1013:
1014: # the input should now contain something matching "p"
1015: # possibly surrounded by white space. If not, fail
1016: procedure expect (p) {
1017:
1018: # throw away blank lines
1019: while (linebuf ? FENCE && optblank && RPOS (0)) {
1020: if (~(linebuf = phrase()))
1021: freturn
1022: }
1023:
1024: # try to match the given pattern, possibly preceded by white space
1025: if (linebuf ? FENCE && optblank && *p = "")
1026: return
1027:
1028: # didn't match: fail
1029: freturn
1030: }
1031:
1032: # expect an identifier in the input; return it.
1033: procedure getid() {
1034: if (expect (*identifier . getid))
1035: return
1036: freturn
1037: }
1038:
1039: # expect a list of identifiers followed by tail
1040: procedure getlist (tail) del {
1041: getlist_start:
1042: if (expect(tail)) {
1043: linebuf = tail && linebuf
1044: return
1045: }
1046: if (getlist = getlist && del && getid()) {
1047: expect(',')
1048: del = ','
1049: go to getlist_start
1050: }
1051: if (expect(tail))
1052: return
1053: freturn
1054: }
1055:
1056: # This procedure is called once for each output statement.
1057: # It maintains the correspondence between Snocone and SNOBOL4
1058: # statements, which is inserted into the output for debugging.
1059: procedure buildstab (stmt, file, line) desc, pad {
1060: pad = DUPL ("?", stmt - bst_stmt - 1)
1061: bst_stab = bst_stab && pad
1062: if (IDENT (file, bst_file)) {
1063: if (DIFFER(pad) || line != bst_line + 1)
1064: desc = line
1065: } else
1066: desc = file && ":" && line
1067: bst_stab = bst_stab && desc && ","
1068: bst_stmt = stmt
1069: bst_file = file
1070: bst_line = line
1071: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.