예제 #1
0
def simpleExpression():
    if SC.sym == PLUS:
        getSym()
        x = term()
    elif SC.sym == MINUS:
        getSym()
        x = term()
        if x.tp != Int: mark('bad type')
        elif type(x) == Const: x.val = -x.val  # constant folding
        else: x = CG.genUnaryOp(MINUS, x)
    else: x = term()
    while SC.sym in {PLUS, MINUS, OR}:
        op = SC.sym
        getSym()
        if op == OR and type(x) != Const: x = CG.genUnaryOp(OR, x)
        y = term()  # x op y
        if x.tp == Int == y.tp and op in {PLUS, MINUS}:
            if type(x) == Const == type(y):  # constant folding
                if op == PLUS: x.val = x.val + y.val
                elif op == MINUS: x.val = x.val - y.val
            else: x = CG.genBinaryOp(op, x, y)
        elif x.tp == Bool == y.tp and op == OR:
            if type(x) == Const:  # constant folding
                if not x.val: x = y  # if x is false, take y, else x
            else: x = CG.genBinaryOp(OR, x, y)
        else: mark('bad type')
    return x
예제 #2
0
def genActualPara(ap, fp, n):
    if type(fp) == Ref:  #  reference parameter, assume ap is Var
        if ap.lev == -2: asm.append('i32.const ' + str(ap.adr))
        # else ap.lev == -1, on stack already
    elif type(ap) in (Var, Ref, Const):
        loadItem(ap)
    else:
        mark('unsupported parameter type')
예제 #3
0
def genLocalVars(sc, start):
    for i in range(start, len(sc)):
        if type(sc[i]) == Var:
            if sc[i].tp in (Int, Bool):
                asm.append('(local $' + sc[i].name + ' i32)')
            elif type(sc[i].tp) in (Array, Record):
                mark('WASM: no local arrays, records')
            else:
                mark('WASM: type?')
    return None
예제 #4
0
def genGlobalVars(sc, start):
    global memsize
    for i in range(start, len(sc)):
        if type(sc[i]) == Var:
            if sc[i].tp in (Int, Bool):
                asm.append('(global $' + sc[i].name +
                           ' (mut i32) i32.const 0)')
            elif type(sc[i].tp) in (Array, Record):
                sc[i].lev, sc[
                    i].adr, memsize = -2, memsize, memsize + sc[i].tp.size
            else:
                mark('WASM: type?')
예제 #5
0
def genVar(x):
    # x is Var, Ref
    if 0 < x.lev < curlev: mark('WASM: level!')
    if type(x) == Ref:
        y = Ref(x.tp)
        y.lev, y.name = x.lev, x.name
        # if type(x.tp) in (Array, Record):
        #    if x.lev > 0: y.name = x.name
    elif type(x) == Var:
        y = Var(x.tp)
        y.lev, y.name = x.lev, x.name
        # if x.lev >= 0: y.name = x.name
        if x.lev == -2: y.adr = x.adr
    return y
예제 #6
0
def factor():
    if SC.sym not in FIRSTFACTOR:
        mark("expression expected")
        while SC.sym not in FIRSTFACTOR | FOLLOWFACTOR | STRONGSYMS:
            getSym()
    if SC.sym == IDENT:
        x = find(SC.val)
        if type(x) in {Var, Ref}:
            x = CG.genVar(x)
            getSym()
        elif type(x) == Const:
            x = Const(x.tp, x.val)
            x = CG.genConst(x)
            getSym()
        else:
            mark('expression expected')
        x = selector(x)
    elif SC.sym == NUMBER:
        x = Const(Int, SC.val)
        x = CG.genConst(x)
        getSym()
    elif SC.sym == LPAREN:
        getSym()
        x = expression()
        if SC.sym == RPAREN: getSym()
        else: mark(") expected")
    elif SC.sym == NOT:
        getSym()
        x = factor()
        if x.tp != Bool: mark('not boolean')
        elif type(x) == Const: x.val = 1 - x.val  # constant folding
        else: x = CG.genUnaryOp(NOT, x)
    else: x = Const(None, 0)
    return x
예제 #7
0
def genAssign(x, y):
    if type(x) == Var:
        if x.lev == -2: asm.append('i32.const ' + str(x.adr))
        loadItem(y)
        if x.lev == 0: asm.append('global.set $' + x.name)
        elif x.lev == curlev: asm.append('local.set $' + x.name)
        elif x.lev == -2: asm.append('i32.store')
        else: mark('WASM: level!')
    elif type(x) == Ref:
        if x.lev == curlev: asm.append('local.get $' + x.name)
        loadItem(y)
        asm.append('i32.store')
    else:
        assert False
