폴리글롯 개요 및 설치

Copyright (c) 2015-, All Rights Reserved by Kwanghoon Choi
(아래 내용을 자유롭게 이용하되 다른 웹 사이트 등을 통한 배포를 금합니다.)

폴리글롯은 확장성 있는 컴파일러 프레임워크이다. 컴파일러에 대한 용어를 비롯한 개요를 먼저 설명하고, 폴리글롯을 소개하고 설치 방법을 설명한다.

0. 컴파일러 기본 용어

C, C++, Java와 같은 프로그래밍언어로 프로그램을 작성할 때 각 언어의 컴파일러를 직접적으로 또는 간접적으로 사용한다. 컴파일러란 소스 프로그램(.java, .c, .cpp, ...)을 입력 받아 실행 파일(.exe, .class, a.out, ...)을 출력하는 프로그램이다.

컴파일러에서 입력을 받아 출력하기까지 대체로 다음과 같은 과정을 거친다.

  1. 파싱(parsing)
  2. 소스 프로그램을 AST로 변환
  3. 타입 검사
  4. AST=>AST로의 최적화 변환
  5. 코드 생성(.exe, .class, ... 파일쓰기)

1~3 또는 1~4까지 과정을 컴파일러 전단부(front-end) 라 하고, 4~5 또는 5의 과정을 컴파일러 후단부(back-end)라 부른다. 컴파일 과정은 매우 복잡해서 항상 이렇게 구분하지 못할 수도 있지만, 편의상 이렇게 다섯단계로 나누어본다.

파싱은 텍스트 파일(바이트 스트림)에서 if 블록, for 블록과 같은 구조를 만들어 내는 구문 분석(syntax analysis) 과정이다. 파싱의 결과로 소스 프로그램의 AST를 만든다.

AST(Abstract Syntax Tree) - 추상구문트리는 소스 프로그램을 컴파일러 내부에서 다루기 위해 표현하는 일종의 자료 구조이다. 추상이라는 단어는, 소스 프로그램에는 포함되어 있지만 반드시 필요하지 않는 정보는 AST에 제외시킨다는 뜻이다. 예를 들어,

  • 소스 프로그램에는 문장과 문장을 구분하는 세미콜론(;)이 반드시 필요하지만, 파싱 단계가 끝나면 자료 구조 상으로 서로 다른 문장들을 구분하기 때문에 세미콜론과 같은 구분자(delimeter)가 더이상 필요 없다.
  • AST에는 보통 구문 설탕(Syntactic Sugar)도 포함하지 않는다. 예를 들어, Java의 for each문은 구문 설탕으로, 일반 while문으로 궁극적으로 변환되어 사라진다.
String[] arr = ...;
...
for (String s : arr) { // for each문
  ...
}

=>

String[] arr = ...;
...
Iterator iter = arr.iterator();   // for each문을 풀어 헤친 코드
while (iter.hasNext()) {
   String s = iter.next();
   ...
}

타입 검사는 의미 분석(semantic analysis) 과정이다. 구문상으로 문제가 없는 프로그램이더라도 의미상 문제를 가지고 있을 수 있다. 예를 들어, int x;로 선언한 변수 x에 대해 세가지 할당문의 사례를 살펴보자.

x = 123; // 할당문의 양쪽이 모두 int 타입. OK
x = 12.3; // 할당문의 왼쪽은 int이지만 오른쪽은 double. 
          // C/C++은 OK로 정의. 12.3을 int형으로 자동 형변환해서 같은 타입으로 만듬.
          // Java는 Not OK로 정의. 자동 형변환을 하지 않음.
x = "1.23"; // 양쪽 타입이 다를 뿐 아니라, 자동 형변환으로 같은 타입으로 만들 수도 없음.

최적화 변환 과정은, 소스 프로그램을 표현하는 초기 AST를 의미는 변하지 않으면서 더 효율적으로 실행할 수 있는 AST로 대체하는 과정이다.

