PL\0 컴파일링 원리 실험(남항)5: 실험 코드, PL\0 코드, 중간 코드의 상세한 설명

23879 단어 컴파일링 원리
원리 실험의 마지막 부분을 컴파일하여 실험 코드, PL\0 코드, 중간 코드의 상세한 설명을 드립니다.
매일 저녁에 몇 십 분에서 몇 시간씩 쉬지 않고 일했는데, 중간에 잔업으로 며칠 동안 꾸물거렸는데, 이로써 마침내 완성된 셈이다!

PL\0 코드

program id;
const m:=7, n:=85;
var x,y,z,q,r;
procedure multiply;
    var a,b;
    begin
        a:=x; b:=y; z:=0;
        while b>0 do
            begin
                if odd b then z:=z+a;
                    a:=2*a; b:=b/2
            end
    end
begin
    x:=m; y:=n;
    call multiply
end

컴파일 원리 실험 코드

import sys


#       ,                 
def error(line_num, message):
    print('   ' + str(line_num) + '      :' + message)


'''                           token'''
key_word = ['program', 'const', 'var', 'procedure', 'begin', 'end', 'if', 'then', 'while', 'do', 'call', 'read',
            'write']  #       
symbol = ['+', '-', '*', '/', '(', ')', '=', ',', ';']  #        
token_list = []
token_index = 0


#             ,         、     ,       
def deal_word(word, line_num):
    length = len(word)
    index = 0
    while index < length:
        token = dict()
        value = ''  # token  
        attribute = ''  # token   
        if word[index].isalpha():  #             
            while index < length and (word[index].isalpha() or word[index].isdigit()):
                value += word[index]
                index += 1
            if value in key_word:  #         
                attribute = 'keyword'
            else:
                attribute = 'identifier'
        elif word[index].isdigit():  #        
            while index < length and word[index].isdigit():
                value += word[index]
                index += 1
            value = int(value)
            attribute = 'number'
        elif word[index] == ':':  # :       :=
            value += word[index]
            index += 1
            if index < length and word[index] == '=':
                value += word[index]
                index += 1
            attribute = value
        elif word[index] == '
            value += word[index]
            index += 1
            if index < length and (word[index] == '=' or word[index] == '>'):
                value += word[index]
                index += 1
            attribute = value
        elif word[index] == '>':  # >   > >=
            value += word[index]
            index += 1
            if index < length and word[index] == '=':
                value += word[index]
                index += 1
            attribute = value
        elif word[index] in symbol:  #        
            value = word[index]
            attribute = word[index]
            index += 1
        else:
            print('  ' + str(line_num) + ':    ' + word[index])
            sys.exit(0)
        #    token 
        token['value'] = value
        token['line_num'] = line_num
        token['attribute'] = attribute
        token_list.append(token)


#         token
def get_token():
    global token_index
    if token_index >= len(token_list):
        sys.exit(0)
    token = token_list[token_index]
    token_index += 1
    return token


'''          '''
table_list = []  #    
mid_code = []  #       
level = 0  #     ,          1
address = 0  #                  ,     level                          
dx = 3  #                    3 SL DL RA


#      ,
def record_table(name, kind, value=None, level=None, address=None, size=None):
    table = dict()
    table['name'] = name
    table['kind'] = kind
    table['value'] = value
    table['level'] = level
    table['address'] = address
    table['size'] = size
    table_list.append(table)


#       
def emit(f, l, a):
    operation = dict()
    operation['F'] = f
    operation['L'] = l
    operation['A'] = a
    mid_code.append(operation)


#                 
def find_table(val):
    index = 0
    for var in table_list:
        if var['name'] == val:
            return index
        index += 1
    return -1


#  → program 
def prog():
    token = get_token()
    if token['value'] == 'program':  #       program
        token = get_token()
        if token['attribute'] == 'identifier':  #         
            token = get_token()
            if token['value'] == ';':  #            block  
                block()
            else:
                error(token['line_num'], '    ;')
        else:
            error(token['line_num'], '    ,      ')
    else:
        error(token['line_num'], '  program   ')


