Esempio n. 1
0
    def parse(self) -> list:
        """Scanner로부터 받아온 Token들을 parse하는 메서드

        최초 기호와 마지막 기호가 담긴 stack과 Token들이 담긴 queue를 이용하여
        PARSING_TABLE에 따라 parse한다.
        LL parser의 원리를 사용한다.

        Returns: SyntaxTree, SymbolTable로 구성된 list를 반환한다.

        Raises:
            NoSemiColonError: 세미 콜론이 있어야할 위치에 없을 때 발생한다.
            NotDefinedCompileError: 에러를 파악할 수 없을 때 발생한다.
            RedundantVariableDeclarationError: 심볼 테이블에 이미 같은 식별자, 블록 넘버의 심볼이 있을 때 발생한다.
            RuntimeError: 심볼 테이블에 int, char 이외의 변수가 입력되는 경우 발생한다.
        """
        # Symbol Table
        symbol_table = SymbolTable(self._source_code)

        # 변수의 타입 기록
        vtype = None

        # 현재 word가 변수 선언할 때의 식별자인지 기록
        is_decl_var = False

        # Syntax Tree
        syntax_tree = SyntaxTree()

        # syntax tree에서 현재 접근 중인 노드의 스택 노드
        current_stack_node: TreeStackNode = None

        # syntax tree에서 현재 접근 중인 노드의 부모 스택
        parent_stack = Stack()

        # error handling을 위해 token이 담긴 queue에서 꺼낸 token들을 저장하는 stack
        used_token_stack = Stack()

        # symbol을 관리할 stack
        stack = Stack()

        stack.push(Parser.END_SYMBOL)
        stack.push(Parser.START_SYMBOL)

        root_node = TreeStackNode(
            TokenNode(Token(Parser.TOTAL_SYMBOL, None, None, 0)))
        root_node.token_node.add_child(
            Token(Parser.START_SYMBOL, None, None, 0))
        root_node.token_node.add_child(Token(Parser.END_SYMBOL, None, None, 0))
        syntax_tree.root = root_node.token_node
        parent_stack.push(root_node)
        current_stack_node = TreeStackNode(
            root_node.token_node.get_child(root_node.next_child()))

        self._token_queue.enqueue(Token(Parser.END_SYMBOL, "", 0, 0))

        log(f"queue : {self._token_queue}")
        log(f"stack : {stack}")
        log(f"work  : start\n")

        try:
            while not stack.is_empty():
                for tree_stack_node in parent_stack:
                    log(f"stack node : {tree_stack_node.token_node.token}")
                for token_node in syntax_tree:
                    log(f"node : {token_node.token} '{token_node.token.token_string}'"
                        )

                log(f"current node : {current_stack_node.token_node.token}")

                if self._token_queue.get().token == stack.get():
                    # 기호가 같을 때 pop
                    token = self._token_queue.dequeue()
                    used_token_stack.push(token)
                    stack.pop()

                    # 토큰이 데이터 타입인 경우, 기록한다
                    if token.token == 'int' or token.token == 'char':
                        vtype = token.token
                    # 토큰이 세미 콜론인 경우, 심볼 테이블에 추가하는 것을 그만둔다.
                    elif token.token == ';':
                        is_decl_var = False
                    # 토큰이 word인 경우,
                    elif is_decl_var and token.token == 'word':
                        symbol_table.add_symbol(token, vtype)

                    # syntax tree의 현재 접근 중인 노드를 queue에서 빠진 token로 교체한다.
                    current_stack_node.token_node.token = token

                    # 부모로 올라가 다음 child로 이동한다.
                    if not token.token == Parser.END_SYMBOL:
                        while True:
                            current_stack_node = parent_stack.pop()
                            next_child = current_stack_node.token_node.get_child(
                                current_stack_node.next_child())

                            if next_child is not None:
                                parent_stack.push(current_stack_node)
                                current_stack_node = TreeStackNode(next_child)
                                break

                    log(f"queue : {self._token_queue}")
                    log(f"stack : {stack}")
                    log(f"work  : pop\n")
                else:
                    # 기호가 다를 땐 확장
                    symbol = stack.pop()
                    next_symbols = Parser.PARSING_TABLE[symbol][
                        self._token_queue.get().token]

                    # 기호가 decl인 경우, 변수 선언으로 간주하고 앞으로 나오는 word들을 심볼 테이블에 추가한다.
                    if symbol == 'decl':
                        is_decl_var = True

                    if next_symbols[0] != 'e':
                        # e는 엡실론으로 추가하지 않는다.
                        # 역순으로 stack에 추가한다.
                        for i in range(-1, -(len(next_symbols) + 1), -1):
                            stack.push(next_symbols[i])

                        # 원래 순서로 syntax tree의 현재 접근 중인 노드의 child로 추가한다.
                        for i in range(0, len(next_symbols)):
                            current_stack_node.token_node.add_child(
                                Token(next_symbols[i], None, None, 0))

                        # 부모 스택에 현재 스택 노드를 추가한 후 첫번째 child로 이동
                        parent_stack.push(current_stack_node)
                        current_stack_node = TreeStackNode(
                            current_stack_node.token_node.get_child(
                                current_stack_node.next_child()))
                    else:
                        # 부모로 올라가 다음 child로 이동한다.
                        while True:
                            current_stack_node = parent_stack.pop()
                            next_child = current_stack_node.token_node.get_child(
                                current_stack_node.next_child())

                            if next_child is not None:
                                parent_stack.push(current_stack_node)
                                current_stack_node = TreeStackNode(next_child)
                                break

                    log(f"queue : {self._token_queue}")
                    log(f"stack : {stack}")
                    log(f"work  : {symbol} -> {next_symbols}\n")
        except KeyError:
            for token in self._token_queue:
                pass

            # stack에 남은 다음 token이 세미 콜론이면 세미 콜론이 있어야할 곳에 없는 것으로 판정한다.
            if stack.get() == ';':
                raise NoSemiColonError(self._source_code,
                                       used_token_stack.get())

            raise NotDefinedCompileError()

        return [syntax_tree, symbol_table]