x = 1 + 2 + 3; // 덧셈을 2번하는 과정 필요
=>
x = 6; // 1+2+3은 6과 동일하므로 6으로 대체

코드 생성 과정은 AST에 따라 동일한 실행 결과를 가지도록 코드를 만들어 파일에 기록한다.

1. 폴리글롯(Polyglot)

폴리글롯은 Java 프로그래밍언어에 대한 확장 가능한 컴파일러 프런트엔드이다.

  • 기본적으로 Java로 작성한 프로그램을 입력을 받는다.
  • Java언어에 새로운 특징을 추가한 새로운 언어에 대한 컴파일러를 만들때 적합한 구조를 갖추고 있다. (Java언어를 처리하는 기존의 폴리글롯 코드는 한 줄도 수정하지 않고도, 새로운 특징을 처리하는 코드만 추가할 수 있다.)
  • Java언어의 컴파일러 프런트엔드를 제공하되, 기존의 javac 컴파일러를 활용해서 코드를 생성한다. (폴리글롯의 입력은 Java 프로그램이고 출력도 Java 프로그램이다. 이 출력 프로그램을 javac를 통해 컴파일하고 클래스 파일 코드를 생성한다.)

폴리글롯을 두가지 방향으로 활용할 수 있다.

  • Java 프로그래밍언어에 새로운 특징을 추가해서 Jif, SessionJ 등 다양한 확장된 Java 언어에 대한 컴파일러를 만들 수 있다.
  • 다른 활용 방법은, Java 언어를 확장하지 않고 그대로 사용하되, 폴리글롯에서 제공하는 컴파일러 프런트엔드를 확장해서 Java 프로그램 분석기나 Java 프로그램 변환기를 작성할 수 있다.

튜토리얼과,API 문서, 기술 문서에서 폴리글롯에 대한 많은 정보를 얻을 수 있다.

https://www.cs.cornell.edu/projects/polyglot/api2/   (2.6.x 버전, 2.7 버전이 아님)

https://ecommons.cornell.edu/handle/1813/5859

 

폴리글롯은 확장가능한 구조로 작성되어 있다. 즉, 어떤 방향으로 활용하든 기존의 폴리글롯 소스 코드를 한 줄도 고치지 않아도 된다.

1.1 폴리글롯 빌드 환경

폴리글롯 라이브러리는 JAR 형태이기 때문에 일단 빌드하면, 윈도우즈/맥/리눅스 등 어느 운영체제에서도 쉽게 사용 가능하다. 다만 폴리글롯 기반 컴파일러 템플릿을 만드는 프로그램은 BASH 쉘 스크립트로 작성되어 있어(윈도우즈용 배치 파일이 없어) 리눅스와 맥에서만 사용 가능하다. 윈도우즈에서 이 프로그램을 사용하려면 cygwin과 같은 환경을 설치해서 쉡을 실행시키면 이 프로그램을 사용할 수 있다.

  • https://www.cygwin.com/

1.2 폴리글롯 다운로드 및 빌드

[1단계]

폴리글롯은 오픈 소프트웨어로 해당 웹사이트에서 내려 받을 수 있다. 현재 (2015년 12월 28일) github 사이트에서 소스를 관리하고 있어 git를 통해서 최신 소스 polyglot-2.7.0을 받을 수 있다.

  • https://www.cs.cornell.edu/projects/polyglot/

$ git clone https://github.com/polyglot-compiler/polyglot

[2단계]

폴리글롯 소스 프로그램은 Java로 작성되어 있고 ANT 빌드 시스템을 사용한다. JDK와 ANT를 미리 설치해놓아야 한다. JDK는 설치 프로그램이 있고, ANT는 JAR 파일로 되어 있어 다운받기만 하면 된다.

  • JDK : http://www.oracle.com/technetwork/java/javase/
  • ANT : http://ant.apache.org/

