Create an executable for a program in an interpreted language: Difference between revisions

From Rosetta Code
Content added Content deleted
(Created Draft task)
 
m (fixed some text)
Line 34: Line 34:
Note, <b>this task is about showing how to achieve the goal</b>, blurb is good but code or commands are required.
Note, <b>this task is about showing how to achieve the goal</b>, blurb is good but code or commands are required.
<br><br>
<br><br>
if your language can only be compiled (unlikely as that may seem - I've heard
if your language can only be compiled (unlikely as that may seem - I've heard that there are C interpreters, for example), you could omit it from the task, write an interpreter :) or ...

that there are C interpreters, for example), you could omit it from the task, write an interpreter :) or ...
<br><br>
<br><br>
If you do generate a source, it need not be in C - it can be in any language for which a compiler is available (perhaps your language).
If you do generate a source, it need not be in C - it can be in any language for which a compiler is available (perhaps your language).

Revision as of 13:33, 10 July 2022

Create an executable for a program in an interpreted language is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

Languages can be implemented by interpreters or compilers. Some languages are implemented by both techniques.

It can be convenient to provide an executable even when the language is normally interpreted. The purpose of this task is to show how it could be done for your language.

One method of doing this would be to create a program in a language for which there is a compiler available (C for example) that writes the actual interpreted source to a temporary file, calls the interpreter to run it and then deletes the temporary file afterwards.
For example, let's assume we need an executable that will run the Hello World program in the interpreter only language I. The I source might be:

    print "Hello, World!"


then (assuming the I interpreter is invoked with the command "InterpretI" and a suitable file for the temporary source is /tmp/t) a suitable C source might be: <lang c>#include <stdio.h>

  1. include <errno.h>

static void w( char * line, FILE * tf ) {fputs( line, tf );

if( errno != 0 ){ perror( "temp" );exit( 2 ); }

} int main( int argc, char ** argv ) {FILE * tf = fopen( "/tmp/t", "w" );

if( tf == NULL ){ perror( "temp" );exit( 1 ); }
w( "    print \"Hello, World!\"\n", tf );
fclose( tf );
system( "InterpretI /tmp/t" );
remove( "/tmp/t" );

} </lang> If your language has other ways of doing this e.g., the interpreter provides an API that would let you specify the code via a string instead of storing it in a file, demonstrate how this would be done.
If the implementation provides a standard utility or option to do this, show the commands necessary to do it.

Note, this task is about showing how to achieve the goal, blurb is good but code or commands are required.