예제 #8
0
def loadItem(x):
    if type(x) == Var:
        if x.lev == 0: asm.append('global.get $' + x.name)  # global Var
        elif x.lev == curlev: asm.append('local.get $' + x.name)  # local Var
        elif x.lev == -2:  # memory Var
            asm.append('i32.const ' + str(x.adr))
            asm.append('i32.load')
        elif x.lev != -1:
            mark('WASM: var level!')  # already on stack if lev == -1
    elif type(x) == Ref:
        if x.lev == -1: asm.append('i32.load')
        elif x.lev == curlev:
            asm.append('local.get $' + x.name)
            asm.append('i32.load')
        else:
            mark('WASM: ref level!')
    elif type(x) == Const:
        asm.append('i32.const ' + str(x.val))
예제 #9
0
def term():
    x = factor()
    while SC.sym in {TIMES, DIV, MOD, AND}:
        op = SC.sym
        getSym()
        if op == AND and type(x) != Const: x = CG.genUnaryOp(AND, x)
        y = factor()  # x op y
        if x.tp == Int == y.tp and op in {TIMES, DIV, MOD}:
            if type(x) == Const == type(y):  # constant folding
                if op == TIMES: x.val = x.val * y.val
                elif op == DIV: x.val = x.val // y.val
                elif op == MOD: x.val = x.val % y.val
            else: x = CG.genBinaryOp(op, x, y)
        elif x.tp == Bool == y.tp and op == AND:
            if type(x) == Const:  # constant folding
                if x.val: x = y  # if x is true, take y, else x
            else: x = CG.genBinaryOp(AND, x, y)
        else: mark('bad type')
    return x
예제 #10
0
def expression():
    x = simpleExpression()
    while SC.sym in {EQ, NE, LT, LE, GT, GE}:
        op = SC.sym
        getSym()
        y = simpleExpression()  # x op y
        if x.tp == y.tp in (Int, Bool):
            if type(x) == Const == type(y):  # constant folding
                if op == EQ: x.val = x.val == y.val
                elif op == NE: x.val = x.val != y.val
                elif op == LT: x.val = x.val < y.val
                elif op == LE: x.val = x.val <= y.val
                elif op == GT: x.val = x.val > y.val
                elif op == GE: x.val = x.val >= y.val
                x.tp = Bool
            else:
                x = CG.genRelation(op, x, y)
        else:
            mark('bad type')
    return x
예제 #11
0
def genUnaryOp(op, x):
    loadItem(x)
    if op == MINUS:
        asm.append('i32.const -1')
        asm.append('i32.mul')
        x = Var(Int)
        x.lev = -1
    elif op == NOT:
        asm.append('i32.eqz')
        x = Var(Bool)
        x.lev = -1
    elif op == AND:
        asm.append('if (result i32)')
        x = Var(Bool)
        x.lev = -1
    elif op == OR:
        asm.append('if (result i32)')
        asm.append('i32.const 1')
        asm.append('else')
        x = Var(Bool)
        x.lev = -1
    else:
        mark('WASM: unary operator?')
    return x
예제 #12
0
def genProcStart(ident, fp):
    global curlev
    if curlev > 0: mark('WASM: no nested procedures')
    curlev = curlev + 1
    asm.append('(func $' + ident + ' ' + ' '.join('(param $' + e.name + ' i32)'
                                                  for e in fp) + '')
    for p in fp:
        if p.tp in (Int, Bool) and type(p) == Ref:
            mark('WASM: only array and record reference parameters')
        elif type(p.tp) in (Array, Record) and type(p) == Var:
            mark('WASM: no structured value parameters')
예제 #13
0
def compoundStatement():
    if SC.sym == BEGIN: getSym()
    else: mark("'begin' expected")
    x = statement()
    while SC.sym == SEMICOLON or SC.sym in FIRSTSTATEMENT:
        if SC.sym == SEMICOLON: getSym()
        else: mark("; missing")
        y = statement()
        x = CG.genSeq(x, y)
    if SC.sym == END: getSym()
    else: mark("'end' expected")
    return x
예제 #14
0
def program():
    newDecl('boolean', Type(CG.genBool(Bool)))
    newDecl('integer', Type(CG.genInt(Int)))
    newDecl('true', Const(Bool, 1))
    newDecl('false', Const(Bool, 0))
    newDecl('read', StdProc([Ref(Int)]))
    newDecl('write', StdProc([Var(Int)]))
    newDecl('writeln', StdProc([]))
    newDecl('print', StdProc([Var(Int)]))
    CG.genProgStart()
    if SC.sym == PROGRAM: getSym()
    else: mark("'program' expected")
    ident = SC.val
    if SC.sym == IDENT: getSym()
    else: mark('program name expected')
    if SC.sym == SEMICOLON: getSym()
    else: mark('; expected')
    declarations(CG.genGlobalVars)
    CG.genProgEntry(ident)
    x = compoundStatement()
    return CG.genProgExit(x)
