4.8 Special Top-Level Statements

Before any of your statements are executed, the Euphoria front-end quickly reads your entire program. All statements are syntax checked and converted to a low-level intermediate language (IL). The interpreter immediately executes the IL after it is completely generated. The translator converts the IL to C. The binder/shrouder saves the IL on disk for later execution. These three tools all share the same front-end (written in Euphoria).

If your program contains only routine and variable declarations, but no top-level executable statements, then nothing will happen when you run it (other than syntax checking). You need a top-level statement to call your main routine (see Example Programs). It's quite possible to have a program with nothing but top-level executable statements and no routines. For example you might want to use Euphoria as a simple calculator, typing just a few print or ? statements into a file, and then executing it.

As we have seen, you can use any Euphoria statement, including for statement, while statement, if statement, etc... (but not return), at the top level i.e. outside of any function or procedure. In addition, the following special statements may only appear at the top level:

  • include
  • with / without

4.8.1 include statement

When you write a large program it is often helpful to break it up into logically separate files, by using include statements. Sometimes you will want to reuse some code that you have previously written, or that someone else has written. Rather than copy this code into your main program, you can use an include statement to refer to the file containing the code. The first form of the include statement is:

include filename
This reads in (compiles) a Euphoria source file.
Some Examples:

include std/graphics.e
include /mylib/myroutines.e
public include library.e

Any top-level code in the included file will be executed at start up time.

Any global identifiers that are declared in the file doing the including will also be visible in the file being included. However the situation is slightly different for an identifier declared as public or export. In these cases the file being included will not see public/export symbols declared in the file doing the including, unless the file being included also explicitly includes the file doing the including. Yes, you would better read that again because its not that obvious. Here's an example...

We have two files, a.e and b.e ...

-- a.e --
? c -- declared as global in 'b.e'
-- b.e --
include a.e
global integer c = 0

This will work because being global the symbol 'c' in b.e can be seen by all files in this include tree.

However ...

-- a.e --
? c -- declared as public in 'b.e'
-- b.e --
include a.e
public integer c = 0

Will not work as public symbols can only be seen when their declaring file is explicitly included. So to get this to work you need to write a.e as ...

-- a.e --
include b.e
? c -- declared as public in 'b.e'

N.B. Only those symbols declared as global in the included file will be visible (accessible) in the remainder of the including file. Their visibility in other included files or in the main program file depends on other factors. Specifically, a global symbols can only be accessed by files in the same include tree. For example...

If we have danny.e declare a global symbol called 'foo', and bob.e includes danny.e, then code in bob.e can access danny's 'foo'. Now if we also have cathy.e declare a global symbol called 'foo', and anne.e includes cathy.e, then code in ann.e can access cathy's 'foo'. Nothing unusual about that situation. Now, if we have a program that includes both bob.e and anne.e, the code in bob.e and anne.e should still work even though there are now two global 'foo' symbols available. This is because the include tree for bob.e only contains danny.e and likewise the include tree for anne.e only contains cathy.e. So as the two 'foo' symbols are in separate include trees (from bob.e and anne.e perspective) code in those files continues to work correctly. A problem can occur if the main program (the one that includes both bob.e and anne.e) references 'foo'. In order for Euphoria to know which one the code author meant to use, the coder must use the namespace facility.

--- mainprog.ex ---
include anne.e as anne
include bob.e  as bob

anne:foo() -- Specify the 'foo' from anne.e.

If the above code did not use namespaces, Euphoria would not have know which 'foo' to use -- the one from bob.e or the one in anne.e.

If public precedes the include statement, then all public identifiers from the included file will also be visible to the including file, and visible to any file that includes the current file.

