이클립스에 내장된 자바파서 활용하기 #1

이클립스는 JDT라는 자바개발환경을 포함하고 있습니다. 그리고 JDT는 자바개발과 관련하여 다양한 기능을 제공(e.g. Code Formatting)하기 위해 자바파서와 AST를 내장하고 있습니다. 따라서 이 부분을 잘 뜯어서 사용하면 훌륭한(!) 자바 파서를 공짜로 얻는 셈이 되는 것이죠.

앞으로 몇부에 걸쳐 JDT에 내장된 자바파서와 AST를 활용할 수 있는 방법을 설명하려고 합니다. 1부에서는 AST의 구조를 파악하는데 도움이 되는 ASTExplorer를 실행해보도록 하겠습니다. 이 과정에서 개발환경을 설정(e.g. 클래스패스 설정)하는 방법도 함께 다루겠습니다. 질문은 덧글로 남겨주세요.

올초에 빠른 시간안에 자바 코드 읽어 다른 형태의 코드로 변환하는 프로그램을 개발해야 했는데, 여러가지 방법을 찾아 고민하던 중에, JDT에 내장된 자바파서를 활용방안을 다룬 다음 웹문서를 발견하게 되었습니다.

Exploring Eclipse’s ASTParser

이 문서에서 ASTExplorer라는 예제 프로그램을 다운 받을 수 있는데, 이클립스 v3.02를 기준으로 하고 있어 다른 버전의 이클립스에 이 프로젝트를 import 하는 경우, 클래스패스에 추가된 JDT 라이브러리의 경로와 이름이 달라 에러가 발생합니다.

이 문제를 해결하는 가장 쉬운 방법은 클래스패스에 등록된 라이브러리를 지우고, eclipse\plugins에 존재하는 라이브러리를 클래스 패스에 추가하는 것입니다만 불필요한 라이브러리가 많이 추가되겠죠?

제가 사용하는 User Library를 첨부합니다. (이클립스 v3.3.1.1 기준) User Libraries에서 Import 하시면 됩니다.

jk10.userlibraries
첨부한 User Library를 클래스패스에 추가하셔도 JDT 버전이 올라가면서 변경된 부분 때문에 컴파일 에러가 발생할 것 입니다.

ASTMain.java의 다음 2라인의 코드를

return new NameEnvironmentAnswer(unit);
return new NameEnvironmentAnswer(classFileReader);

다음과 같이 수정해 주시면 컴파일 에러가 해결됩니다.

return new NameEnvironmentAnswer(unit, null);
return new NameEnvironmentAnswer(classFileReader, null);

ASTMain.java와 ASTExplorer.java 모두 main 메서드를 가지고 있습니다. ASTMain.java의 코드를 읽어보면 AST를 생성하는 작업을 정의하고 있는데, JDT 버전이 달라서 그런지 Exception이 발생하며 제대로 실행되지 않습니다.

ASTExplorer.java의 경우 실행에 문제가 없습니다. 실행해 보시면 다음과 같은 화면을 보실 수 있습니다.

사용자 삽입 이미지
이 프로그램은 JDT 내장 자바파서가 생성하는 AST 객체의 구조를 한눈에 파악할 수 있도록 화면 왼쪽에 AST의 구조를, 화면 오른쪽에 소스코드를 보여줍니다. AST에 익숙하지 않은 경우에 큰 도움을 주는 프로그램이죠.

AST에 대한 API Reference는 이클립스의 Help Contents에서 찾아 볼 수 있습니다. 웹에서 확인하고 싶으신 경우 다음 URL을 참조하세요.

http://help.eclipse.org/help33/index.jsp?topic=/org.eclipse.jdt.doc.isv/reference/api/org/eclipse/jdt/core/dom/package-summary.html

1부에서는 간단히(?) JDT에 포함된 파서와 AST를 활용한 ASTExplorer를 실행해 보았습니다. 2부에서는 자바소스코드를 읽어 AST를 얻는 방법에 대하여 설명하겠습니다. (물론 ASTExplorer 소스코드를 읽어보시면 쉽게 이해하실 수 있겠습니다만… ^^;)

나 홀로 프로젝트

팀원 4명이 함께 진행하던 프로젝트를 몇 일전부터 혼자 담당하게 되었다. 업무의 인수인계 후에 살펴보니 코드리뷰 한번 없이 각자 개발한 코드는 동일한 기능이 비효율적으로 중복되어 있는 구조를 가지고 있었다. 그리고 언어를 다루는 프로그램의 특성상 언어의 의미(Semantic)은 엄밀히 지키면서 동작해야 하는데 그렇지 않았다. 내가 작성했던 코드 역시 마찬가지…

적절히 책임감이 분산되었던 함께하는 코딩과 혼자 모든 책임을 짊어지고 하는 코딩은 다르지 않아야 하는데 달랐던 것 같다. 마치 범죄 현장을 목격하고 아무도 신고 하려하지 않았던 다수의 대중들처럼…

실장님은 거의 완성된 것으로 보고 계시지만, 실제로는 그렇지 않은 상황에서 적절한 타협점을 찾기 위해 나에게 약간(?)은 버겁지만 실장님도 받아들일만한 프로젝트 예상일정을 보고했고 그로 인해 조금(?)은 조바심을 느끼면서 일을 홀로 진행하고 있다.

4명이 함께 프로젝트를 진행하면서, 코드가 비효율적으로 작성되어가고 있음을, 언젠가 한번은 이러한 비효율적이고 명확하지 않은 구조 때문에 더 큰 비용이 발생할 수 있음을 예상하고 있었지만 일개 팀원으로서 어떤 조취를 취하는 것은 영 부담스러웠다.

