1. 程式人生 > >130242014060-鄭佳敏-第2次實驗

130242014060-鄭佳敏-第2次實驗

哪些 代碼 {} 增加 需求分析 練習 畫出 全局 技術分享

一、實驗目的

  1.熟悉體系結構的風格的概念

  2.理解和應用管道過濾器型的風格。

  3、理解解釋器的原理

  4、理解編譯器模型

二、實驗環境

  硬件:

  軟件:Python或任何一種自己喜歡的語言

三、實驗內容

  1、實現“四則運算”的簡易翻譯器。

  結果要求:

  1)實現加減乘除四則運算,允許同時又多個操作數,如:2+3*5-6 結果是11

  2)被操作數為整數,整數可以有多位

  3)處理空格

  4)輸入錯誤顯示錯誤提示,並返回命令狀態“CALC”

加強練習:

1、有能力的同學,可以嘗試實現賦值語句,例如x=2+3*5-6,返回x=11。(註意:要實現解釋器的功能,而不是只是顯示)

2、嘗試實現自增和自減符號,例如x++

2、采用管道-過濾器(Pipes and Filters)風格實現解釋器

技術分享

圖2 管道-過濾器風格

技術分享

圖 3 編譯器模型示意圖

本實驗,實現的是詞法分析和語法分析兩個部分。

四、實驗步驟:

要求寫具體實現代碼,並根據實際程序,畫出程序的總體體系結構圖和算法結構圖。

總體結構圖參照體系結構風格。

算法結構圖如下:

技術分享

代碼:

INTEGER, PLUS, MINUS, MUL, DIV, LPAREN, RPAREN, EOF,VARIABLE,EQUALITY,INCREMENT,REDUCE = (
‘INTEGER‘, ‘PLUS‘, ‘MINUS‘, ‘MUL‘, ‘DIV‘, ‘LPAREN‘, ‘RPAREN‘, ‘EOF‘,‘VARIABLE‘,‘EQUALITY‘,‘INCREMENT‘,‘REDUCE‘)
# 定義一個全局的變量數組來保存“變量名”:值的鍵值對
variables = {}
# Token是標記
class Token(object):
def __init__(self,type,value):
self.type = type
self.value = value
# toString
def __str__(self):
return ‘Token({type},{value})‘.format(
type=self.type,
value = self.value
)

class Lexer(object):
# 詞法分析器
# 給每個詞打標記
# text為輸入的表達式
def __init__(self, text):
self.text = text
# pos為當前位置
self.pos = 0
# current_char為當前字符
self.current_char = self.text[self.pos]
# 取字符錯誤時調用的方法
def error(self):
# raise 拋出異常
raise Exception(‘Invalid Char‘)
#前進的方法,即取下一個字符
def advance(self):
# 往下走,取值
self.pos += 1
if self.pos > len(self.text) - 1:
self.current_char = None
else:
self.current_char = self.text[self.pos]

def variable(self):
# 變量處理
variable = ‘‘
while self.current_char is not None and self.current_char.isalpha():
variable = variable + self.current_char
# 往下走,取值
self.advance()
# 取值完畢後,將該變量存入字典中
if variable not in variables:
variables[variable] = None
return variable
def integer(self):
# 多位整數處理
result = ‘‘
while self.current_char is not None and self.current_char.isdigit():
result = result + self.current_char
# 往下走,取值
self.advance()
return int(result)
# 處理輸入時的非法空格
def deal_space(self):
# 循環遍歷,遇到空格則跳過,取下一個字符
while self.current_char is not None and self.current_char.isspace():
self.advance()