If an absolute filename is given, Euphoria will open it and start parsing it. When a relative filename is given, Euphoria will try to open the file relative to the following directories, in the following order:

  1. The directory containing the current source file. i.e. the source file that contains the include statement that is being processed.
  2. The directory containing the main file given on the interpreter, translator or binder -- see command_line.
  3. If you've defined an environment variable named EUINC, Euphoria will check each directory listed in EUINC (from left to right). EUINC should be a list of directories, separated by semicolons (colons on Linux / FreeBSD), similar in form to your PATH variable. EUINC can be added to your set of Linux / FreeBSD or Windows environment variables. (Via Control Panel / Performance & Maintenance / System / Advanced on XP, or AUTOEXEC.BAT on older versions of Windows). e.g. SET EUINC=C:\EU\MYFILES;C:\EU\WINDOWSLIB EUINC lets you organize your include files according to application areas, and avoid adding numerous unrelated files to euphoria\include.
  4. Finally, if it still hasn't found the file, it will look in euphoria\include. This directory contains the standard Euphoria include files. The environment variable EUDIR tells Euphoria where to find your euphoria directory.

An included file can include other files. In fact, you can "nest" included files up to 30 levels deep.

Include file names typically end in .e, or sometimes .ew or .eu (when they are intended for use with Windows or Unix). This is just a convention. It is not required.

If your filename (or path) contains blanks or escape-able characters , you must enclose it in double-quotes, otherwise quotes are optional. When a filename is enclosed in double-quotes, you can also use the standard escape character notation to specify filenames that have non-ASCII characters in them.

Note that under Windows, you can also use the forward slash '/' instead of the usually back-slash '\'. By doing this, the file paths are compatible with Unix systems and it means you don't have to 'escape' the back-slashes.
For example:

include "c:/program files/myfile.e"

Other than possibly defining a new namespace identifier (see below), an include statement will be quietly ignored if the same file has already been included.

An include statement must be written on a line by itself. Only a comment can appear after it on the same line.

The second form of the include statement is:

include filename as namespace_identifier:
This is just like the simple include, but it also defines a namespace identifier that can be attached to global identifiers in the included file that you want to refer to in the main file. This might be necessary to disambiguate references to those identifiers, or you might feel that it makes your code more readable. This as identifier namespace exists in the current file, along with any namespace identifier the included file may define.
See Also: Using namespaces.

4.8.2 with / without

These special statements affect the way that Euphoria translates your program into internal form. Options to the with and without statement come in two flavors. One simply turns an option on or off, while the others have multiple states.

4.8.2.1 On / Off options

Default Option
without profile
without profile_time
without trace
without batch
with type_check
with indirect_includes
with inline

with turns on one of the options and without turns off one of the options.

For more information on the profile, profile_time and trace options, see Debugging and Profiling. For more information on the type_check option, see Performance Tips.

There is also a rarely-used special with option where a code number appears after with. In previous releases this code was used by RDS to make a file exempt from adding to the statement count in the old "Public Domain" Edition. This is not used any longer, but does not cause an error.

You can select any combination of settings, and you can change the settings, but the changes must occur between subroutines, not within a subroutine. The only exception is that you can only turn on one type of profiling for a given run of your program.

An included file inherits the with/without settings in effect at the point where it is included. An included file can change these settings, but they will revert back to their original state at the end of the included file. For instance, an included file might turn off warnings for itself and (initially) for any files that it includes, but this will not turn off warnings for the main file.

indirect_includes, This with/without option changes the way in which global symbols are resolved. Normally, the parser uses the way that files were included to resolve a usage of a global symbol. If without indirect_includes is in effect, then only direct includes are considered when resolving global symbols.

This option is especially useful when a program uses some code that was developed for a prior version of Euphoria that uses the pre-4.0 standard library, when all exposed symbols were global. These can often clash with symbols in the new standard library. Using without indirect_includes would not force a coder to use namespaces to resolve symbols that clashed with the new standard library.

Note that this setting does not propagate down to included files, unlike most with/without options. Each file begins with indirect_includes turned on.

with batch, Causes the program to not present the "Press Enter" prompt if an error occurs. The exit code will still be set to 1 on error. This is helpful for programs that run in a mode where no human may be directly interacting with it. For example, a CGI application or a CRON job.

You can also set this option via a command line parameter.

4.8.2.2 Complex with / without options

with / without warning

Any warnings that are issued will appear on your screen after your program has finished execution. Warnings indicate minor problems. A warning will never terminate the execution of your program. You will simply have to hit the Enter key to keep going -- which may stop the program on an unattended computer.