JDK

  • java
  • javac

ANT

  • ant

이 메모에서 가정하는 기본 폴더를 /Users/lazyswamp/Work/Seminar/라고 가정하고, $HOME이 이 경로를 가리킨다고 하자.

ANT(apache-ant-1.9.6-bin.zip)을 다운받아  $HOME/apache-ant-1.9.6에 풀어놓고, $HOME/apache-ant-1.9.6/bin을 /Users/lazyswamp/.bashrc에 아래의 줄을 추가하여 PATH에 ant 프로그램의 경로를 추가한다.

  • PATH=/Users/lazyswamp/Work/Seminar/apache-ant-1.9.6/bin:$PATH

[3단계]

polyglot-master.zip을 GitHub에서 다운받아 $HOME/polyglot-master/에 압축을 풀어놓고, 아래의 명령을 차례로 실행한다.

  • cd $HOME/polyglot-master
  • ant  bin                                              ==> 소스를 빌드해서 클래스 파일을 만듬

(새로 빌드된 것은 아니지만) $HOME/polyglot-master/bin/ 아래 jlc, jl5c, jl7c이 있다. 이 파일은  BASH 쉘 프로그램이고 각각 확장자가 .jl, .jl5, .jl7인 1.4, 1.5, 1.7 버전 Java 프로그램을 컴파일한다.

  • ant jar                                            ==> polyglot.jar 파일을 만듬

$HOME/polyglot-master/lib/polyglot.jar 파일이 생성되었는지 확인한다.

[4단계]

먼저 빌드한 폴리글롯을 실행하기 위한 환경을 설정한다. 아래의 경로 설정을 /Users/lazyswamp/.bashrc에 추가한다.

Polyglot

POLYGLOT=$HOME/polyglot-master

PATH=$POLYGLOT/bin:$PATH
CLASSPATH=$POLYGLOT/classes:$CLASSPATH
CLASSPATH=$POLYGLOT/lib/java_cup.jar:$CLASSPATH

CLASSPATH=$POLYGLOT/lib/polyglot.jar:$CLASSPATH

간단한 예제 Java 프로그램을 만들어 테스트한다.

$ pwd

/Users/lazyswamp/Work/Seminar/

$ jlc

jlc: No command line arguments given
usage: jlc [options] <source-file>.jl ...
where [options] includes:
--help print this message
--version print version info
-addbootcp <path> prepend <path> to the bootclasspath
-assert recognize the assert keyword
-bootclasspath <path> where to find runtime class files (default: JVM
property: sun.boot.class.path (or all jars in
java.home/lib))
-c compile only to .java
-classpath <path> where to find user class files (default: JVM
property: java.class.path)
-commandlineonly only compile files named on the command-line (may
also require -c)
-D <directory> output directory for .java files (default: same
as -d)
-d <directory> output directory (default: current directory)
-debugpositions generate position information for
compiler-generated code
-disable <pass> disable pass <pass>
-dump <pass> dump the ast after pass <pass>
-errors <num> set the maximum number of errors (default: 100)
-fqcn output fully-qualified class names
-g generate debugging info in class files
-mergestrings parse concatenated string literals as one single
string literal
-no-output-to-fs keep .java files in memory if possible
-nooutput delete output files after compilation
-noserial disable class serialization
-ox <ext> set output extension
-postcompiler <compiler> run javac-like compiler after translation
-postopts <options> options to pass to the compiler after translation
-preferclassfiles prefer class files to source files even if the
source is newer
-print <pass> pretty-print the ast after pass <pass>
-report <topic>=<level> print verbose debugging information about topic
at specified verbosity. Allowed topics: cfg,
context, dataflow, errors, frontend, imports,
loader, resolver, serialize, time, types, visit,
verbose, debug, jl, qq
-simpleoutput use SimpleCodeWriter
-sourcepath <path> where to find source files (default: current
directory)
-stdout output to stdout
-sx <ext> set source extension
-v delete output files after compilation
-w <num> set the maximum width of the .java output files
(default: 80)

