RecursiveDescentParsing 을 TFP 로 시도를 해보려고 하는데.. Parser부분에 대한 test 의 결과를 얻기 위해서는 AST를 얻도록 해야 하고, AST를 조금씩 구축해나가는 방향으로 디자인유도중인데. 이 아이디어 생각하려는데 1시간을 소비했다. 흡;
먼저 "1"을 넣으면 "1"을 리턴하는 프로그램을 만듭니다. 다음 "314"를 넣으면 "314"를 리턴하게 합니다. 다음엔, "1 + 0"을 넣으면 "1"을 리턴하게 합니다. 다음, "1 + 314"를 넣으면 "315"를 리턴합니다. 다음, "1 + 2 + 314"를 하면 "317"을 리턴합니다. 다음, "1 - 0"을 하면 "1"을 리턴합니다. 다음, "1 - 1"을 하면 "0"을 리턴합니다. 다음, "314 - 1 + 2"를 하면 "315"를 리턴합니다. 다음, "- 1"을 넣으면 "-1"을 리턴합니다. 다음, "( 1 )"을 넣으면 "1"을 리턴합니다. ...... AST는 아직 생각하지 말고 당장 현재의 테스트를 패스하게 만드는데 필요한 것만 만들어 나가고 OAOO를 지키면서(테스트코드와 시스템코드 사이, 그리고 시스템 코드 간) 리팩토링을 지속적으로 합니다 -- 그렇다고 파싱 이론을 전혀 이용하지 말라는 말은 아니고 YAGNI를 명심하라는 것입니다. 그러면 어느 누가 봐도 훌륭한 디자인의 파서를 만들 수 있습니다. DoTheSimplestThingThatCouldPossiblyWork. --김창준
- 아. 이번 레포트에서 요구하는 것이 계산기는 아니고, 간단한 언어에 대한 파싱 유도과정을 보여주고 에러처리하는 것이다보니, 구체적인 결과를 얻는 부분이 모호하다 판단이 들어서요. 그래서 조금 더 명시적으로 보이는 DOM 형태의 AST를 구하는 형태로 접근했습니다. --석천
대강 다음과 같은 식으로 접근했고요. 테스트코드 2-3줄쓰고 파서 메인코드 작성하고 하는 식으로 접근했습니다. (
Refactoring 을 하다보면
FactoryMethodPattern 과
CompositePattern 이 적용될 수 있을 것 같은데, 아직은 일단.)
문제점 : 테스트 가능할 수 있는 아이디어가 나오기까지가 오래걸렸다. 테스트 가능한 방법으로 접근하고 나서부터의 코딩은 1-1.5시간정도밖에 안걸렸지만. 그리고 본래의 스펙에는 AST 에 대한 언급이 없었다. 해당 함수가 제대로 호출되었는지를 근거로 접근하는 것이 나았을지도.
~cpp
parser = RealParser()
parser.setStringStream("a = b+c")
doc = parser.parse()
self.assert_(doc != None)
# 이 테스트를 만족할때까지 프로그래밍
start = doc.getStart()
self.assert_(start != None)
# 이 테스트를 만족할때까지 프로그래밍
statements = start.getStatements()
self.assert_(statements != None)
# 이 테스트를 만족할때까지 프로그래밍
statement = statements.getStatement()
self.assert_(statement != None)
# 이 테스트를 만족할때까지 프로그래밍
identifier = statement.getIdentifier()
token = identifier.getToken()
self.assertEquals(token.tokenString, 'a')
self.assertEquals(token.tokenType, Scanner.TOKEN_IDENTIFIER)
# 이 테스트를 만족할때까지 프로그래밍
assignment_operator = statement.getAssignmentOperator()
token = assignment_operator.getToken()
self.assertEquals(token.tokenString, '=')
self.assertEquals(token.tokenType, Scanner.TOKEN_ASSIGNMENT_OPERATOR)
# 이 테스트를 만족할때까지 프로그래밍
expression = statement.getExpression()
self.assert_(expression != None)
# 이 테스트를 만족할때까지 프로그래밍
term = expression.getTerm()
self.assert_(term != None)
# 이 테스트를 만족할때까지 프로그래밍
factor = term.getFactor()
self.assert_(factor != None)
# 이 테스트를 만족할때까지 프로그래밍
identifier = factor.getIdentifier()
self.assert_(identifier != None)
# 이 테스트를 만족할때까지 프로그래밍
token = identifier.getToken()
self.assertEquals(token.tokenString,'b')
self.assertEquals(token.tokenType, Scanner.TOKEN_IDENTIFIER)
# 이 테스트를 만족할때까지 프로그래밍
plus_operator = expression.getPlusOperator()
token = plus_operator.getToken()
self.assertEquals(token.tokenString, '+')
self.assertEquals(token.tokenType, Scanner.TOKEN_PLUS_OPERATOR)
# 이 테스트를 만족할때까지 프로그래밍