if your language can only be compiled (unlikely as that may seem - I've heard that there are C interpreters, for example), you could omit it from the task, write an interpreter :) or ...

If you do generate a source, it need not be in C - it can be in any language for which a compiler is available (perhaps your language).

Whether or not the executable can be cross-compiled for a platform other than the one your program runs on is assumed to be a property of the compiler you are going to use to create the executable.


ALGOL 68

There have been several implementations of Algol 68, both compiled and interpreted. A popular implementation currently available for Windows and Linux is ALGOL 68G which is an interpreter (though under Linux a hybrid part compilation, part interpreted mode is available). This example follows the suggestion in the task description and creates a C source that will write the Algol 68 source and run the interpreter.

Works with: ALGOL 68G version Any - tested with release 2.8.3.win32

<lang algol68>IF # create an executable to run a program with Algol 68G #

   # a C program is created that writes the source to a temporary file and  #
   # then calls a the Algol 68G interpreter to run it                       #
   # get the temporary file path, the path to the interpreter, the source   #
   # file and the path for the generated C source                           #
   STRING temp file path, algol 68g path, a68 source, c source;
   print( ( "Temporary file path                      (target system) : " ) );
   read( ( temp file path, newline ) );
   print( ( "Command to run the Algol 68G interpreter (target system) : " ) );
   read( ( algol 68g path, newline ) );
   print( ( "Algol 68 source                            (this system) : " ) );
   read( ( a68 source, newline ) );
   print( ( "C source to generate                       (this system) : " ) );
   read( ( c source, newline ) );
   FILE input source file, output source file;
   open( input source file, a68 source, stand in channel ) /= 0

THEN

   # failed to open the Algol 68 source file                                #
   print( (  "Unable to open """ + a68 source + """", newline ) )

ELIF IF open( output source file, c source, stand out channel ) = 0

    THEN
        # opened OK - file already exists and will be overwritten           #
        FALSE
    ELSE
        # failed to open the file - try creating a new file                 #
        establish( output source file, c source, stand out channel ) /= 0
    FI

THEN

   # failed to open the C source file                                       #
   print( ( "Unable to open """ + c source + """", newline ) );
   close( input source file )

ELSE

   # files opened OK                                                        #
   # returns line with any " or \ characters preceded by \                  #
   PROC add escapes = ( STRING line )STRING:
        BEGIN
           [ 1 : ( ( UPB line + 1 ) - LWB line ) * 2 ]CHAR output line;
           INT o pos := 0;
           FOR l pos FROM LWB line TO UPB line DO
               CHAR c = line[ l pos ];
               IF c = "\" OR c = """" THEN
                   # must escape this character in C                        #
                   output line[ o pos +:= 1 ] := "\"
               FI;
               output line[ o pos +:= 1 ] := c
           OD;
           output line[ 1 : o pos ]
        END # add escapes # ;
   # writes line to the output source file                                  #
   PROC emit = ( STRING line )VOID:
        put( output source file, ( line, newline ) );
   BOOL at eof := FALSE;
   # set the EOF handler for the input file                                 #
   on logical file end( input source file
                      , ( REF FILE f )BOOL:
                          BEGIN
                              # note that we reached EOF on the latest read #
                              at eof := TRUE;
                              # return TRUE so processing can continue      #
                              TRUE
                          END
                        );
   # include headers, output routine and the start of the main routine      #
   emit( "#include <stdio.h>" );
   emit( "#include <errno.h>" );
   emit( "static void w( char * line, FILE * tf )" );
   emit( "{fputs( line, tf );" );
   emit( " if( errno != 0 ){ perror( ""temp"" );exit( 2 ); }" );
   emit( "}" );
   emit( "int main( int argc, char ** argv )" );
   emit( "{FILE * tf = fopen( """
       + add escapes( temp file path )
       + """, ""w"" );"
       );
   emit( " if( tf == NULL ){ perror( ""temp"" );exit( 1 ); }" );
   # output code to write the Algol 68 source to the temporary file         #
   WHILE STRING line;
         get( input source file, ( line, newline ) );
         NOT at eof
   DO
       IF line /= "" THEN
           # line is not empty                                              #
           emit( " w( """ + add escapes( line ) + "\n"", tf );" )
       FI
   OD;
   close( input source file );
   # code to close the temporary file and interpret it then delete it       #
   emit( " fclose( tf );" );
   emit( " system( """
       + add escapes( algol 68g path )
       + " "
       + add escapes( temp file path )
       + """ );"
       );
   emit( " remove( """ + add escapes( temp file path ) + """ );" );
   emit( "}" );
   close( output source file );
   print( ( newline
          , c source
          , " generated"
          , newline
          , "This can now be compiled for the target system "
          , "(possibly via cross-compilation)"
          , newline
          , "using a suitable C compiler"
          , newline
          )
        )

FI</lang>

Output:

Assuming /tmp/t is a temporary file that could be written to by the generated C program and that the command to run ALGOL 68G is a68g, a sample run of the program might be:

Temporary file path                      (target system) : /tmp/t
Command to run the Algol 68G interpreter (target system) : a68g
Algol 68 source                            (this system) : hw.a68
C source to generate                       (this system) : _hw_a68.c

_hw_a68.c generated
This can now be compiled for the target system (possibly via cross-compilation)
using a suitable C compiler

If hw.a68 contains: <lang algol68>print( ( "Hello, World!", newline ) ) </lang>

The generated _hw_a68.c would contain: <lang c>#include <stdio.h>

  1. include <errno.h>

static void w( char * line, FILE * tf ) {fputs( line, tf );

if( errno != 0 ){ perror( "temp" );exit( 2 ); }

} int main( int argc, char ** argv ) {FILE * tf = fopen( "/tmp/t", "w" );

if( tf == NULL ){ perror( "temp" );exit( 1 ); }
w( "print( ( \"Hello, World!\", newline ) )\n", tf );
fclose( tf );
system( "a68g /tmp/t" );
remove( "/tmp/t" );

}</lang>

AWK

Translation of: ALGOL 68

<lang awk># create an executable to run a program with awk

  1. a C program is created that writes the source to a temporary file and
  2. then calls a the Awk interpreter to run it

BEGIN \ {

   FALSE = 0;
   TRUE  = 1;
   # get the temporary file path, the path to the interpreter, the source
   # file and the path for the generated C source
   printf( "Temporary file path                (target system) : " );
   getline tempPath;
   printf( "Command to run the Awk interpreter (target system) : " );
   getline awkInterpreter;
   printf( "Awk source                           (this system) : " );
   getline awkSource;
   printf( "C source to generate                 (this system) : " );
   getline cSource;
   atEof   = FALSE;
   ioError = FALSE;
   # include headers, output routine and the start of the main routine
   printf( "" ) > cSource;
   emit( "#include <stdio.h>" );
   emit( "#include <errno.h>" );
   emit( "static void w( char * line, FILE * tf )" );
   emit( "{fputs( line, tf );" );
   emit( " if( errno != 0 ){ perror( \"temp\" );exit( 2 ); }" );
   emit( "}" );
   emit( "int main( int argc, char ** argv )" );
   emit( "{FILE * tf = fopen( \"" addEscapes( tempPath ) "\", \"w\" );" );
   emit( " if( tf == NULL ){ perror( \"temp\" );exit( 1 ); }" );
   # output code to write the Awk source to the temporary file
   do
   {
       line = readLine( awkSource );
       sub( / *$/, "", line );
       if( ! atEof && line != "" )
       {
           emit( " w( \"" addEscapes( line ) "\\n\", tf );" )
       } # if ! atEof
   }
   while( ! atEof );
   close( awkSource );
   # code to close the temporary file and interpret it then delete it
   emit( " fclose( tf );" );
   emit( " system( \"" addEscapes( awkInterpreter ) \
         " " addEscapes( tempPath ) "\" );"         \
       );
   emit( " remove( \"" addEscapes( tempPath ) "\" );" );
   emit( "}" );
   close( cSource );
   if( ! ioError )
   {
       printf( "\n%s c source generated\n", cSource );
       printf( "This can now be compiled for the target system "     \
               "(possibly via cross-compilation)\n"                  \
               "using a suitable C compiler\n"                       );
   } # if ! ioError

} # BEGIN


function addEscapes( str, result ) {

   result = str;
   gsub( /[\\]/, "\\\\", result );
   gsub( /"/,    "\\\"", result );

return result; } # addEscapes


function emit( line ) {

   printf( "%s\n", line ) >> cSource;

} # emit


function readLine( fName, ioStat,

                                                                      result )

{

   iostat = ( getline result < fName );
   if( iostat < 1 )
   {
       atEof  = TRUE;
       result = "";
       if( iostat < 0 )
       {
           ioError = TRUE;
           printf( "*** Error reading: %s\n", fName );
       } # if iostat < 0
   } # if iostat < 1


return result; } # readLine</lang>

Output:

Assuming /tmp/t is a temporary file that could be written to by the generated C program and that the command to run the awk interpregter is awk -f, a sample run of the program might be:

Temporary file path                (target system) : /tmp/t
Command to run the Awk interpreter (target system) : awk -f
Awk source                           (this system) : hw.awk
C source to generate                 (this system) : _hw_awk.c

_hw_awk.c c source generated
This can now be compiled for the target system (possibly via cross-compilation)
using a suitable C compiler