위와 같은 jlc의 옵션이 출력되는 것을 볼 수 있다면 polyglot을 성공적으로 설치하였다. jl5c나 jl7c도 실행해보면 유사한 형태의 옵션을 볼 수 있다.

jlc로 Java 프로그램을 컴파일하는 예를 보자.

$ vim Main.java

package com.example.java;

public class Main {
  public static void main(String[] args) {
     System.out.println("Hello Polyglot");
  }
}

jlc로 Main.java를 컴파일해보면 아래와 같은 컴파일 에러가 난다. 그 이유는 jlc는 Java 프로그램을 입력으로 받는 컴파일러이긴 하지만, 확장자로 .java가 아닌 .jl을 기대하기 때문이다.

$ jlc Main.java

jlc: Source "Main.java" does not have the extension ".jl".
1 error.

$ cp Main.java Main.jl

$ jlc Main.jl

$ ls

Main.class Main.java Main.jl

jlc는 Main.jl을 입력받아 Main.java를 생성하고, javac를 통해 Main.class로 코드 생성한다. 이때 Main.java의 내용을 보면 앞에서 작성했던 것에 jlc 컴파일러가 정보를 추가했음을 확인할 수 있다.

$ cat Main.java

public class Main {
 public static void main(String[] args) {
 System.out.println("Hello Polyglot");
 }
 
 public Main() { super(); }
 
 public static final String jlc$CompilerVersion$jl = "2.7.0";
 public static final long jlc$SourceLastModified$jl = 1451395028000L;
 public static final String jlc$ClassType$jl =
 ("H4sIAAAAAAAAAI1WTWwbRRQeb5ykSdM6MSTqT/5InEhNW5sKhAQBRGq1TcAh" +
 "UdwKEUTNeHfsbLLe2c6OHScQVJBQIg45QFrKoZyCBCi0ElLFAVXqCVoVIVEh" +
 "BAcoN0AlEr3ABShvZtdee50WLO3MeObN+/nme29mYxPV2wz1WtRYyBqUR/mC" +
 "RezoJGY20eIGtu3jMJFSz+yPrb1zsvWTOhSaRiHdTHLMdTVOTU6KfBq15Egu" +
 "TZg9omlEm0ZtJiFakjAdG/oiCFJzGoVtPWtinmfEniI2NQpCMGznLcKkzdJk" +
 "ArWo1LQ5y6ucMpuj1sQsLuBYnutGLKHbfDiBGjI6MTT7FHoVBRKoPmPgLAh2" +
 "JEpRxKTG2FExD+LNOrjJMlglpS3BOd3UOOrx7yhHHHkGBGBrY47wGVo2FTQx" +
 "TKCw45KBzWwsyZluZkG0nubBCkd77qoUhLZZWJ3DWZLiaJdfbtJZAqkmCYvY" +
 "wlG7X0xqKjK0x3dmFae1+ezjqy+bo6YifdaIagj/62FTt2/TFMkQRkyVOBtb" +
 "hhJnccflFQUhEG73CTsyn75y+6kD3VeuOjJ7t5CZSM8SlafU9fTOrzvj+x6t" +
 "E25ss6itCypURS5PddJdGS5awMWOskaxGC0tXpn6/PnTH5FbCmoeQw0qNfI5" +
 "YFWbSnOWbhB2jJiEYU60MdRETC0u18dQI4wTukmc2YlMxiZ8DAUNOdVA5X+A" +
 "KAMqBERBGOtmhpbGFuYzcly0EEKN8KEAfPXwFdxxI0cDsRM2kB/4sLhgz+Oc" +
 "FXuOsrlYkuR0E7PYONbN6Kxh/V/BorC4Yz4QADA6/YlpAItHqaERllLX8oeP" +
 "3L6Quq6Uqen6ylFQ6EKBgFRyv2CrgyZgMQc5BmnUsi/54tMvrfTVwTFa80ER" +
 "DYhG/KTyUnEMRhiYklJDy7/8cfHsEvXoxVGkhvW1OwVr+/wBMaoSDaqCp36o" +
 "F19KXV6KKOIImqAYcIhFZFa330YVe4dLlUCAoCTQ9gxlOWyIpVL6NvMZRue9" +
 "GYn0dtGEHNAFWD4HZRF5Immd/+6rXx9ShOJSvQlVFKYk4cMVHBfKWiSb2zzs" +
 "jzNCQO6Hc5Nvn9lcfkECDxL9WxmMiDYO3MZAasreuHrq+5s/rn+jeIfFUYOV" +
 "Txu6WpSx7LwDvwB8/4hPEFVMiB7KVdxNkt5ylljC8qDnG+SLATkLrtuRE2aO" +
 "anpGx2mDCKb8FRo4dOm31VbnuA2YccBj6MB/K/Dmdx9Gp6+f/LNbqgmool57" +
 "+HliThG4z9M8whheEH4UX7vR9e4X+DyUE0hhW18kMiuRxAPJA9wvsRiU7ZBv" +
 "7aBo9jpotbvz8k+nbHtE0+dgK4b9Lq7I/TW4+V7qkVhttUTbVq2Toa67lWZ5" +
 "ray/vvaeNvH+IaeAhqvL3REzn/v427+/jJ776doWed3EqXXQIAViVNgUidvj" +
 "Mzku7y0vqT4c37h2bFB9S0F15Zytuf6qNw1XGofkYQRub1OEIWYaJai7yyCF" +
 "RfACcwgLPen2gxUguRm2JeKKRBwobct3hQe9hLTN1Tbg9rv80HsHHigD4r8e" +
 "JY2cG+z3jZu3buzouiALTDCNbScg/7ui9tlQ9RqQ8TSVPe0Unva5Hj7i9g9W" +
 "xi9Fw/CgkdwWj4eo83iwLEsqG7kHe0dF8xgU9hwUQ7v2Ip9keg5KT8G9yMnK" +
 "2pt3oqtrSsVrp7/mwVG5x3nxSFvNookIIj9wLytyx9GfLy599sHSsuL6+TC4" +
 "WKC6VnTvICg0tWE7D4TivxHTrF59CgAA");
}