#  → [][][]
#      ;                  ,  condecl vardecl proc block     
def block():
    global dx
    global level
    global mid_code
    global token_index
    dx = 3  #              block          SL DL RA
    #   block               
    #      block         ,           ,     body  , body    
    #                    ,          ,   cx1    jmp         
    cx1 = len(mid_code)  # cx1  jmp              
    emit('JMP', 0, 0)
    token = get_token()
    if token['value'] == 'const':  #        → const {,};
        const()
        token = get_token()
        while token['value'] == ',':
            const()
            token = get_token()
        if token['value'] == ';':
            token = get_token()
        else:
            error(token['line_num'], '  ;')
    if token['value'] == 'var':  #        → var {,};
        token = get_token()
        if token['attribute'] == 'identifier':  #                dx          
            record_table(token['value'], 'VARIABLE', level=level, address=dx)
            dx += 1
            token = get_token()
        else:
            error(token['line_num'], 'var        ')
        while token['value'] == ',':
            token = get_token()
            if token['attribute'] == 'identifier':
                record_table(token['value'], 'VARIABLE', level=level, address=dx)
                dx += 1
                token = get_token()
                continue
        if token['value'] == ';':
            token = get_token()
        else:
            error(token['line_num'], '  ;')
    #    while            
    while token['value'] == 'procedure':  #       → procedure ([{,}]);{;}
        token = get_token()
        if token['attribute'] == 'identifier':
            record_table(token['value'], 'PROCEDURE', level=level, address=len(mid_code))
            token = get_token()
        else:
            error(token['line_num'], '         ')
        if token['value'] != ';':  #                          
            error(token['line_num'], '  ;')
            token_index -= 1
        #     block     block          level               
        level += 1  #   +1
        cur_dx = dx  #           
        block()
        level -= 1  #       
        dx = cur_dx  #           
        token = get_token()
        if token['value'] == ';':  #           proc
            token = get_token()
        else:
            break
    token_index -= 1  #                  
    #   body     block   jmp  
    ins = dict()
    ins['F'] = 'JMP'
    ins['L'] = 0
    ins['A'] = len(mid_code)  #        body      
    mid_code[cx1] = ins
    emit('INT', 0, dx)  #        body           SL DL RA     
    body()  #   body
    emit('OPR', 0, 0)  #        ,        


# :=
def const():
    token = get_token()
    variable = token['value']
    if token['attribute'] == 'identifier':  #                
        token = get_token()
        if token['value'] == ':=':
            token = get_token()
            if token['attribute'] == 'number':
                record_table(variable, 'CONSTANT', value=token['value'], level=level)
            else:
                error(token['line_num'], ':=       ')
        else:
            error(token['line_num'], '  :=')
    else:
        error(token['line_num'], '     ')


#  → begin {;}end
def body():
    global token_index
    token = get_token()
    if token['value'] != 'begin':
        error(token['line_num'], '  begin')
        token_index -= 1
    statement()
    token = get_token()
    while token['value'] == ';':  #   statement
        statement()
        token = get_token()
    if token['value'] != 'end':
        error(token['line_num'], '  end')
        token_index -= 1


#  := 
#                |if  then [else ]
#                |while  do 
#                |call ([{,}])
#                |
#                |read ({,})
#                |write ({,})
def statement():
    global token_index
    global level
    token = get_token()
    if token['value'] == 'end':  #                  ;      statement,       
        error(token['line_num'], ';    ')
        token_index -= 1
        return
    if token['attribute'] == 'identifier':  #  := 
        index = find_table(token['value'])
        if index == -1:
            error(token['line_num'], token['value'] + '   ')
        elif table_list[index]['kind'] != 'VARIABLE':
            error(token['line_num'], table_list[index]['name'] + '      ')
        token = get_token()
        if token['value'] != ':=':
            error(token['line_num'], '  :=')
            token_index -= 1  #       
        expression()
        if index != -1:  #         sto                                       
            emit('STO', level - table_list[index]['level'], table_list[index]['address'])
    elif token['value'] == 'if':  # if  then [else ]
        lexp()
        token = get_token()
        if token['value'] != 'then':
            error(token['line_num'], '     then')
            token_index -= 1
        cx2 = len(mid_code)  # cx2  jpc              
        emit('JPC', 0, 0)  # if    jpc   else        
        statement()
        #     if       else   
        ins = dict()
        ins['F'] = 'JPC'
        ins['L'] = 0
        ins['A'] = len(mid_code)  #        if        
        mid_code[cx2] = ins
        token = get_token()
        if token['value'] == 'else':  #       
            cx1 = len(mid_code)
            emit('JMP', 0, 0)
            statement()
            #     if       
            ins = dict()
            ins['F'] = 'JMP'
            ins['L'] = 0
            ins['A'] = len(mid_code)  #        if        
            mid_code[cx1] = ins
        else:
            token_index -= 1  #      
        #     if       
    elif token['value'] == 'while':  # while  do 
        jmp_addr = len(mid_code)  #     while                        
        lexp()
        token = get_token()
        #         
        if token['value'] != 'do':
            error(token['line_num'], '  do   ')
            token_index -= 1
        cx2 = len(mid_code)  # cx2  jpc              
        emit('JPC', 0, 0)  # if    jpc   else        
        statement()
        #     jmp        
        emit('JMP', 0, jmp_addr)
        #   jpc  
        ins = dict()
        ins['F'] = 'JPC'
        ins['L'] = 0
        ins['A'] = len(mid_code)  #        while       
        mid_code[cx2] = ins
    elif token['value'] == 'call':  # call ([{,}])
        token = get_token()
        if token['attribute'] != 'identifier':
            error(token['line_num'], '         ')
        else:
            index = find_table(token['value'])
            if index == -1:
                error(token['line_num'], token['value'] + '   ')
            elif table_list[index]['kind'] == 'PROCEDURE':
                emit('CAL', level - table_list[index]['level'], table_list[index]['address'])
            else:
                error(token['line_num'], token['value'] + '     ')
    else:  # body
        token_index -= 1
        body()


