CS 307: 11. Language Translation

Due: Wednesday, November 21, 2001.

Our final assignment is to implement a program to translate Scheme into other languages: Pascal, C++, and Java. Use the programs for expression translation from the previous assignment. For this assignment, you should add functions to translate several kinds of Scheme statements to equivalent forms in these other languages. The result will be a printed source-code form of the translated program.

The file graph1.scm contains two Scheme functions that you should translate to each of the other languages.

  1. Examine the functions (graph1) and (factorial n) in the file graph1.scm and execute them in Scheme to see what they do.

  2. Write a function (var-type->lang var alist language) that will output a variable declaration for the variable var if it is defined in the association list alist. The form of the declaration should be var:type for Pascal and type var for C++ and Java. The type should be translated for the target language using type->lang. An example of the alist is ((n integer)); this should produce n:integer for Pascal, int n for C++, and long n for Java.

  3. Write a function (st->lang s indent fn language) to translate statements. s is a statement, indent is the number of spaces the code should be indented, and fn is the function name (e.g., factorial) if the value of this statement should be returned as the value of the function, or #f otherwise (e.g., if the program is a procedure rather than a function). st->lang should begin by calling crtab to start a new line and indent indent spaces.

    1. Write the following functions to translate specific Scheme statements. These functions have the same arguments as st->lang.

      1. begin->lang

        Scheme (begin S1 S2 ... Sn )
        Pascal begin   S1; S2; ... ; Sn   end
        C++, Java { S1; S2; ... ; Sn; }

        Note that in Pascal there is not a ; after the last statement Sn in a begin group, although some Pascal compilers may accept one. Call st->lang to print the sub-statements Si; add 3 to indent for the sub-statements to make the code more readable.

      2. if->lang

        Scheme (if expr S1 S2 ) (if expr S1 )
        Pascal if expr   then   S1   else   S2 if expr   then   S1
        C++, Java if ( expr )   S1   else   S2 if ( expr )   S1

      3. dotimes->lang

        Scheme (dotimes ( i   n ) code )
        Pascal for i := 0 to n - 1 do   code
        C++, Java for ( i = 0; i < n; i++)   code

        Note that in the target languages, code must be a single statement; this can be accomplished by consing a begin onto the list of code.

      4. while->lang

        Scheme (while   test   code )
        Pascal while test   do   code
        C++, Javawhile ( test )   code

        Note that in the target languages, code must be a single statement; this can be accomplished by consing a begin onto the list of code.

    2. Test for specific functions that are translated specially, and call the appropriate translator function for each of them. For set! and vector-set!, call expr->lang. For let or let*, call let->lang, described below.

    3. If the code is not a pair, or is not a call to one of one of the special functions, then call a function (return->lang s indent fn language). return->lang should work as follows:

      1. If fn is #f, call expr->lang to print the statement.

      2. Otherwise,
        1. For Pascal, make an assignment statement using set! to assign to the function name the value of s, and call expr->lang to print it. E.g., in factorial the code 1 will be translated as factorial := 1 .

        2. For C++ and Java, make a ``function call'' using the function return and call expr->lang to print it. For example, in factorial the code 1 will be translated as return(1) .

    4. Write a function (let->lang s indent fn language) to translate let and let*. For each variable and initial value (var value) defined by the let, you should do two things:

      1. First, generate a declaration for each variable. For Pascal, print the keyword var once before processing the declarations. If the initial value of the variable is a constant, use the function type to infer its type and print its equivalent as given by type->lang. For example, the code (let ((i 3) (x 3.1)) ...) should generate:

        Pascal var i:integer; x:real;
        C++ int i; float x;
        Java long i; double x;

      2. Next, generate statements to assign the initial value to each variable. The above let should generate the assignments ((set! i 3) (set! x 3.1)).

        Append these assignment statements and the code of the let and cons a begin onto the front. Then print the begin statement using st->lang.

  4. Write a program (translate name code types fntype language) that will translate a Scheme function to another language. name is the name of the function. code is the Scheme code, of the form (lambda (args) ...). types is an association list of ((var type) ...). fntype is the type of the result if this is a function, or #f if it is a procedure rather than a function. language is the target language (pascal, c++, or java). Example calls for the two test functions are as follows:
    1. (translate 'graph1 graph1-code '() #f 'pascal)
    2. (translate 'factorial factorial-code '((n integer)) 'integer 'java)

    First, print the procedure or function header. For the two test cases, these should be:

    Pascal procedure graph1;
    C++ void graph1() {
    Java public static void graph1() {

    Pascal function factorial(n:integer):integer;
    C++ int factorial(int n) {
    Java public static long factorial(long n) {

    For Pascal, the result type of the function follows the arguments; for C++ and Java, the result type precedes the function name.

    Next, call st->lang to print the code with an indentation of 3. If the code is not a let, let*, or begin, cons a begin onto the list of code to force it to be a begin.

    Finally, print closing punctuation and the name of the procedure or function as a comment:

    Pascal ; {graph1}
    C++, Java } // graph1

  5. Use cut-and-paste to extract the code that you generated for each of the test programs and run it in Java. Skeleton code for Java is provided in the files graph.java and fact.java; insert your code into these files and then run it without other manual editing.

    You may use any version of Java you wish. The class web page has instructions for downloading Java SDK (32 MB) and BlueJ.

    To run your programs using BlueJ:

    1. Use cut-and-paste to insert the code produced by your program into the skeleton files graph.java and fact.java .
    2. Put the resulting files into the bluej directory.
    3. Start BlueJ. Under the Class menu, select New Project and enter a project name.
    4. Under the Edit menu, select Add Class from File, then select the graph file. Do the same for the fact file.
    5. Right-click on the graph icon, then select Compile. If it compiles successfully, right-click on the icon and select void main() to execute it. An output window should appear with the results. Similarly compile and execute the fact file.