Main.java를 Main.jl5로 바꾸면 jl5c 컴파일러를 테스트할 수 있고, Main.jl7으로 바꾸면 jl7c 컴파일러를 테스트할 수 있다.

jlc는 Java 1.4의 프로그램을 컴파일하고, jl5c와 jl7c는 각각1.5와 1.7의 프로그램을 컴파일한다. 예를 들어, Java Generics는 Java 1.6이후 부터 지원되므로 jlc와 jl5c에서는 Java Generics을 사용하는 프로그램을 컴파일하지 못한다.

jlc, jl5c, jl7c는 각각 확장자가 .jl, .jl5, .jl7인 Java 프로그램을 입력받는다. 만약 보통 우리가 알고 있는 .java 확장자를 갖는 Java 프로그램을 컴파일하려면 다음과 같이 옵션을 적용할 수 있다.

$ jlc -extclass polyglot.ext.jl7.JL7ExtensionInfo Main.java

위 명령어는 Main.java를 입력받아 Main.java로 출력한 다음 javac로 클래스 파일을 만든다. 입력 Main.java를 지워버리고 출력 Main.java로 대체한다. 입력 파일을 유지하기 위해서 출력 파일의 경로를 지정할 수 있다.

$ jlc -d output -extclass polyglot.ext.jl7.JL7.JL7ExtensionInfo Main.java

출력 파일 Main.java는 -d 옵션으로 지정한 output 디렉토리 아래에 생긴다.