#   → [+|-]{}
def expression():
    global token_index
    token = get_token()
    if token['value'] == '+' or token['value'] == '-':
        term()
        if token['value'] == '-':  # -       
            emit('OPR', 0, 1)
    else:
        token_index -= 1  #   
        term()
    token = get_token()
    while token['value'] == '+' or token['value'] == '-':
        term()
        if token['value'] == '+':
            emit('OPR', 0, 2)
        elif token['value'] == '-':
            emit('OPR', 0, 3)
        token = get_token()
    token_index -= 1


#  {}
def term():
    global token_index
    factor()
    token = get_token()  #     
    while token['value'] == '*' or token['value'] == '/':
        factor()
        if token['value'] == '*':
            emit('OPR', 0, 4)
        elif token['value'] == '/':
            emit('OPR', 0, 5)
        token = get_token()
    token_index -= 1  #         


#  ||()
def factor():
    global token_index
    token = get_token()
    if token['attribute'] == 'identifier':  #         
        index = find_table(token['value'])
        if index == -1:  #       
            error(token['line_num'], token['value'] + '   ')
        else:
            if table_list[index]['kind'] == 'CONSTANT':  #   
                emit('LIT', 0, table_list[index]['value'])  #        
            elif table_list[index]['kind'] == 'VARIABLE':
                emit('LOD', level - table_list[index]['level'], table_list[index]['address'])  #  
            elif table_list[index]['kind'] == 'PROCEDURE':
                error(token['line_num'], table_list[index]['name'] + '    ,   ')
    elif token['attribute'] == 'number':  #     
        emit('LIT', 0, token['value'])
    elif token['attribute'] == '(':  #            
        expression()
        token = get_token()
        if token['attribute'] != ')':  #        
            error(token['line_num'], '     ')
            token_index -= 1  #      


#   |odd 
def lexp():
    global token_index
    token = get_token()
    if token['value'] == 'odd':
        expression()
        emit('OPR', 0, 6)  #     
    else:
        token_index -= 1  #            
        expression()
        token = get_token()
        if token['value'] != '=' and token['value'] != '<>' and token['value'] != '' and token['value'] != '>=':
            error(token['line_num'], '       ')
            token_index -= 1
        expression()
        if token['value'] == '=':
            emit('OPR', 0, 8)
        elif token['value'] == '<>':
            emit('OPR', 0, 9)
        elif token['value'] == '=':
            emit('OPR', 0, 11)
        elif token['value'] == '>':
            emit('OPR', 0, 12)
        elif token['value'] == '<=':
            emit('OPR', 0, 13)


#               
stack = [0 for i in range(0, 8000)]  #        0     SL DL RA


#      B   level    SL  
def get_sl(B, level):
    global stack
    res_B = B
    while level > 0:
        res_B = stack[res_B]
        level -= 1
    return res_B


