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