jlc, jlc5, jlc7을 실행할 때 Compiler Not Found와 같은 에러가 발생하는 경우가 종종 있다. Polyglot에서 javax.tools.JavaCompiler 클래스의 getSystemJavaCompiler 메소드를 호출하여, JDK에 포함된 tools.jar를 사용하는데, JRE와 JDK를 둘 다 설치한 경우 알 수 없는 충돌이 생겨 이 메소드가 제대로 작동하지 않을 수 있다. 한가지 응급 조치는 JRE 디렉토리 이름을 변경해서 실행 경로(PATH)에서 JRE를 참조하지 못하고 오직 JDK만 참조하게 하는 것이다.

2. 폴리글롯 기반 컴파일러

지금까지 폴리글롯을 빌드해서 기본으로 제공하는 컴파일러 jlc, jl5c, jl7c를 사용하는 예를 보았다. 이제는 폴리글롯을 기반으로 하는 새로운 컴파일러를 만들기 위한 템플릿을 만드는 방법을 설명한다. 먼저, 텍스트 기반으로 컴파일러 템플릿을 만드는 과정을 살펴보고, 그 다음에 이클립스로 옮기는 방법을 설명한다.

폴리글롯 기반 컴파일러 템플릿을 만드는 도구는 폴리글롯 안에 포함되어 있는 newext.sh 쉘 스크립트를 사용한다. 한가지 주의할 점은 생성된 템플릿의 컴파일 기능은 Java 1.4 버전의 프로그램을 입력받는 것을 가정한다. 만일 Java 1.7 버전을 입력받는 컴파일러를 만들고 싶다면 코드 한 줄(단 한줄!)을 바꾸면 된다. 나중에 이점을 설명한다.

 

2.1 텍스트 기반 컴파일러

ANT, JDK, POLYGLOT이 이미 설치되어 있고, 이 프로그램을 실행시킬 수 있는 경로가 이미 PATH에 설정되어 있다고 가정한다.

폴리글롯 기반 컴파일러 템플릿을 생성하기 위해 newext.sh을 실행한다.

$ newext.sh

/Users/lazyswamp/Work/Seminar/polyglot-master/bin/newext.sh: too few arguments
Usage: /Users/lazyswamp/Work/Seminar/polyglot-master/bin/newext.sh dir package LanguageName ext
where dir - name to use for the top-level directory
and for the compiler script
package - name to use for the Java package
LanguageName - full name of the language
ext - file extension for source files

package and LanguageName must be legal Java identifiers
examples:
/Users/lazyswamp/Work/Seminar/polyglot-master/bin/newext.sh polyj polyj PolyJ pj
/Users/lazyswamp/Work/Seminar/polyglot-master/bin/newext.sh atomjava polyglot.ext.atomjava AtomJava aj

이 프로그램에 몇가지 인자를 지정해주어야 한다.

$ newext.sh myproj tool.compiler.java Java java

  • myproj : 템플릿을 저장할 디렉토리
  • tool.compiler.java : 컴파일러 템플릿 소스 코드의 패키지 명
  • Java : 컴파일러의 입력 언어 이름
  • java : 컴파일러 입력 프로그램의 확장자 이름

생성된 컴파일러 템플릿은 다음과 같이 구성되어 있다.

$ ls
README build.xml lib tests bin compiler runtime

컴파일러 템플릿 소스 코드는 comiler/src 디렉토리에 있고, 여기에 개발할 컴파일러의 소스를 추가한다. 이 소스를 빌드한 결과 클래스 파일을 compiler/classes 디렉토리에  놓게 된다. tests 디렉토리 아래 Hello.java 프로그램이 기본적으로 생성되어 있고 템플릿 컴파일러를 적용해서 실행해 볼 수 있다.

이제 ant를 실행해서 빌드한다.

$ ant

드디어 생성한 컴파일러를 실행할 차례다. 템플릿에 포함된 컴파일러는  bin/{myproj,myprojc}로 실행 가능한 파일로 만든다.