예제 #15
0
def typedIds(kind):
    if SC.sym == IDENT:
        tid = [SC.val]
        getSym()
    else:
        mark("identifier expected")
        tid = []
    while SC.sym == COMMA:
        getSym()
        if SC.sym == IDENT:
            tid.append(SC.val)
            getSym()
        else:
            mark('identifier expected')
    if SC.sym == COLON:
        getSym()
        tp = typ().val
        if tp != None:
            for i in tid:
                newDecl(i, kind(tp))
    else:
        mark("':' expected")
예제 #16
0
def declarations(allocVar):
    if SC.sym not in FIRSTDECL | FOLLOWDECL:
        mark("'begin' or declaration expected")
        while SC.sym not in FIRSTDECL | FOLLOWDECL | STRONGSYMS:
            getSym()
    while SC.sym == CONST:
        getSym()
        if SC.sym == IDENT:
            ident = SC.val
            getSym()
            if SC.sym == EQ: getSym()
            else: mark("= expected")
            x = expression()
            if type(x) == Const: newDecl(ident, x)
            else: mark('expression not constant')
        else: mark("constant name expected")
        if SC.sym == SEMICOLON: getSym()
        else: mark("; expected")
    while SC.sym == TYPE:
        getSym()
        if SC.sym == IDENT:
            ident = SC.val
            getSym()
            if SC.sym == EQ: getSym()
            else: mark("= expected")
            x = typ()
            newDecl(ident, x)  #  x is of type ST.Type
            if SC.sym == SEMICOLON: getSym()
            else: mark("; expected")
        else: mark("type name expected")
    start = len(topScope())
    while SC.sym == VAR:
        getSym()
        typedIds(Var)
        if SC.sym == SEMICOLON: getSym()
        else: mark("; expected")
    varsize = allocVar(topScope(), start)
    while SC.sym == PROCEDURE:
        getSym()
        if SC.sym == IDENT: getSym()
        else: mark("procedure name expected")
        ident = SC.val
        newDecl(ident, Proc([]))  #  entered without parameters
        sc = topScope()
        openScope()  # new scope for parameters and body
        if SC.sym == LPAREN:
            getSym()
            if SC.sym in {VAR, IDENT}:
                if SC.sym == VAR:
                    getSym()
                    typedIds(Ref)
                else:
                    typedIds(Var)
                while SC.sym == SEMICOLON:
                    getSym()
                    if SC.sym == VAR:
                        getSym()
                        typedIds(Ref)
                    else:
                        typedIds(Var)
            else:
                mark("formal parameters expected")
            fp = topScope()
            sc[-1].par = fp[:]  #  procedure parameters updated
            if SC.sym == RPAREN: getSym()
            else: mark(") expected")
        else: fp = []
        parsize = CG.genProcStart(ident, fp)
        if SC.sym == SEMICOLON: getSym()
        else: mark("; expected")
        localsize = declarations(CG.genLocalVars)
        CG.genProcEntry(ident, parsize, localsize)
        x = compoundStatement()
        CG.genProcExit(x, parsize, localsize)
        closeScope()  #  scope for parameters and body closed
        if SC.sym == SEMICOLON: getSym()
        else: mark("; expected")
    return varsize
예제 #17
0
def typ():
    if SC.sym not in FIRSTTYPE:
        mark("type expected")
        while SC.sym not in FIRSTTYPE | FOLLOWTYPE | STRONGSYMS:
            getSym()
    if SC.sym == IDENT:
        ident = SC.val
        x = find(ident)
        getSym()
        if type(x) == Type: x = Type(x.val)
        else:
            mark('not a type')
            x = Type(None)
    elif SC.sym == ARRAY:
        getSym()
        if SC.sym == LBRAK: getSym()
        else: mark("'[' expected")
        x = expression()
        if SC.sym == PERIOD: getSym()
        else: mark("'.' expected")
        if SC.sym == PERIOD: getSym()
        else: mark("'.' expected")
        y = expression()
        if SC.sym == RBRAK: getSym()
        else: mark("']' expected")
        if SC.sym == OF: getSym()
        else: mark("'of' expected")
        z = typ().val
        if type(x) != Const or x.val < 0:
            mark('bad lower bound')
            x = Type(None)
        elif type(y) != Const or y.val < x.val:
            mark('bad upper bound')
            x = Type(None)
        else:
            x = Type(CG.genArray(Array(z, x.val, y.val - x.val + 1)))
    elif SC.sym == RECORD:
        getSym()
        openScope()
        typedIds(Var)
        while SC.sym == SEMICOLON:
            getSym()
            typedIds(Var)
        if SC.sym == END: getSym()
        else: mark("'end' expected")
        r = topScope()
        closeScope()
        x = Type(CG.genRec(Record(r)))
    else:
        x = Type(None)
    return x
