Compiler/Simple file inclusion pre processor: Difference between revisions

Content added Content deleted
(Specified the minimum functionality required for the pre-processor.)
m (syntax highlighting fixup automation)
Line 75: Line 75:
When run, the pre-processor will read source from standard input and write the resultant source to standard output. If standard output is re-directed to a temporary source file, it can then be compiled/interpreted with the actual Algol 68 compiler.
When run, the pre-processor will read source from standard input and write the resultant source to standard output. If standard output is re-directed to a temporary source file, it can then be compiled/interpreted with the actual Algol 68 compiler.
<br>(NB: The source must end with a line-feed)
<br>(NB: The source must end with a line-feed)
<lang algol68># Algol 68 pre-processor #
<syntaxhighlight lang="algol68"># Algol 68 pre-processor #
# Processes read/include pragmas in an Algol 68 upper stropping source #
# Processes read/include pragmas in an Algol 68 upper stropping source #
# It is assumed _ is allowd in tags and bold words #
# It is assumed _ is allowd in tags and bold words #
Line 449: Line 449:
FI
FI


END</lang>
END</syntaxhighlight>
{{out}}
{{out}}
Pre-processing the following program:
Pre-processing the following program:
Line 482: Line 482:
<br>It differs from GAWK syntax in that the include directive can appear inside or outside functions. The file name can be quoted or not. Nested includes are not supported.
<br>It differs from GAWK syntax in that the include directive can appear inside or outside functions. The file name can be quoted or not. Nested includes are not supported.
<br>The source can be a named file or read from stdin. If it is read from stdin, <code>-v sec=sourceName</code> can be specified on the AWK command line to name the file. The pre-processed source is writen to stdout.
<br>The source can be a named file or read from stdin. If it is read from stdin, <code>-v sec=sourceName</code> can be specified on the AWK command line to name the file. The pre-processed source is writen to stdout.
<lang awk># include.awk: simple file inclusion pre-processor
<syntaxhighlight lang="awk"># include.awk: simple file inclusion pre-processor
#
#
# the command line can specify:
# the command line can specify:
Line 534: Line 534:
printf( "#line %d %s\n", NR, ( srcName != "" ? srcName : FILENAME ) );
printf( "#line %d %s\n", NR, ( srcName != "" ? srcName : FILENAME ) );


} # includeFile</lang>
} # includeFile</syntaxhighlight>


=={{header|J}}==
=={{header|J}}==
Line 544: Line 544:
This approach is not recursive (and while it seems to offer little advantage over the native implementation of 'load', it does support 'load' inside multi-line string constants, as long as the reference(s) to the content being loaded would be supportable as a J script reference).
This approach is not recursive (and while it seems to offer little advantage over the native implementation of 'load', it does support 'load' inside multi-line string constants, as long as the reference(s) to the content being loaded would be supportable as a J script reference).


<lang J>preproc=: {{
<syntaxhighlight lang="j">preproc=: {{
lines=. <;.2 LF,~CR-.~fread y
lines=. <;.2 LF,~CR-.~fread y
for_ndx. |.I.'load'-:"1 (4&{.@>) lines do.
for_ndx. |.I.'load'-:"1 (4&{.@>) lines do.
Line 555: Line 555:
end.
end.
0!:0;lines
0!:0;lines
}}</lang>
}}</syntaxhighlight>


=={{header|Julia}}==
=={{header|Julia}}==
Line 565: Line 565:
the standard Julia syntax. Calls to the <code>include</code> function that contain a single argument which is a string in parentheses will be preproccessed. Other calls to <code>include</code> with different arguments will not be preprocessed by <code>preprocess.jl</code>.
the standard Julia syntax. Calls to the <code>include</code> function that contain a single argument which is a string in parentheses will be preproccessed. Other calls to <code>include</code> with different arguments will not be preprocessed by <code>preprocess.jl</code>.


<lang julia># preprocess.jl convert includes to file contenets
<syntaxhighlight lang="julia"># preprocess.jl convert includes to file contenets


infile = length(ARGS) > 0 ? ARGS[1] : stdin
infile = length(ARGS) > 0 ? ARGS[1] : stdin
Line 583: Line 583:
output = replace(input, r"\sinclude\(\"[^\"]+\"\)\s" => includefile)
output = replace(input, r"\sinclude\(\"[^\"]+\"\)\s" => includefile)
write(outfile, output)
write(outfile, output)
</syntaxhighlight>
</lang>