#    
def interpreter():
    #            
    global stack
    B = 0  #      
    T = 0  #      
    I = None  #         
    P = 0  #             mid_code     
    #     
    I = mid_code[P]
    P += 1
    while P != 0:  # P 0                       
        if I['F'] == 'JMP':  #          
            P = I['A']
        elif I['F'] == 'JPC':
            if stack[T] == 0:  #     0   
                P = I['A']
            T -= 1  #               
        elif I['F'] == 'INT':
            T += I['A'] - 1  #     
        elif I['F'] == 'LOD':
            T += 1
            stack[T] = stack[get_sl(B, I['L']) + I['A']]
        elif I['F'] == 'STO':
            stack[get_sl(B, I['L']) + I['A']] = stack[T]
            T -= 1
        elif I['F'] == 'LIT':
            T += 1
            stack[T] = I['A']
        elif I['F'] == 'CAL':  #     
            T += 1
            stack[T] = get_sl(B, I['L'])
            stack[T + 1] = B
            stack[T + 2] = P
            B = T
            P = I['A']
        elif I['F'] == 'OPR':
            if I['A'] == 0:  #     
                T = B - 1
                P = stack[T + 3]
                B = stack[T + 2]
            elif I['A'] == 1:  #     
                stack[T] = -stack[T]
            elif I['A'] == 2:  #   
                T -= 1
                stack[T] = stack[T] + stack[T + 1]
            elif I['A'] == 3:  #   
                T -= 1
                stack[T] = stack[T] - stack[T + 1]
            elif I['A'] == 4:  #   
                T -= 1
                stack[T] = stack[T] * stack[T + 1]
            elif I['A'] == 5:  #   
                T -= 1
                stack[T] = int(stack[T] / stack[T + 1])
            elif I['A'] == 6:  # odd   
                stack[T] = stack[T] % 2
            elif I['A'] == 8:  # ==
                T -= 1
                stack[T] = stack[T] == stack[T + 1]
            elif I['A'] == 9:  # !=
                T -= 1
                stack[T] = stack[T] != stack[T + 1]
            elif I['A'] == 10:  # <
                T -= 1
                stack[T] = stack[T] < stack[T + 1]
            elif I['A'] == 11:  # >=
                T -= 1
                stack[T] = stack[T] >= stack[T + 1]
            elif I['A'] == 12:  # >
                T -= 1
                stack[T] = stack[T] > stack[T + 1]
            elif I['A'] == 13:  # <=
                T -= 1
                stack[T] = stack[T] <= stack[T + 1]
        I = mid_code[P]  #        
        if P == 0:
            break
        P += 1  #   P+1            


if __name__ == '__main__':
    #        ,           ,         、  、  
    with open('code.txt', 'r') as file:
        line_num = 1
        for line in file.readlines():
            for word in line.strip().split():
                deal_word(word, line_num)
            line_num += 1
    #          ,        
    prog()  #  prog       
    #                 
    interpreter()

중간 코드 설명


위의 PL\0 코드에서 생성한 중간 코드
{'F': 'JMP', 'L': 0, 'A': 30}   #      
{'F': 'JMP', 'L': 0, 'A': 2}    #   multiply  
{'F': 'INT', 'L': 0, 'A': 5}    #   5   
{'F': 'LOD', 'L': 1, 'A': 3}    #  x     
{'F': 'STO', 'L': 0, 'A': 3}    #         a
{'F': 'LOD', 'L': 1, 'A': 4}    #  y     
{'F': 'STO', 'L': 0, 'A': 4}    #         b
{'F': 'LIT', 'L': 0, 'A': 0}    #    0    
{'F': 'STO', 'L': 1, 'A': 5}    #         z
{'F': 'LOD', 'L': 0, 'A': 4}    # while        b      
{'F': 'LIT', 'L': 0, 'A': 0}    #    0    
{'F': 'OPR', 'L': 0, 'A': 12}   #   b > 0  
{'F': 'JPC', 'L': 0, 'A': 29}   #          
{'F': 'LOD', 'L': 0, 'A': 4}    #  b     
{'F': 'OPR', 'L': 0, 'A': 6}    #           
{'F': 'JPC', 'L': 0, 'A': 20}   # if         
{'F': 'LOD', 'L': 1, 'A': 5}    #  z      
{'F': 'LOD', 'L': 0, 'A': 3}    #  a      
{'F': 'OPR', 'L': 0, 'A': 2}    #         
{'F': 'STO', 'L': 1, 'A': 5}    #         z
{'F': 'LIT', 'L': 0, 'A': 2}    #    2    
{'F': 'LOD', 'L': 0, 'A': 3}    #    a    
{'F': 'OPR', 'L': 0, 'A': 4}    #         
{'F': 'STO', 'L': 0, 'A': 3}    #         a
{'F': 'LOD', 'L': 0, 'A': 4}    #    b    
{'F': 'LIT', 'L': 0, 'A': 2}    #    2    
{'F': 'OPR', 'L': 0, 'A': 5}    #         
{'F': 'STO', 'L': 0, 'A': 4}    #         b
{'F': 'JMP', 'L': 0, 'A': 9}    #   while  
{'F': 'OPR', 'L': 0, 'A': 0}    #   multiply      
{'F': 'INT', 'L': 0, 'A': 8}    #         
{'F': 'LIT', 'L': 0, 'A': 7}    #   7    
{'F': 'STO', 'L': 0, 'A': 3}    #        x
{'F': 'LIT', 'L': 0, 'A': 85}   #   85    
{'F': 'STO', 'L': 0, 'A': 4}    #         y
{'F': 'CAL', 'L': 0, 'A': 1}    #       
{'F': 'OPR', 'L': 0, 'A': 0}    #      

좋은 웹페이지 즐겨찾기