$ ls -al bin
-rw-r--r-- 1 lazyswamp staff 1634 Mar 15 11:46 myproj
-rw-r--r-- 1 lazyswamp staff 1646 Mar 15 11:46 myprojc

$ chmod ugo+x bin/{myproj,myprojc}

$ ls -al bin
-rw-r-xr-x 1 lazyswamp staff 1634 Mar 15 11:46 myproj
-rw-r-xr-x 1 lazyswamp staff 1646 Mar 15 11:46 myprojc

(바로 실행하면 아래와 같은 오류가 발생한다.)

$ bin/myprojc
오류: 기본 클래스 myproj.Main을(를) 찾거나 로드할 수 없습니다.

컴파일러 템플릿으로 생성된 bin/myprojc에서 일부 오류를 수정할 필요가 있다. 다음과 같이 수정한다.

$ vim bin/myprojc

1. myproj를 tool.compiler.java.Main로 변경

Is this a bug???

polyglot() {

eval "$java" "$vmargs" -classpath "'$classpath'" myproj.Main "$@"

eval "$java" "$vmargs" -classpath "'$classpath'" tool.compiler.java.Main "$@"
}

2. 확장 인자에 해당하는 부분을 모두 주석 처리해서 제거

if [ -n "$ext" ]; then

args="-ext '$ext' $args"

fi

이제 컴파일러 템플릿을 실행할 수 있다.

$ bin/myprojc -d output tests/Hello.java

$ ls -al output

Hello.java Hello.class

 

2.2 폴리글롯 기반 컴파일러 템플릿을 이클립스 Java 프로젝트로 옮기기

폴리글롯 컴파일러 템플릿을 생성했지만, 실제 컴파일러를 개발하려면 앞으로 아주 많은 프로그래밍 작업이 필요하다. 텍스트 환경에서 개발하기 매우 불편하고 이클립스 환경을 이용하는 것이 필요하다. 이런 이유로, 앞에서 만든 컴파일러 템플릿을 이클립스로 옮기려고 한다.

[1단계]

이클립스를 실행해서 새로운 Java 프로젝트를 만든다.

  • File => New => Java 프로젝트 (예: 프로젝트 이름 MyPolyglotProject)
  • [ workspace/MyPolyglotProject/ 디렉토리 ]

[2단계]