어려움에 처하긴 했지만, 거대한 코드를 내가 원하는 모습으로 마음껏 리펙토링 하고 하나의 작품을 만들어 가듯 아름답게 꾸미는 작업을 마음껏 할 수 있다는 것이 즐겁다.

1년 정도 회사에서 소프트웨어를 개발해보니 소프트웨어를 개발의 가장 큰 어려움은 기하급수적으로 증가하는 복잡도(Complexity)를 관리하는 것이 아닐까 하는 생각이 든다. 언젠가 팀장이 되어 프로젝트를 관리하는 입장이 되기전에 많은 경험과 많은 생각으로 충분한 역량을 쌓아 두어야겠다는 생각이 든다. 때문에 이번 프로젝트는 나에게 도전이자 기회다.

리눅스로 작업환경 변경

사용자 삽입 이미지
작업환경을 완전히 리눅스로 옮겼다. 윈도우 컴퓨터에서 Putty로 셀레론 컴퓨터에 접속해서 GCC를 컴파일 하며 작업하다 듀얼 코어 컴퓨터에 리눅스를 설치하고 직접 컴파일 하니 속도가 2배 가까이 향상 된 듯한 느낌을 준다. 게다가 우분투 7.10은 설정하고 사용하기가 정말 편리하다.

빨간색을 좋아하다 보니 입맛에 맞게 글꼴과 테마를 수정했다. 그럭저럭 마음에 드는 개발 환경을 마련하는데 성공! 출근해서 저녁먹을때까지는 리눅스 환경에서 업무에 집중하자!

Ruby로 처음 작성한 코드, test harness

펄, 파이선, 루비 등의 스크립트 언어 중에 하나 정도는 알아 두는게 편할 것 같다는 생각에 이번 달에는 루비를 공부하고 있다. 책의 절반을 쭉 읽어 나가면서 코드는 한번도 작성한 적이 없었지만 언어가 간결해서 그런지 몰라도 쉽게 원하는 코드를 작성할 수 있었다.

지금 진행하고 있는 프로젝트는 코볼 컴파일러의 개발인데, 컴파일러가 생성한 코드가 정확한가를 확인하는 가장 쉬운 방법은 기존의 컴파일러가 생성한 코드와 수행 결과(stdout)을 비교하는 것.

지금까지는 급한 마음에 두 실행파일을 번갈아 실행하며 눈으로 수행결과를 비교했는데, “실용주의 프로그래머”를 보면 테스트를 포함한 프로젝트 빌드의 전과정을 자동으로 수행할 수 있도록 할 것을 강조하고 있다.

그리하여 고즈넉한 저녁에 잠깐의 짬과 약간의 용기를 내어 처음으로 루비를 사용해 간단한 test harness를 작성해 보았다.

name_list = [
    ‘intrinsic_math_func’,
    ‘intrinsic_char_func’,
    ‘intrinsic_case_func’,
    ‘intrinsic_value_func’,
    ‘intrinsic_divide_func’,
    ‘intrinsic_numval’,
    ‘intrinsic_annuity’
]

test_cnt = 0
succ_cnt = 0
fail_cnt = 0

# TODO
# compare execution time
name_list.each do |name|

    test_cnt += 1

    mf_exec = “./” + name + “.cob32”
    tmax_exec = “./” + name + “.gcobol”

    mf_stdout = `#{mf_exec}`
    tmax_stdout = `#{tmax_exec}`

    print “[#{test_cnt}] #{mf_exec} vs #{tmax_exec}”
    if (mf_stdout == tmax_stdout)
        puts ” …success”
        succ_cnt += 1
    else
        puts ” …fail”
        fail_cnt += 1
        puts “[#{mf_exec}]”
        puts mf_stdout
        puts “[#{tmax_exec}]”
        puts tmax_stdout
    end
    puts
end

puts
puts “Total : #{test_cnt}”
puts “Success : #{succ_cnt}”
puts “Fail : #{fail_cnt}”
puts

컴파일러가 생성한 코드의 수행시간 역시 컴파일러를 평가하는데 중요한 이슈이므로, 두가지 컴파일러가 생성한 코드의 수행시간을 자동으로 비교해 주는 프로그램을 루비로 간단히 작성하는 것도 큰 의미가 있을 것 같다. 사용하기 쉬운 루비 언어를 조금 더 연습해서 프로젝트의 여기저기에 잘 활용한다면 생산성을 향상 시킬 수 있을 것이다.

VMWare Fusion pre-order

beta4에 이어 rc1을 사용하고 있었는데 8월 6일 정식 발매 된다는 소식을 듣고 그동안 미뤄오던 pre-order($39.99)를 해버렸다. 정식 발매 이후에 구입하게 되면 $79.99를 지불해야 한다.

윈도우를 사용할 수 밖에 없는 현실이 슬프지만 어쩔 수 없는 노릇. 플랫폼에 independent한 인터넷 환경은 얼마나 시간이 지나야 갖춰질까? 당장 이 글을 쓰고 있는 테터툴 마저도 사파리에서 html 모드로 글을 쓸 수 밖에 없으니 안타까움을 금할 길이 없다.

아마도 이번 pre-order가 최초의 정품 소프트웨어 구입이 될 것 같다. $39.99 정도의 가격이면 충분히 감당할 수 있을 정도. 오히려 맥용 정품 소프트웨어가 윈도우용 소프트웨어보다 대체로 저렴한 것 같다.

다음 구입할 맥용 소프트웨어는 차기 맥OS인 레오파드! 10월이 기다려지는구나. 즐거운 컴퓨팅을 기대하며 그 날을 기다린다.