=={{header|Phix}}==
=={{header|Phix}}==
Standard feature. Phix ships with a bunch of standard files in a builtins directory, most of which it knows how to "autoinclude", but some must be explicitly included ([http://phix.x10.mx/docs/html/include.htm full docs]). You can explicitly specify the builtins directory or not (obviously without it will look in the project directory first), and use the same mechanism for files you have written yourself. There is no limit to the number or depth of files than can be included. Relative directories are honoured, so if you specify a (partial) directory that is where it will look first for any sub-includes. You can also use single line "stub includes" to redirect include statements to different directories/versions. Note that namespaces are '''not''' supported by pwa/p2js. You can optionally use double quotes, but may then need to escape backslashes. Includes occur at compile time, as opposed to dynamically.
Standard feature. Phix ships with a bunch of standard files in a builtins directory, most of which it knows how to "autoinclude", but some must be explicitly included ([http://phix.x10.mx/docs/html/include.htm full docs]). You can explicitly specify the builtins directory or not (obviously without it will look in the project directory first), and use the same mechanism for files you have written yourself. There is no limit to the number or depth of files than can be included. Relative directories are honoured, so if you specify a (partial) directory that is where it will look first for any sub-includes. You can also use single line "stub includes" to redirect include statements to different directories/versions. Note that namespaces are '''not''' supported by pwa/p2js. You can optionally use double quotes, but may then need to escape backslashes. Includes occur at compile time, as opposed to dynamically.
<!--<lang Phix>-->
<!--<syntaxhighlight lang="phix">-->
<span style="color: #008080;">include</span> <span style="color: #000000;">builtins</span><span style="color: #0000FF;">/</span><span style="color: #004080;">complex</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span>
<span style="color: #008080;">include</span> <span style="color: #000000;">builtins</span><span style="color: #0000FF;">/</span><span style="color: #004080;">complex</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span>
<span style="color: #008080;">include</span> <span style="color: #004080;">complex</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span> <span style="color: #000080;font-style:italic;">-- also valid</span>
<span style="color: #008080;">include</span> <span style="color: #004080;">complex</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span> <span style="color: #000080;font-style:italic;">-- also valid</span>
<span style="color: #008080;">include</span> <span style="color: #008000;">"builtins\\complex.e"</span> <span style="color: #000080;font-style:italic;">-- ditto</span>
<span style="color: #008080;">include</span> <span style="color: #008000;">"builtins\\complex.e"</span> <span style="color: #000080;font-style:italic;">-- ditto</span>
<!--</lang>-->
<!--</syntaxhighlight>-->
If the compiler detects that some file has already been included it does not do it again (from the same directory, two or more files of the same name ''can'' be included from different directories).
If the compiler detects that some file has already been included it does not do it again (from the same directory, two or more files of the same name ''can'' be included from different directories).
I should perhaps also state that include handling is part of normal compilation/interpretation, as opposed to a separate "preprocessing" step, and that each file is granted a new private scope, and while of course there is only one "global" scope, it will use the implicit include hierarchy to automatically resolve any clashes that might arise to the most appropriate one, aka "if it works standalone it should work exactly the same when included in as part of a larger application".
I should perhaps also state that include handling is part of normal compilation/interpretation, as opposed to a separate "preprocessing" step, and that each file is granted a new private scope, and while of course there is only one "global" scope, it will use the implicit include hierarchy to automatically resolve any clashes that might arise to the most appropriate one, aka "if it works standalone it should work exactly the same when included in as part of a larger application".
Line 597: Line 597:
And so on to the task as specified: Since the task specifies it "is about implementing a pre-processor for ''your language'', not just describing it's features" and as per discussions on the talk page, and the above, a "preprocessor" for Phix would fail in so many ways it is simply not really worth attempting, and should certainly never actually be used.<br>
And so on to the task as specified: Since the task specifies it "is about implementing a pre-processor for ''your language'', not just describing it's features" and as per discussions on the talk page, and the above, a "preprocessor" for Phix would fail in so many ways it is simply not really worth attempting, and should certainly never actually be used.<br>
The following will replace include statements with file contents, but do '''not''' expect it to work or do anything useful on any existing [Phix] code. Mutually recursive includes will cause a mutually recursive infinite loop, until you run out of memory, that is without adding some kind of "already done" stack to the following.
The following will replace include statements with file contents, but do '''not''' expect it to work or do anything useful on any existing [Phix] code. Mutually recursive includes will cause a mutually recursive infinite loop, until you run out of memory, that is without adding some kind of "already done" stack to the following.
<!--<lang Phix>-->
<!--<syntaxhighlight lang="phix">-->
<span style="color: #008080;">function</span> <span style="color: #000000;">preprocess</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">filename</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">preprocess</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">filename</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">inlines</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">get_text</span><span style="color: #0000FF;">(</span><span style="color: #000000;">filename</span><span style="color: #0000FF;">,</span><span style="color: #004600;">GT_LF_STRIPPED</span><span style="color: #0000FF;">),</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">inlines</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">get_text</span><span style="color: #0000FF;">(</span><span style="color: #000000;">filename</span><span style="color: #0000FF;">,</span><span style="color: #004600;">GT_LF_STRIPPED</span><span style="color: #0000FF;">),</span>
Line 612: Line 612:
<span style="color: #008080;">return</span> <span style="color: #000000;">outlines</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">outlines</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<!--</lang>-->
<!--</syntaxhighlight>-->
As the Wren entry eloquently puts it: The above code is limited in the sense that all top-level variables of the imported module (not just the specifically "global" ones) are now visible in the outer scope. Consequently, the code will no longer compile if there are any name clashes.
As the Wren entry eloquently puts it: The above code is limited in the sense that all top-level variables of the imported module (not just the specifically "global" ones) are now visible in the outer scope. Consequently, the code will no longer compile if there are any name clashes.


Line 632: Line 632:


A Raku script to do source filtering / preprocessing: save it and call it 'include'
A Raku script to do source filtering / preprocessing: save it and call it 'include'
<lang perl6>unit sub MAIN ($file-name);
<syntaxhighlight lang="raku" line>unit sub MAIN ($file-name);
my $file = slurp $file-name;
my $file = slurp $file-name;
put $file.=subst(/[^^|['{{' \s*]] '#include' \s+ (\S+) \s* '}}'?/, {run(«$*EXECUTABLE-NAME $*PROGRAM-NAME $0», :out).out.slurp(:close).trim}, :g);</lang>
put $file.=subst(/[^^|['{{' \s*]] '#include' \s+ (\S+) \s* '}}'?/, {run(«$*EXECUTABLE-NAME $*PROGRAM-NAME $0», :out).out.slurp(:close).trim}, :g);</syntaxhighlight>


This will find: any line starting with '#include' followed by a (absolute or relative) path to a file, or #include ./path/to/file.name enclosed in double curly brackets anywhere in the file.
This will find: any line starting with '#include' followed by a (absolute or relative) path to a file, or #include ./path/to/file.name enclosed in double curly brackets anywhere in the file.
Line 643: Line 643:


Top level named... whatever, let's call it 'preprocess.raku'
Top level named... whatever, let's call it 'preprocess.raku'
<lang perl6># Top level test script file for #include Rosettacode
<syntaxhighlight lang="raku" line># Top level test script file for #include Rosettacode
# 'Compiler/Simple file inclusion pre processor' task
# 'Compiler/Simple file inclusion pre processor' task


Line 651: Line 651:


#include ./include1.file
#include ./include1.file
</syntaxhighlight>
</lang>


include1.file
include1.file
Line 740: Line 740:


Nevertheless, it is possible to write a limited pre-processor in Wren (the VM itself is written in C):
Nevertheless, it is possible to write a limited pre-processor in Wren (the VM itself is written in C):
<lang ecmascript>import "io" for File
<syntaxhighlight lang="ecmascript">import "io" for File


var source = File.read("source.wren")
var source = File.read("source.wren")
Line 764: Line 764:
}
}


File.create("source2.wren") { |file| file.writeBytes(source) }</lang>
File.create("source2.wren") { |file| file.writeBytes(source) }</syntaxhighlight>
<br>
<br>
The above code is limited in the sense that '''all''' top-level variables of the imported module (not just the specifically imported ones) are now visible in the outer scope. Consequently, the code will no longer compile if there are any name clashes.
The above code is limited in the sense that '''all''' top-level variables of the imported module (not just the specifically imported ones) are now visible in the outer scope. Consequently, the code will no longer compile if there are any name clashes.


The obvious solution of placing the imported code in a block and then 'lifting' the specifically imported variables into the outer scope does not work because of Wren's rather strange scoping rules. If you did this, then the imported module's top level variables would no longer be top-level relative to the code as a whole and hence would no longer be visible to classes defined within the module itself! For example, if you try to run the following script, you get the error shown:
The obvious solution of placing the imported code in a block and then 'lifting' the specifically imported variables into the outer scope does not work because of Wren's rather strange scoping rules. If you did this, then the imported module's top level variables would no longer be top-level relative to the code as a whole and hence would no longer be visible to classes defined within the module itself! For example, if you try to run the following script, you get the error shown:
<lang ecmascript>var B
<syntaxhighlight lang="ecmascript">var B


{ // block starts here
{ // block starts here
Line 783: Line 783:
} // end of block
} // end of block


B.method()</lang>
B.method()</syntaxhighlight>


Other problems include dealing with '''import''' statements which have been commented out (not catered for in the above pre-processor) and resolving import file paths which is not actually set in stone but depends on how Wren is being embedded. The above pre-processor code only deals with paths which are relative to the current directory.
Other problems include dealing with '''import''' statements which have been commented out (not catered for in the above pre-processor) and resolving import file paths which is not actually set in stone but depends on how Wren is being embedded. The above pre-processor code only deals with paths which are relative to the current directory.