def infixToPostfix(infixString): order = {"*": 3, "/": 3, "+": 2, "-": 2, "(": 1} operatorStack = Stack() postfixString = [] infixList = infixString.split() print infixList for infixEle in infixList: if infixEle in "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789": print "append %s to the output string" % infixEle postfixString.append(infixEle) elif infixEle == "(": print "push ( to the stack" operatorStack.push(infixEle) elif infixEle == ")": print "pop operator until see (" topOper = operatorStack.pop() while topOper != "(": print "pop %s until see (" % topOper postfixString.append(topOper) topOper = operatorStack.pop() else: while (not operatorStack.isEmpty()) and (order[operatorStack.peek()] >= order[infixEle]): print "pop out %s before push %s in" % (operatorStack.peek(), infixEle) postfixString.append(operatorStack.pop()) print "push %s in the stack" % infixEle operatorStack.push(infixEle) while not operatorStack.isEmpty(): postfixString.append(operatorStack.pop()) return postfixString
def parChecker(parString): s = Stack() for par in parString: if par == "(": s.push(par) else: if s.isEmpty(): return False else: s.pop() return s.isEmpty()
def postfixEva(postfixString): operandStack = Stack() postfixList = postfixString.split(" ") print postfixList for postfixEle in postfixList: if postfixEle in "0123456789": print "push %s in the operand stack." % postfixEle operandStack.push(postfixEle) else: operand2 = operandStack.pop() operand1 = operandStack.pop() mathResult = mathCal(postfixEle, int(operand1), int(operand2)) print "calculate %s %s %s and push the result %s in the operand stack" %(operand1, postfixEle, operand2, mathResult) operandStack.push(mathResult) return operandStack.pop()
def search_address_of(self, token: Token, block_number_stack: Stack) -> int: """심볼 테이블에서 변수의 주소를 검색하는 메서드 Args: token: 검색할 토큰 block_number_stack: 해당 토큰이 속한 블록 스택 Returns: 심볼 테이블에서 탐색한 변수의 주소 Raises: NoVariableDeclarationError: 선언되지 않은 변수를 사용할 때 발생한다. """ while True: block_number = block_number_stack.pop() search_result = self._symbol_table[ self._symbol_table['identifier'] == token.token_string and self._symbol_table['block_number'] == block_number] if len(search_result) > 1: # 같은 범위에 같은 식별자의 변수가 중복됨. raise RuntimeError("Compiler >> redundant variable") elif len(search_result) == 1: # 찾은 경우 return search_result[0][4] else: # 찾지 못한 경우 if not block_number_stack.is_empty(): # 스택에 블록 넘버가 남은 경우 continue else: # 스택이 빈 경우 -> 정의된 변수가 없음 raise NoVariableDeclarationError(self._source_code, token)
def revString(item): astack = Stack() revstring = "" for i in item: astack.push(i) for j in range(len(item)): revstring += astack.pop() return revstring
def DecimalToBinary(decNum): binString = "" binStack = Stack() while decNum > 0: binNum = decNum % 2 binStack.push(binNum) decNum = decNum // 2 while not binStack.isEmpty(): binString += str(binStack.pop()) return binString
def DecimalToBase(decNum, base): system = "0123456789ABCDEF" baseString = "" baseStack = Stack() while decNum > 0: baseNum = decNum % base baseStack.push(baseNum) decNum = decNum // base while not baseStack.isEmpty(): baseString += system[baseStack.pop()] return baseString
class SyntaxTree: """코드의 구문을 저장한 트리 구문 분석 단계의 결과로 생성된다. in 키워드로 반복문을 사용하면 preorder로 순회한다. 트리 예시) total prog $ word ( ) block 순서 예시) total - prog - word - ( - ) - block - $ """ def __init__(self): self._root: TokenNode = None self._parent_stack = Stack() self._current: TreeStackNode = None @property def root(self) -> TokenNode: return self._root @root.setter def root(self, token_node: TokenNode): self._root = token_node def __iter__(self): return self def __next__(self) -> TokenNode: if self._current is None: if self._root is not None: self._current = TreeStackNode(self._root) return self._current.token_node else: raise StopIteration while True: child = self._current.next_child() if self._current.token_node.get_child(child) is not None: self._parent_stack.push(self._current) self._current = TreeStackNode( self._current.token_node.get_child(child)) return self._current.token_node else: if not self._parent_stack.is_empty(): self._current = self._parent_stack.pop() continue else: self._current = None raise StopIteration
def symChecker(symString): s = Stack() for sym in symString: if sym in "({[": s.push(sym) else: if s.isEmpty(): return False else: matSym = s.pop() if not matchChecker(matSym,sym): return False return s.isEmpty()
def parseTreeBuilder(inputExpr): exprList = inputExpr.split(" ") parseTree = BinaryTree("") parentRoot = Stack() parentRoot.push(parseTree) currentRoot = parseTree for token in exprList: if token == "(": currentRoot.insertLeft("") parentRoot.push(currentRoot) currentRoot = currentRoot.getLeftChild() elif token not in ['+','-','*','/',')']: currentRoot.setRootVal(int(token)) currentRoot = parentRoot.pop() elif token in ['+','-','*','/']: currentRoot.setRootVal(token) currentRoot.insertRight("") parentRoot.push(currentRoot) currentRoot = currentRoot.getRightChild() elif token == ")": currentRoot = parentRoot.pop() else: raise ValueError return parseTree
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]
def Generate_code(Code): In = Instruction() result_Code = [] operater = ["*", "+", "==", ">", "="] # While block의 중첩을 구분하기 위함. whileStack = Stack() # block # 구분하기 위함. blockStack = Stack() #연산자와 피연산자를 저장하기 위함 num = [] op = [] #현재 어느 Tree속에 들어와있는지 구분(WHILE, IF, THEN, ELSE, RETURN, block) current_state = "" #WHILE LABEL에 숫자를 붙이기 위함 While_num = 0 #IF LABEL에 숫자를 붙이기 위함 if_num = 0 #LABEL <block_num : while/if_num> block_num = 0 register_num = 0 for token in Code: num1 = 0 num2 = 0 if token.token.token == "WHILE": While_num += 1 current_state = "WHILE" whileStack.push(token.token.token) result_Code.append(f"WHILE <{block_num+ 1 } : {While_num}> : ") elif token.token.token == "IF": current_state = "IF" if_num += 1 result_Code.append(f"IF <{block_num} : {if_num}> : ") elif token.token.token == "RETURN": current_state = "RETURN" if token.token.token == "block": block_num += 1 blockStack.push(block_num) elif token.token.token == "}": block_num = blockStack.pop() if current_state == 'block' and not whileStack.is_empty(): result_Code.append(f"END_WHILE <{block_num } : {While_num}> :") While_num -= 1 whileStack.pop() #WHILE로 시작할 경우 if current_state == "WHILE": #연산자, 피연산자 저장 if token.token.token == "num" or token.token.token == "word": result_Code.append( In.LD("R" + str(register_num), token.token.token_string)) num.append("R" + str(register_num)) register_num += 1 if token.token.token in operater: op.append(token.token.token) # 조건 부분이 끝나면 연산 시작 if token.token.token == "block": current_state = "block" op.reverse() num.reverse() # 피연산자와 연산자 LIST의 길이를 보고 연산을 반복한다. while len(num) - 1 != 0 and len(op) != 0: num1 = num[0] num2 = num[1] if op[0] == "==": result_Code.extend(In.Operater(num1, num2, op[0])) else: result_Code.append(In.Operater(num1, num2, op[0])) del num[0] num[0] = num2 del op[0] result_Code.append( In.JUMPF(num[0], f"END_WHILE <{block_num} : {While_num}>")) # 한 block, cond에 관해 연산이 끝나면 num list와 op list는 모두 비운 뒤 다른 연산에 들어간다. del num[0] if current_state == "block": if token.token.token == "num" or token.token.token == "word": result_Code.append( In.LD("R" + str(register_num), token.token.token_string)) num.append("R" + str(register_num)) register_num += 1 if token.token.token in operater: op.append(token.token.token) if token.token.token == ";": op.reverse() num.reverse() while len(num) - 1 != 0 and len(op) != 0: num1 = num[0] num2 = num[1] if op[0] == "==": result_Code.extend(In.Operater(num1, num2, op[0])) else: result_Code.append(In.Operater(num1, num2, op[0])) del num[0] num[0] = num2 del op[0] del num[0] result_Code.append( In.JUMP(f"WHILE <{block_num} : {While_num}>")) #if로 시작할 경우" if current_state == "IF": if token.token.token == "num" or token.token.token == "word": result_Code.append( In.LD("R" + str(register_num), token.token.token_string)) num.append("R" + str(register_num)) register_num += 1 if token.token.token in operater: op.append(token.token.token) if token.token.token == "THEN": current_state = "THEN" op.reverse() num.reverse() while len(num) - 1 != 0 and len(op) != 0: num1 = num[0] num2 = num[1] if op[0] == "==": result_Code.extend(In.Operater(num1, num2, op[0])) else: result_Code.append(In.Operater(num1, num2, op[0])) del num[0] num[0] = num2 del op[0] result_Code.append( In.JUMPF(num[0], f"ELSE <{block_num} : {if_num}> : ")) del num[0] if current_state == "THEN": if token.token.token == "num" or token.token.token == "word": result_Code.append( In.LD("R" + str(register_num), token.token.token_string)) num.append("R" + str(register_num)) register_num += 1 if token.token.token in operater: op.append(token.token.token) if token.token.token == "ELSE": current_state = "ELSE" op.reverse() num.reverse() while len(num) - 1 != 0 and len(op) != 0: num1 = num[0] num2 = num[1] if op[0] == "==": result_Code.extend(In.Operater(num1, num2, op[0])) else: result_Code.append(In.Operater(num1, num2, op[0])) del num[0] num[0] = num2 del op[0] result_Code.append(f"ELSE <{block_num} : {if_num}> : ") del num[0] if current_state == "ELSE": if token.token.token == "num" or token.token.token == "word": result_Code.append( In.LD("R" + str(register_num), token.token.token_string)) num.append("R" + str(register_num)) register_num += 1 if token.token.token in operater: op.append(token.token.token) if token.token.token == "}": op.reverse() num.reverse() while len(num) - 1 != 0 and len(op) != 0: num1 = num[0] num2 = num[1] if op[0] == "==": result_Code.extend(In.Operater(num1, num2, op[0])) else: result_Code.append(In.Operater(num1, num2, op[0])) del num[0] num[0] = num2 del op[0] del num[0] result_Code.append(f"ENDIF <{block_num} : {if_num}> : ") #RETURN으로 시작할 경우 if current_state == "RETURN": if token.token.token == "num" or token.token.token == "word": result_Code.append( In.LD("R" + str(register_num), token.token.token_string)) num.append("R" + str(register_num)) register_num += 1 if token.token.token in operater: op.append(token.token.token) if token.token.token == ";": current_state = "block" op.reverse() num.reverse() while len(num) - 1 != 0 and len(op) != 0: num1 = num[0] num2 = num[1] if op[0] == "==": result_Code.extend(In.Operater(num1, num2, op[0])) else: result_Code.append(In.Operater(num1, num2, op[0])) del num[0] num[0] = num2 del op[0] result_Code.append(In.ADD("RV", "ZERO", num[0])) del num[0] file_writer = FileWriter(file_path.split("/")[0] + "/targetCode.code") for i in result_Code: file_writer.write(i) file_writer.write("\n") print(i)
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)