Esempio n. 2
0
def Syntax_tree_Optimization(syntax_tree):
    Code = []

    TreeStack = Stack()
    block_num = 0

    for token in syntax_tree:
        if token.token.token == "total":
            TreeStack.push(token.token.token)

        if token.token.token == "block" and TreeStack.get() == "total":
            block_num += 1
            TreeStack.push(token.token.token)
            Code.append(token)

        if token.token.token == "}":
            Code.append(token)
            block_num -= 1
            while TreeStack.get() != "block":
                if TreeStack.get() == "total":
                    break
                TreeStack.pop()
            TreeStack.pop()

            if not TreeStack.is_empty() and TreeStack.get() == "WHILE":
                TreeStack.pop()
            if not TreeStack.is_empty() and TreeStack.get() == "ELSE":
                TreeStack.pop()
                TreeStack.pop()
                TreeStack.pop()

        if TreeStack.is_empty():
            continue
        elif TreeStack.get() == "stat":
            if token.token.token == "WHILE" or token.token.token == "IF" or token.token.token == "RETURN":
                Code.append(token)
                TreeStack.push(token.token.token)
            if token.token.token == "word":
                Code.append(token)
                TreeStack.push(token.token.token)

        elif TreeStack.get() == "WHILE":
            if token.token.token == "cond":
                Code.append(token)
                TreeStack.push(token.token.token)

        elif TreeStack.get() == "cond":
            if token.token.token != "block" and token.token.token != "THEN":
                if token.token.token_string is not None:
                    Code.append(token)
            if token.token.token == "block":
                TreeStack.pop()
                block_num += 1
                Code.append(token)
                TreeStack.push(token.token.token)
            if token.token.token == "THEN":
                TreeStack.pop()
                Code.append(token)
                TreeStack.push(token.token.token)

        elif TreeStack.get() == "block":
            if token.token.token == "stat":
                TreeStack.push(token.token.token)

        elif TreeStack.get() == "IF":
            if token.token.token == "cond":
                Code.append(token)
                TreeStack.push(token.token.token)

        elif TreeStack.get() == "IF":
            if token.token.token == "cond":
                Code.append(token)
                TreeStack.push(token.token.token)

        elif TreeStack.get() == "THEN":
            if token.token.token == "block":
                block_num += 1
                Code.append(token)
                TreeStack.push(token.token.token)
            if token.token.token == "ELSE":
                Code.append(token)
                TreeStack.push(token.token.token)

        elif TreeStack.get() == "ELSE":
            if token.token.token == "block":
                block_num += 1
                Code.append(token)
                TreeStack.push(token.token.token)

        elif TreeStack.get() == 'word':
            if token.token.token == ";":
                Code.append(token)
                TreeStack.pop()
                continue
            if token.token.token_string is not None:
                Code.append(token)

        elif TreeStack.get() == "RETURN":
            if token.token.token == ";":
                Code.append(token)
                TreeStack.pop()
                if TreeStack.get() == "stat":
                    TreeStack.pop()
                continue
            if token.token.token_string is not None:
                Code.append(token)
    Generate_code(Code)