예제 #18
0
def selector(x):
    while SC.sym in {PERIOD, LBRAK}:
        if SC.sym == PERIOD:  #  x.f
            getSym()
            if SC.sym == IDENT:
                if type(x.tp) == Record:
                    for f in x.tp.fields:
                        if f.name == SC.val:
                            x = CG.genSelect(x, f)
                            break
                    else:
                        mark("not a field")
                    getSym()
                else:
                    mark("not a record")
            else:
                mark("identifier expected")
        else:  #  x[y]
            getSym()
            y = expression()
            if type(x.tp) == Array:
                if y.tp == Int:
                    if type(y) == Const and \
                       (y.val < x.tp.lower or y.val >= x.tp.lower + x.tp.length):
                        mark('index out of bounds')
                    else:
                        x = CG.genIndex(x, y)
                else:
                    mark('index not integer')
            else:
                mark('not an array')
            if SC.sym == RBRAK: getSym()
            else: mark("] expected")
    return x
예제 #19
0
def statement():
    if SC.sym not in FIRSTSTATEMENT:
        mark("statement expected")
        getSym()
        while SC.sym not in FIRSTSTATEMENT | FOLLOWSTATEMENT | STRONGSYMS:
            getSym()
    if SC.sym == IDENT:
        x = find(SC.val)
        getSym()
        if type(x) in {Var, Ref}:
            x = CG.genVar(x)
            x = selector(x)
            if SC.sym == BECOMES:
                getSym()
                y = expression()
                if x.tp == y.tp in {Bool, Int}: x = CG.genAssign(x, y)
                else: mark('incompatible assignment')
            elif SC.sym == EQ:
                mark(':= expected')
                getSym()
                y = expression()
            else:
                mark(':= expected')
        elif type(x) in {Proc, StdProc}:
            fp, ap, i = x.par, [], 0  #  list of formals, list of actuals
            if SC.sym == LPAREN:
                getSym()
                if SC.sym in FIRSTEXPRESSION:
                    y = expression()
                    if i < len(fp):
                        if (type(fp[i]) == Var or type(y) == Var) and \
                           fp[i].tp == y.tp:
                            if type(x) == Proc:
                                ap.append(CG.genActualPara(y, fp[i], i))
                        else:
                            mark('illegal parameter mode')
                    else:
                        mark('extra parameter')
                    i = i + 1
                    while SC.sym == COMMA:
                        getSym()
                        y = expression()
                        if i < len(fp):
                            if (type(fp[i]) == Var or type(y) == Var) and \
                               fp[i].tp == y.tp:
                                if type(x) == Proc:
                                    ap.append(CG.genActualPara(y, fp[i], i))
                            else:
                                mark('illegal parameter mode')
                        else:
                            mark('extra parameter')
                        i = i + 1
                if SC.sym == RPAREN: getSym()
                else: mark("')' expected")
            if i < len(fp): mark('too few parameters')
            elif type(x) == StdProc:
                if x.name == 'read': x = CG.genRead(y)
                elif x.name == 'write': x = CG.genWrite(y)
                elif x.name == 'writeln': x = CG.genWriteln()
                elif x.name == 'print': x = CG.genPrint(y)
            else: x = CG.genCall(x, ap)
        else: mark("variable or procedure expected")
    elif SC.sym == BEGIN: x = compoundStatement()
    elif SC.sym == IF:
        getSym()
        x = expression()
        if x.tp == Bool: x = CG.genThen(x)
        else: mark('boolean expected')
        if SC.sym == THEN: getSym()
        else: mark("'then' expected")
        y = statement()
        if SC.sym == ELSE:
            if x.tp == Bool: y = CG.genElse(x, y)
            getSym()
            z = statement()
            if x.tp == Bool: x = CG.genIfElse(x, y, z)
        else:
            if x.tp == Bool: x = CG.genIfThen(x, y)
    elif SC.sym == WHILE:
        getSym()
        t = CG.genWhile()
        x = expression()
        if x.tp == Bool: x = CG.genDo(x)
        else: mark('boolean expected')
        if SC.sym == DO: getSym()
        else: mark("'do' expected")
        y = statement()
        if x.tp == Bool: x = CG.genWhileDo(t, x, y)
    else: x = None
    return x