def get_next_token(self):
# 打標記:1)pos+1,2)返回Token(類型,數值)
while self.current_char is not None:
# 空格處理
if self.current_char.isspace():
self.deal_space()
# 數字處理(判斷是否為多位整數)
if self.current_char.isdigit():
return Token(INTEGER, self.integer())
# 加號處理Plus
if self.current_char == ‘+‘:
# # 判斷是自增還是加號
# if self.get_next_token() ‘+‘:
# self.advance()
# return Token(PLUS, ‘+‘)
self.advance()
return Token(PLUS, ‘+‘)
# 減號處理Minus
if self.current_char == ‘-‘:
self.advance()
return Token(MINUS, ‘-‘)
# 左括號
if self.current_char == ‘(‘:
self.advance()
return Token(LPAREN,‘(‘)
# 右括號
if self.current_char == ‘)‘:
self.advance()
return Token(RPAREN,‘)‘)
# 乘號
if self.current_char == ‘*‘:
self.advance()
return Token(MUL,‘*‘)
# 除號
if self.current_char == ‘/‘:
self.advance()
return Token(DIV,‘/‘)
# 若是判斷出字符則進入變量獲取的方法
if self.current_char.isalpha():
return Token(VARIABLE,self.variable())
# 等號
if self.current_char == ‘=‘:
self.advance()
return Token(EQUALITY,‘EQUALITY‘)
# # 自增
# if self.current_char == ‘++‘:
# self.advance()
# return Token(EQUALITY,‘EQUALITY‘)

# 其余均為非法字符
self.error()
# 取到None字符 返回一個空的Token 表示循環結束
return Token(EOF, None)

class Interpreter(object):
# 句法分析
# 語法樹
# 語法樹中的一個參數為詞法分析器Lexer
def __init__(self, lexer):
self.lexer = lexer
self.current_token = self.lexer.get_next_token()

def error(self):
raise Exception(‘Invalid Syntax‘)
# 當當前Token取值完畢
# 刪除當前的Token,取下一個Token的值
def eat(self, token_type):
# 跳過與當前相同的Token,取下一個Token
if self.current_token.type == token_type:
self.current_token = self.lexer.get_next_token()
else:
# 若在刪除的過程中出錯,會引起整體的錯誤,故拋錯
self.error()
# 工廠方法
def factor(self):
token = self.current_token
# 判斷當前要刪除的Token類型
if token.type == INTEGER:
self.eat(INTEGER)
return token.value
# 將類型為Variable的變量返回
if token.type == VARIABLE:
self.eat(VARIABLE)
return variables[token.value]
# 左括號
elif token.type == LPAREN:
self.eat(LPAREN)
result = self.expr()
self.eat(RPAREN)
return result

def term(self):
result = self.factor()
while self.current_token.type in (MUL, DIV):
token = self.current_token
if token.type == MUL:
self.eat(MUL)
result = result * self.factor()
if token.type == DIV:
self.eat(DIV)
result = result / self.factor()
return result

def expr(self):
result = self.term()
while self.current_token.type in (PLUS, MINUS):
token = self.current_token
if token.type == PLUS:
self.eat(PLUS)
result = result + self.term()
if token.type == MINUS:
self.eat(MINUS)
result = result - self.term()
return result
def assignment(self):
if self.current_token.type == VARIABLE:
var = self.current_token.value
self.eat(VARIABLE)
if self.current_token.type == EQUALITY:
self.eat(EQUALITY)
variables[var] = self.expr()
return var
def printResult(text):
lexer = Lexer(text)
variableKey = Interpreter(lexer).assignment()
print(variableKey,"=",variables[variableKey])

def main():
while True:
try:
text = input(‘calc_> ‘)
except EOFError:
break

if not text:
continue
# try:
printResult(text)
# except Exception:
# print(‘Invalid Syntax‘)


if __name__ == ‘__main__‘:
main()


實驗結果:
1.基本功能:

技術分享

2.額外功能

技術分享


五、實驗總結

  體系結構是需求分析和概要設計之間的一個過程,是對項目的整體框架的搭建。若是之前的編程方式,看著這個題目不會想到去分析輸入的表達式會有哪些情況哪些可能,不會想到一個復雜的表達式要怎樣分解。前期我用直接編碼的方式實現了簡單的加減法,後來想要加上乘除法的時候發現代碼的結構非常不易變動增加。後來我嘗試了搭建框架的形式先分析了架構,將邏輯分析清楚後再編程,發現編程變得很簡單,基本是照著圖寫的傻瓜式編程,不需要復雜的思考就可以寫完代碼了。

  後來在這個架構的基礎上又增加賦值的部分後,又發現實現搭好架構再編碼,對代碼的可擴展也有很大的幫助。

  這個實驗讓我很深刻的體會到有架構的代碼和沒架構直接編寫代碼的差別很大,有一個好的架構可以讓編寫更簡單,也可以讓編寫出來的程序更易擴展,而不是寫完這個程序就結束了,想擴展還得全盤推翻。

130242014060-鄭佳敏-第2次實驗