The forms available are ...

with warning
enables all warnings
without warning
disables all warnings
with warning {warning name list}
with warning = {warning name list}
enables only these warnings, and disables all other
without warning {warning name list}
without warning = {warning name list}
enables all warnings except the warnings listed
with warning &= {warning name list}
with warning += {warning name list}
enables listed warnings in addition to whichever are enabled already
without warning &= {warning name list}
without warning += {warning name list}
disables listed warnings and leaves any not listed in its current state.
with warning save
saves the current warning state, i.e. the list of all enabled warnings. This destroys any previously saved state.
with warning restore
causes the previously saved state to be restored.
without warning strict
overrides some of the warnings that the -STRICT command line option tests for, but only until the end of the next function or procedure. The warnings overridden are * default_arg_type * not_used * short_circuit * not_reached * empty_case * no_case_else

The with/without warnings directives will have no effect if the -STRICT command line switch is used. The latter turns on all warnings and ignores any with/without warnings statement. However, it can be temporarily affected by the "without warning strict" directive.


Warning Names


Name Meaning
none When used with the with option, this turns off all warnings. When used with the without option, this turns on all warnings.
resolution an identifier was used in a file, but was defined in a file this file doesn't (recursively) include.
short_circuit a routine call may not take place because of short circuit evaluation in a conditional clause.
override a built-in is being overridden
builtin_chosen an unqualified call caused Euphoria to choose between a built-in and another global which does not override it. Euphoria chooses the built-in.
not_used A variable has not been used and is going out of scope.
no_value A variable never got assigned a value and is going out of scope.
custom Any warning that was defined using the warning() procedure.
not_reached After a keyword that branches unconditionally, the only thing that should appear is an end of block keyword, or possibly a label that a goto statement can target. Otherwise, there is no way that the statement can be reached at all. This warning notifies this condition.
translator An option was given to the translator, but this option is not recognized as valid for the C compiler being used.
cmdline A command line option was not recognized.
mixed_profile For technical reasons, it is not possible to use both with profile and with profile_time in the same section of code. The profile statement read last is ignored, and this warning is issued.
empty_case In switch that have without fallthru, an empty case block will result in no code being executed within the switch statement.
default_case A switch that does not have a case else clause.
default_arg_type Reserved (not in use yet)
deprecated Reserved (not in use yet)
all Turns all warnings on. They can still be disabled by with/without warning directives.

Example

with warning save
without warning &= (builtin_chosen, not_used)
 . . . -- some code that might otherwise issue warnings
with warning restore

Initially, only the following warnings are enabled:

  • resolution
  • override
  • builtin_chosen
  • translator
  • cmdline
  • mixed_profile
  • not_reached
  • custom

This set can be changed using -W or -X command line switches.

with / without define

As mentioned about ifdef statement, this top level statement is used to define/undefine tags which the ifdef statement may use.

The following tags have a predefined meaning in Euphoria:

  • WINDOWS: platform is any version of Windows (tm) from '95 on to Vista and beyond
  • WINDOWS: platform is any kind of Windows system
  • UNIX: platform is any kind of Unix style system
  • LINUX: platform is Linux
  • FREEBSD: platform is FreeBSD
  • OSX: platform is OS X for Macintosh
  • SAFE: turns on a slower debugging version of memory.e called safe.e when defined. Switching mode by renaming files no longer works.
  • EU4: defined on all versions of the version 4 interpreter
  • EU4_0: defined on all versions of the interpreter from 4.0.0 to 4.0.X
  • EU4_0_0: defined only for version 4.0.0 of the interpreter

The name of a tag may contain any character that is a valid identifier character, that is A-Za-z0-9_. It is not required, but by convention defined words are upper case.

4.8.2.3 with / without inline

This directive allows coders some flexibility with inlined routines. The default is for inlining to be on. Any routine that is defined when without inline is in effect will never be inlined.

with inline takes an optional integer parameter that defines the largest routine (by size of IL code) that will be considered for inlining. The default is 30.