Annotation of researchv10no/cmd/snocone/snocone.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: 
                      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: }

unix.superglobalmegacorp.com

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