컴파일러 템플릿의 소스 코드 myproj/compiler/src/*를 MyPolyglotProject  프로젝트의 src 폴더에 복사한다.  복사 후 많은 컴파일 에러가 발생해서 소스 코드에 빨간 줄이 나타날 수 있는데, 나중에 적절한 라이브러리를 추가하면 없어질 것이다.

[3단계]

myproj/lib 디렉토리 밑에 있는 java_cup.jar, jflex.jar, polyglot.jar, and ppg.jar,pth.jar JAR 라이브러리를 MyPolyglotProject 프로젝트의 lib 폴더에 복사한다.

이클립스 프로젝트의 빌드 경로(build path)에 라이브러리를 추가해야 한다.

  • MyPolyglotProject 프로젝트 이름의 마우스 오른쪽 클릭
  • ==> Build path ==> Configure build path
  • ==> Java build path ==> libraries
  • ==> Add Jars   (lib 폴더에 복사한 JAR 파일들을 모두 선택)

소스를 추가했을 때 발생했을 수 있는 컴파일 에러 표시 빨간 줄이 사라질 것이다. 여전히 문제가 있다면 Java Compiler ==> Compiler comliance level 1.7 or higher 옵션을 확인한다.

[4단계]

테스트를 위해 myproj/tests 디렉토리 전체를 MyPolyglotProject에 복사한다.

[5단계]

MyPolyglotProject를 실행한다. Run configuration을 생성해서 실행 설정을 먼저 작성한다.

  • MyPolyglotProject 프로젝트 이름의 마우스 오른쪽 클릭
  • ==> Run Configuration을 선택
  • ==> Java Application을 선택
  • ==> Run Configuration의 이름을 지정 (예: MyPolyglotProject)
  • ==> Main 탭의 Project name : MyPolyglotProject
  • ==> Main 탭의 Main class :  tool.compiler.java.Main
  • ==> Arguments 탭 : -d output tests/Hello.java          (cf. 윈도우즈의 경우 tests\Hello.java)
  • ==> Classpath 탭 : User Entries와  Add JARs => Add lib를 선택하고 lib에 추가한 모든 JAR 파일들을 선택
  • (옵션:   ==> JRE 탭 :  JDK 디렉토리 아래에 있는 JRE 폴더를 선택)

예를 들어,

[JDK folder] C:\Program Files\java\jdk1.8.0_45
[JRE folder] C:\Program Files\java\jdk1.8.0_45\jre

(One may meet some "Java compiler not found" error in case
the JRE folder and JDK folders are not set apppropriately.
See the troubleshooting section for the relevant issue.)

[6단계]

Run As에서 MyPolyglotProject를 선택해서 실행한다.

  • 실행 창에 특별한 메시지를 출력하지 않는다.

MyPolyglotProject/output 디렉토리 아래 Hello.java와 Hello.class가 생성되어 있다면 이클립스 프로젝트로 컴파일러 템플릿을 성공적으로 옮겼음을 확인할 수 있다.

 

2.3 이클립스 프로젝트로 만든 템플릿 컴파일러에서 Java 7의 입력 프로그램을 받기

폴리글롯 컴파일러 템플릿은 기본적으로 Java 1.4버전의 입력 프로그램을 받도록 구성되어 있다. tests/Hello.java를 선택해서 Java Generics을 사용하도록 변경해서 컴파일해보면 컴파일 에러가 발생한다.

package com.example.java;

public class Main {
  public static void main(String[] args) {
     System.out.println("Hello Polyglot");
  }
}

class Box<E> {
   private E elem;
   public E get() { return elem; }
   public void set(E elem) { this.elem = elem; }
}

/Users/lazyswamp/Documents/workspace/polyglot/MyPolyglotProject/tests/Hello.java:7:

    Syntax error: unexpected operator <.

class Box<E> {

                ^

1 error.

 

Java 1.4 입력 언어를 Java 1.7로 변경하기 위해서 src/tool/compiler/java/Main.java 소스 프로그램에서 아래와 같이 한 줄 바꾸면 된다.

package tool.compiler.java;

public class Main 
{
  public static void main(String[] args) {
   polyglot.main.Main polyglotMain = new polyglot.main.Main();
  
   try {
      // polyglotMain.start(args, new tool.compiler.java.ExtensionInfo());
      polyglotMain.start(args, new polyglot.ext.jl7.JL7ExtensionInfo());
   }
   catch(polyglot.main.Main.TerminationException e) {
      System.err.println(e.getMessage());
      System.exit(1);
   }
}

다시 실행하면 Java Generics을 포함하는 입력 프로그램을 잘 컴파일 됨을 볼 수 있고, Java 1.7로 변경 되었음을 확인할 수 있다.

 

 

2.4 이후에 ...

이제 폴리글롯을 설정했고 이제부터 각자가 원하는 컴파일러를 만드는 작업을 시작할 때이다. 폴리글롯은 확장 가능한 구조로 작성되어 있어 기존 라이브러리의 코드 한 줄을 바꾸지 않고 본인이 생성한 이클립스 프로젝트에 적절한 코드를 작성하기만 하면 된다. 이 점은 분명히 장점이지만, 이 확장 가능한 구조로 만들기 위해서 기존 컴파일러 구조보다 훨씬 복잡한 구성이 불가피하였다.

이 다음 메모에는 이 복잡한 구성에 대해 설명할 계획이다.

 

Leave a Reply

Your email address will not be published. Required fields are marked *