Annotation of researchv10no/cmd/snocone/oosnocone.sc, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.