Euphoria User Manual
Euphoria User Manual
User Manual
Published 2012-10-13 20:11 UTC
Contents
2 Introduction 4
2.1 Yet Another Programming Language? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.2 Euphoria delivers the expected features of a modern language . . . . . . . . . . . . . . . . . . . . . . . . 4
2.3 Euphoria is unique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.4 Euphoria has qualities that go beyond the elegance of sequences . . . . . . . . . . . . . . . . . . . . . . 5
2.5 As a first programming language . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.6 As an extension to languages you already know . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.7 But, my favorite language is ... . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.8 Products . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.9 Requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.10 Conventions used in the manual . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.11 Discover Euphoria . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.12 Disclaimer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
4 Licensing 11
5 Euphoria Credits 12
5.1 Current Authors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
5.2 Past Authors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
5.3 Contributors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
II Installing Euphoria 14
6 Installation 15
6.1 Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
6.2 Linux and FreeBSD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
6.3 OS X . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
6.4 DOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
7 Post Install 19
ii
8.3 Config File Notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
11 Editing a Program 30
12 Distributing a Program 31
IV Language Reference 34
14 Definition 35
14.1 Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
14.2 Identifiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
14.3 Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
14.4 Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
14.5 Precedence Chart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
15 Declarations 50
15.1 Identifiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
15.2 Specifying the type of a variable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
15.3 Scope . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
16 Assignment statement 66
16.1 Assignment with Operator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
17 Branching Statements 68
17.1 if statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
17.2 switch statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
17.3 ifdef statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
18 Loop statements 76
18.1 while statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
18.2 loop until statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
18.3 for statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
20 Short-Circuit Evaluation 85
V Formal Syntax 93
22 Formal Syntax 94
22.1 Basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
22.2 Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
22.3 Sequence Slice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
22.4 if . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
22.5 ifdef . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
22.6 break . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
22.7 continue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
22.8 retry . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
22.9 exit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
22.10 fallthru . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
22.11 for . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
22.12 while . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
22.13 loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
22.14 goto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
22.15 declare a variable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
22.16 declare a constant . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
22.17 declare an enumerated value . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
22.18 call a procedure or function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
22.19 declare a procedure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
22.20 declare a function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
22.21 declare a user defined type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
22.22 return the result of a function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
22.23 default namespace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
22.24 with options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
VI Mini-Guides 110
24 Debugging and Profiling 111
24.1 Debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
24.2 The Trace Screen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
24.3 The Trace File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
24.4 Profiling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
24.5 Some Further Notes on Time Profiling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
25 Binding and Shrouding 116
25.1 The Shroud Command . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
25.2 The Bind Command . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
41 Console 192
41.1 Information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192
41.2 Key Code names. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193
41.3 Cursor Style Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
41.4 Keyboard related routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195
41.5 Cross Platform Text Graphics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199
42 Date/Time 209
42.1 Localized Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209
42.2 Date/Time type Accessors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210
42.3 Intervals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211
42.4 Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212
42.5 Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212
44 I/O 257
44.1 Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257
44.2 Read/Write Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 258
44.3 Low Level File/Device Handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 267
44.4 File Reading/Writing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274
50 Utilities 329
50.1 Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 329
53 Searching 347
53.1 Equality . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 347
53.2 Finding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 349
53.3 Matching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 358
56 Sorting 412
56.1 Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 412
56.2 Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 413
62 Math 470
62.1 Sign and comparisons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 470
62.2 Roundings and remainders . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 475
62.3 Trigonometry . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 480
62.4 Logarithms and powers. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 486
62.5 Hyperbolic trigonometry . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 490
62.6 Accumulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 493
62.7 Bitwise operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 495
65 Statistics 517
65.1 Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 517
68 Flags 563
68.1 Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 563
74 DNS 642
74.1 Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 642
74.2 General Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 647
xii
Part I
1
Chapter 1
Quick Overview
2
CHAPTER 1. QUICK OVERVIEW
Stand-alone
You can make a single, stand-alone executable file from your program.
Generic
Euphoria routines are naturally generic. The example program below shows a single routine that will sort any type of
data--integers, floating-point numbers, strings etc. Euphoria is not an object-oriented language, yet it achieves
many of the benefits of these languages in a much simpler way.
Free
Euphoria is completely free and open source.
9 n = length ( x )
10 if n = 0 or n = 1 then
11 return x -- trivial case
12 end if
13
32 procedure print_sorted_list ()
33 -- generate sorted_list from original_list
34 sequence sorted_list
35
Euphoria has come a long way since v1.0 was released in July 1993 by Rapid Deployment Software (RDS). There are
now enthusiastic users around the world.
3
Chapter 2
Introduction
4
CHAPTER 2. INTRODUCTION
2.4. EUPHORIA HAS QUALITIES THAT GO BEYOND THE ELEGANCE OF SEQUENCES
Routines are more generic -- a routine used for strings may also be applied to any data structure
A higher level view of programming -- because sequences encompass conventional lists, arrays, tables, tuples, ...,
and all other data-structures.
Sequences are dynamic -- you may create and destroy at will -- and modify them to any size and complexity
Euphoria programs can be translated then compiled as C programs -- fast programs become even faster
Euphoria lets you write multi-tasking programs -- independent of the platform you are using
5
CHAPTER 2. INTRODUCTION 2.8. PRODUCTS
2.8 Products
The Euphoria Interpreter is used to execute your code directly with no binding or compilation steps. Edit, run, edit, run.
The Euphoria Binder is used to create stand-alone programs by binding the Euphoria interpreter onto your source
code.
The Euphoria Translator converts Euphoria-source into C-source. This allows Euphoria programs to be compiled by
a standard C compiler to make even faster stand-alone programs.
You can freely distribute the Euphoria interpreter, and any other files contained in this package, in whole or in part, so
anyone can run a Euphoria program that you have developed. You are completely free to distribute any Euphoria programs
that you write.
2.9 Requirements
To run the Windows version of Euphoria, you need any Windows 95 or any later 32-bit version of Windows. It runs fine
on XP, Vista, and Windows 7.
To run the Unix version of Euphoria you need a supported Unix platform (Linux, FreeBSD, NetBSD or OpenBSD)
and GCC v4.x. Binary packages are available for various platforms and distributions which remove the need for GCC to
be present.
To run the OS X version of Euphoria, you need an Intel based Mac.
On Windows platforms you have two choices. If you run eui then a console window is created. If you run euiw
then no console is created, making it suitable for GUI applications.
The manual will only reference eui in examples and instructions; the reader is left to choose the correct interpreter.
Euphoria runs on many platforms. When operating system specific issues must be described you will see these
descriptions:
Windows will be a general reference to a family of Microsoft Windows operating systems that includes 95/ME/98/XP/NT/Vista/7/
! lines above run off right side of page You will see the constant WINDOWS used for Windows specific code.
Unix will be a general reference to the family operating systems that includes Linux, FreeBSD, NetBSD, OpenBSD,
Mac OS X, ... You will see the constant UNIX used for Unix specific code.
Directory names in Windows use \ separators, while Unix systems use /. Unix users should substitute / when they
examine sample code. Hint: Windows users can now use / in directory names.
Operating system names are often trademarks. There is no intent to infringe on their owners rights. Within a
paragraph, Euphoria keywords (like atom or while) and program excerpts are written in a fixed font.
Samples of Euphoria programs will be syntax colored using a fixed font:
1 for i =1 to 10 do
2 ? i
3 end for
4 -- this is a comment line
5 -- above is a for loop example
6
CHAPTER 2. INTRODUCTION 2.12. DISCLAIMER
2.12 Disclaimer
Euphoria is provided as is without warranty of any kind. In no event shall any authors of Euphoria or contributors to
Euphoria be held liable for any damages arising from the use of, or inability to use, this product.
7
Chapter 3
Whats new in 4.0?
Euphoria v4.0 is a very large jump in functionality from the previous stable release, 3.1.1.
Euphoria has a brand new standard library consisting of over 800 public members. Too numerous to list here, please
see the reference section of this manual.
New logo
Multiline comments using the C-styled comments /* .. */, which can be nested.
Binary, Octal and alternative Decimal and Hexadecimal number format - 0b10 (2), 0t10 (8), 0d10 (10), 0x10
(16)
Hexadecimal string formats. Use \x to embed any byte value into a standard string, or create an entire hexadecimal
byte string using x" ... "
8
CHAPTER 3. WHATS NEW IN 4.0? 3.3. LANGUAGE ENHANCEMENTS
Optional list terminator. The final item in a list can be the dollar symbol ($). This is just a place holder for the
end-of-list, making it easier to add and delete items from the source code without having to adjust the commas.
Assign on declaration. You can now declare a variable and assign it an initial value on the same statement.
The object() built-in function can now be used to safely test if a variable has been initialized or not.
Forward referencing. You no longer need to lexically declare a routine before using it.
loop/until
You can label a loop
while X with entry
exit, continue, retry. All with an optional "label"
goto
export
public (public include)
override
Built in sockets
Resource clean up that can be triggered manually, or when an objects reference count goes to zero
Built in, optimized sequence operations (remove, insert, splice, replace, head, tail)
Built in peek and poke 2 byte values, 1 byte signed values, peek null terminated strings, peek, peek2, peek string,
poke and poke2
Fine grained control over which, if any, warnings will be generated by Euphoria, with / without warning.
9
CHAPTER 3. WHATS NEW IN 4.0? 3.4. TOOL ADDITIONS / ENHANCEMENTS
Interpreter
New test mode, Command line switches
Batch mode for unattended execution such as a CGI application, Command line switches
Translator
Compiles directly
Can compile in debug mode using the -debug argument
Can write a makefile
Can compile/bind a resource file on Windows
Now includes eudbg.lib, eu.a and eudbg.a files in addition to the eu.lib file enabling one to link against
debug libraries and also use the MinGW compiler directly without having to recompile sources.
New independent shrouder
Coverage Analysis
Disassembler
10
Chapter 4
Licensing
This product is free and open source, and has benefited from the contributions of many people. You have complete
royalty-free rights to distribute any Euphoria programs that you develop. You are also free to distribute the interpreter,
backend and even translator. You can shroud or bind your program and distribute the resulting files royalty-free.
You may incorporate any Euphoria source files from this package into your program, either as is or with your
modifications. (You will probably need at least a few of the standard euphoria\include files in any large program).
We would appreciate it if you told people that your program was developed using Euphoria, and gave them the address:
http://www.openeuphoria.org/ of our Web page, but we do not require any such acknowledgment.
Icon files, such as euphoria.ico in euphoria\bin, may be distributed with or without your changes.
The high-speed version of the Euphoria Interpreter back-end is written in ANSI C, and can be compiled with many
different C compilers. The complete source code is in euphoria\source, along with execute.e, the alternate, Euphoria-
coded back-end. The generous Open Source License allows both personal and commercial use, and unlike many other
open source licenses, your changes do not have to be made open source.
Some additional 3rd-party legal restrictions might apply when you use the Euphoria To C Translator.
11
Chapter 5
Euphoria Credits
Euphoria has been continuously developed since it was started in 1993 by Robert Craig. In 2006, version 3.0 was released
as open source. Various releases were made to the 3.x series and then in the 4th quarter of 2010 the largest update ever
was made to Euphoria, starting the Euphoria 4.x series.
It has taken quite a few people to get this far and we would like to recognize them here. Authors/Contributors are
listed in alphabetical order by their last name.
For an up-to-date listing, see the EuphoriaContributors page at the OpenEuphoria Wiki.
Tom Ciplijauskas
Jeremy Cowgar
C. K. Lester
Matthew Lewis
Derek Parnell
Shawn Pringle
Chris Cuvier
Junko Miura
5.3 Contributors
Jiri Babor
Chris Bensler
CoJaBo
12
CHAPTER 5. EUPHORIA CREDITS 5.3. CONTRIBUTORS
Jason Gade
Ryan Johnson
Lonny Nettnay
Marco Antonio Achury Palma
Michael Sabal
13
Part II
Installing Euphoria
14
Chapter 6
Installation
To install Euphoria, consult the instructions below for your particular operating system.
6.1 Windows
All versions other than Windows 95 work without problems. To use Windows 95, it must have Internet Explorer version
4 or higher installed (included in service pack 2.5). To use the new socket functions you will also Windows 2000 or later.
To use all of the new standard library functions you will need at least Windows XP or later.
EUPHORIA is frequently tested on versions Windows XP, Vista, 7.
To install Euphoria on Windows, visit the following URL:
http://openeuphoria.org/wiki/view/DownloadEuphoria.wc
The Standard version is a complete Euphoria installation, with Interpreter, Binder, Translator. Included are demo
programs and documentation.
The Open Watcom version has the contents of the Standard version, plus a bundled compiler. This is a convenient
way of producing compiled executables from Euphoria programs.
Download the latest Windows installer found under the Binary Releases heading of the Current version of Euphoria.
Run the program and follow the prompts to get Euphoria installed.
The installer copies the required files; adds the binary subdirectory to your path, if you leave update environment
checked; and if you leave Associate file extensions checked, it associates icons and various actions to EUPHORIA file
extensions. Please do not open Euphoria Console Files from Explorer; they are meant to be run from the command line.
The installer does not set the environment variable EUDIR to the Euphoria directory even though many third-party
programs expect that to be set. This is so an older version of EUPHORIA can also still work on the same system. To set
this variable please see the section How to manually edit your environment in Windows below.
On WinME/98/95 if the install program fails to edit your autoexec.bat file, you will have to do it yourself. Follow
the manual procedure described below.
Euphoria cannot be run under Windows 3.1 and some unpatched versions of Windows 95 will not be able to run
EUPHORIA 4.0.
You have two EUPHORIA installs and you want to change the environment to use another EUPHORIA.
15
CHAPTER 6. INSTALLATION 6.1. WINDOWS
You can also go to the Start Menu, select Run, type in sysedit and press Enter. autoexec.bat should appear
as one of the system files that you can edit and save.
3. Reboot (restart) your machine. This will define your new PATH and EUDIR environment variables.
Some systems, such as Windows ME, have an autoexec.bat file, but its a hidden file that might not show up
in a directory listing. Nevertheless its there, and you can view it and edit it if necessary by typing, for example:
notepad c:\autoexec.bat in a DOS window.
There is another, optional, environment variable used by some experienced users of Euphoria. It is called EUINC
(see the include statement ). It determines a search path for included files and this variable is used by new and older
versions of EUPHORIA. However, for 4.0 and above we now have a configuration file for adding include paths
and other settings.
16
CHAPTER 6. INSTALLATION 6.2. LINUX AND FREEBSD
You can also set an editor for your EUPHORIA programs this way:
HKEY _CLASS ES_ROOT \ EUWinApp \ shell \ edit \ command "\( Default ) = > C :\ EUPHORIA \ BIN \ euiw . exe C :\ EUPHORIA
HKEY _CLASS ES_ROOT \ EUConsoleApp \ shell \ edit \ command "\( Default ) = > C :\ EUPHORIA \ BIN \ euiw . exe C :\ EUPH
HKEY _CLASS ES_ROOT \ EUInc \ shell \ edit \ command "\( Default ) = > C :\ EUPHORIA \ BIN \ euiw . exe C :\ EUPHORIA \ BI
You can setup to allow the supplied editor program open to the line where the last failure occured in ex.err files:
HKEY _CLASS ES_ROOT \. err \( Default ) = > EUError
HKEY _CLASS ES_ROOT \ EUError \( Default ) = > Error File
HKEY _CLASS ES_ROOT \ EUError \ shell \ debug = > Debug what created this error file
HKEY _CLASS ES_ROOT \ EUError \ shell \ debug \ command \( Default ) = > C :\ EUPHORIA \ BIN \ eui . exe C :\ EUPHORIA \ B
HKEY _CLASS ES_ROOT \ EUError \ DefaultIcon \( Default ) = > C :\ Windows \ system32 \ shell32 . dll ,78
17
CHAPTER 6. INSTALLATION 6.3. OS X
6.3 OS X
Look for an installation package for Apple installations.
http://openeuphoria.org/wiki/view/DownloadEuphoria.wc
6.4 DOS
There is DOS support only up to Euphoria 3.1. DOS developers are invited to contribute their skills.
18
Chapter 7
Post Install
The directory maps will help you locate the Euphoria executables, documentation, and sample programs.
The default for the Windows installation, and optional for a Unix installation:
|
| __ euphoria
| file_id . diz
| License . txt
|
| __ bin
| Interpreter ( eui . exe and euiw . exe , if on Windows )
| ( eui , if on Unix )
| Binder ( eubind , with eub )
| Translator ( euc . exe , if on Windows )
| ( euc , if on Unix )
| Utilities ( bugreport . ex , bench . ex , ed . ex , ...)
|
| __ include
| | ( original include files )
| |
| | __ std ( standard Euphoria library : io .e , sequence .e , ...)
| |
| | __ euphoria ( Euphoria specific )
|
|
| __ docs ( html and pdf documentation files )
|
| __ tutorial ( small tutorial programs to help you learn Euphoria )
|
| __ demo ( generic demo programs that run on all platforms )
| |
| | __ win32 ( Windows specific demo programs ( optional ) )
| | __ unix ( Linux / FreeBSD / OS X specific demo programs ( optional ))
| | __ langwar ( language war game for Linux / FreeBSD / OS X )
| | __ bench ( benchmark program )
|
| __ source ( the complete source code for : interpreter , translator )
|
| __ tests ( unit tests for Euphoria )
|
| __ packaging ( software for making installation packages )
The Linux subdirectory is not included in the Windows distribution, and the win32 subdirectories are not included in
19
CHAPTER 7. POST INSTALL
the Linux/FreeBSD distribution. In this manual, directory names are shown using backslash (\). Linux/FreeBSD users
should substitute forward slash (/).
The Debian Package installs Euphoria into these directories:
|
| __ / usr / bin ( executables : eui , euc , ... )
|
| __ / usr / share / euphoria
| |
| | __ bin ( utility programs )
| | __ demo ( general demonstration programs )
| | __ include ( standard library )
| | __ source ( source - code for Euphoria )
| | __ tutorial ( tutorial programs for learning Euphoria )
|
| __ / usr / share / doc / euphoria ( html and pdf documentation )
|
| __ / etc / euphoria ( eu . cfg )
Additionally, installing from source on a Unix-like OS will install in the same pattern, by default using /usr/local/
instead of /usr/. You can change /usr/local to something else by running:
$ ./ configure -- prefix / some / other / location
Before building.
The include, demo and tutorial directories are the same in Windows and Unix.
20
Chapter 8
Set Up the Euphoria Configuration File (eu.cfg)
Euphoria supports reading command line switches from configuration files. The default name for the configuration file is
eu.cfg. However you can specify different ones by using the -C switch.
21
CHAPTER 8. SET UP THE EUPHORIA CONFIGURATION FILE (EU.CFG) 8.2. CONFIG FILE LOCATIONS
A configuration file is only ever processed once. Additional references to the same file are ignored.
22
Part III
Using Euphoria
23
Chapter 9
Example Programs
The built-in routine puts() does the job of displaying text on a screen. It requires two arguments. The first argument,
1, directs the output to STDOUT or the console. The second argument, is a string of text that will be output.
The result is:
Hello , World
9.2 Sorting
The following is an example of a more useful Euphoria program.
1 include std / console . e
2 sequence original_list
3
9 n = length ( x )
10 if n = 0 or n = 1 then
11 return x -- trivial case
12 end if
13
24
CHAPTER 9. EXAMPLE PROGRAMS 9.2. SORTING
32 procedure print_sorted_list ()
33 -- generate sorted_list from original_list
34 sequence sorted_list
35
The above example contains a number of statements that are processed in order.
include std/console.e
This tells Euphoria that this application needs access to the public symbols declared in the file std/console.e. This
is referred to as a library file. In our case here, the application will be using the display() routine from console.e.
Note that merge sort() will just as easily sort any list of data items ...
{1.5 , -9 , 1 e6 , 100}
{ " oranges " , " apples " , " bananas " }
25
CHAPTER 9. EXAMPLE PROGRAMS 9.3. WHAT TO DO?
This example is stored as euphoria\tutorial\example.ex. This is not the fastest way to sort in Euphoria. Go to
the euphoria\demo directory and type
eui allsorts
to compare timings on several different sorting algorithms for increasing numbers of objects.
For a quick tutorial example of Euphoria programming, see euphoria\demo\bench\filesort.ex.
You can also double-click on a .ex or .exw file from Windows as file associations have been setup during the installation
process.
9.3.3 Benchmark
Create some new benchmark tests. See demo\bench. Do you get the same speed ratios as we did in comparison with
other popular languages? Report your findings on the forum.
The guru program will search all the .doc files, example programs, and other files, and will present you with a sorted
list of the most relevant chunks of text that might answer your enquiry.
26
CHAPTER 9. EXAMPLE PROGRAMS 9.3. WHAT TO DO?
Simple
What if there were 100 C++ ships in Language Wars? What if sb.ex had to move 1000 balls instead of 125? Change
some parameters in polygon.ex. Can you get prettier pictures to appear? Add some funny phrases to buzz.ex.
Harder
Then, some slightly harder ones (takes a few minutes):
Define a new function of x and y in plot3d.ex.
Challenging
Then a challenging one (takes an hour or more):
Set up your own customized database by defining the fields in mydata.ex.
Major
Then a major project (several days or weeks):
Write a smarter 3D TicTacToe algorithm.
Remember that after any error you can simply type: ed to jump into the editor at the offending file and line.
Once you get used to it, youll be developing programs much faster in Euphoria than you could in Perl, Java, C/C++
or any other language that we are aware of.
27
Chapter 10
Creating Euphoria programs
Euphoria programs can be written with any plain text editor. As a convenience Euphoria comes with ed, an editor
written in Euphoria, that is handy for editing and executing Euphoria programs. Take a look at \euphoria\demo and
euphoria\tutorial to see many example programs.
or simply,
eui filesort < rawtxt > sortedtxt
For frequently-used programs under Windows you might want to make a small .bat (batch) file, perhaps called
myprog.bat, containing two statements like:
28
CHAPTER 10. CREATING EUPHORIA PROGRAMS 10.2. RUNNING UNDER WINDOWS
eui myprogex
The first statement turns off echoing of commands to the screen. The second runs eui myprog.ex with up to 9
command-line arguments. See command line() for an example of how to read these arguments. Having a .bat file will
save you the minor inconvenience of typing eui all the time; i.e., you can just type:
myprog
instead of:
eui myprog
Under modern Unix variants, you can use #!/usr/bin/env eui as the first line of your script file. On older Unix
variants, you may need to use the full path to eui, #!/usr/local/bin/eui.
If your program is called foo.ex:
1 / usr / bin / env eui
2
3 procedure foo ()
4 ? 2+2
5 end procedure
6
7 foo ()
to run your program. You could even shorten the name to simply foo. Euphoria ignores the first line when it starts
with #!. Be careful though that your first line ends with the unix-style \n, and not the Windows-style \r\n, or the unix
shell might get confused. If your file is shrouded, you must give the path to eub, not eui.
You can also run bind to combine your Euphoria program with the eui interpreter, to make a stand-alone executable
file. With a stand-alone executable, you can redirect standard input and output. Binding is discussed further in Distributing
a Program.
Using the Euphoria To C Translator, you can also make a stand-alone executable file, and it will normally run much
faster than a bound program.
29
Chapter 11
Editing a Program
You can use any text editor to edit a Euphoria program. However, Euphoria comes with its own special editor that is
written entirely in Euphoria. Type: ed followed by the complete name of the file you wish to edit. You can use this editor
to edit any kind of text file. When you edit a Euphoria file some extra features such as color syntax highlighting and
auto-completion of certain statements are available to make your job easier.
Whenever you run a Euphoria program and get an error message, during compilation or execution, you can simply
type ed with no file name and you will be automatically positioned in the file containing the error, at the correct line and
column, and with the error message displayed at the top of the screen.
Under Windows you can associate ed.bat with various kinds of text files that you want to edit. Color syntax highlighting
is provided for .ex, .exw, .exd, .e and .pro (profile files).
Most keys that you type are inserted into the file at the cursor position. Hit the Esc key once to get a menu bar of
special commands. The arrow keys, and the Insert/Delete/Home/End/PageUp/PageDown keys are also active. Under
Linux/FreeBSD some keys may not be available, and alternate keys are provided. See Ed - Euphoria Editor for a complete
description of the editing commands.
If you need to understand or modify any detail of the editors operation, you can edit the file ed.ex in euphoria\bin
(be sure to make a backup copy so you dont lose your ability to edit). If the name ed conflicts with some other command on
your system, simply rename the file euphoria\bin\ed.bat to something else. Because this editor is written in Euphoria,
it is remarkably concise and easy to understand. The same functionality implemented in a language like C, would take far
more lines of code.
ed is a simple text-mode editor that runs on all platforms and is distributed with Euphoria. There is a list of other
editors at the OpenEuphoria web site, many of which include extra features such as syntax highlighting.
30
Chapter 12
Distributing a Program
In the first method you simply ship your users the interpreter along with your Euphoria source files including any
Euphoria includes that may be necessary from the euphoria/include directory. If the Euphoria source files and the
interpreter are placed together in one directory then your user can run your program by typing eui followed by the path
of your main executable source file. You might also provide a small .bat file so people wont actually have to type the
interpreter name. This method assumes that you are willing to share your Euphoria source code with your users.
The Binder gives you two more methods of distribution. You can shroud your program, or you can bind your program.
Shrouding combines all of the Euphoria source code that your program needs to create a single .il file. Binding combines
your shrouded program with the Euphoria backend (eub or eubw on Windows) to create a single, stand-alone executable
file. For example, if your program is called myprog.ex you can create myprog.exe which will run identically. For
more information about shrouding and binding, see Binding and Shrouding.
Finally, with the Euphoria To C Translator, you can translate your Euphoria program into C and then compile it with
a C compiler to get an executable program.
31
Chapter 13
Command line switches
You can launch Euphoria with some extra command line switches, in order to add or change configuration elements. When
running a GUI, there is always some way to open a prompt and enter any text with options, arguments and whatever the
program being launched may need for proper, expected operation. Under Windows, this is achieved by clicking the Start
button and selecting Run..., or hitting Windows-R.
Command line switches may be changed or added, one at a time.
In the table below, (all) indicates that the given switch applies to the Interpreter, Translator and Binder. Use of
(interpreter), (translator) and/or (binder) indicates that the referenced switch applies only to that execution
mode.
-BATCH (all)
Executes the program but if any error occurs, the Press Enter prompt is not presented. The exit code will be set
to 1 on error, 0 on success. This option can also be set via the with batch directive.
Specifies the include directory for the C compiler once EUPHORIA code is translated.
-COPYRIGHT (all)
Displays the copyright banner for euphoria.
-CON (translator)
Windows only. Specifies that the translated program should be a console application. The default is to build a
windowed application.
-D word (all)
Defines a word as being set. Words are processed by the ifdef statement. Words can also be defined via the with /
without define directive.
-DEBUG (translator)
Enable debug mode for the generated code.
32
CHAPTER 13. COMMAND LINE SWITCHES 13.1. FURTHER NOTES
-H, (all)
Displays the list of available command line options.
-STRICT (all)
This turns on all warnings, overriding any with/without warning statement found in the source. This option can
also be set via the with/without warning directive.
-TEST (all)
Parses the code only and issues any warnings or errors to STDOUT. On error the exit code will be 1, otherwise 0. If
an error was found, the normal Press Enter prompt will not be presented when using the -TEST parameter which
enables many editor/IDE programs to test the syntax of your Euphoria source in real time.
-VERSION (all)
Displays the version of euphoria that is running.
-X;
Resets, or adds to, the list of warnings that will not be issued. This is opposite of the -W switch.
33
Part IV
Language Reference
34
Chapter 14
Definition
14.1 Objects
14.1.1 Atoms and Sequences
All data objects in Euphoria are either atoms or sequences. An atom is a single numeric value. A sequence is a
collection of objects, either atoms or sequences themselves. A sequence can contain any mixture of atom and sequences;
a sequence does not have to contain all the same data type. Because the objects contained in a sequence can be an
arbitrary mix of atoms or sequences, it is an extremely versatile data structure, capable of representing any sort of data.
A sequence is represented by a list of objects in brace brackets , separated by commas with an optional sequence
terminator, $. Atoms can have any integer or double-precision floating point value. They can range from approximately
-1e300 (minus one times 10 to the power 300) to +1e300 with 15 decimal digits of accuracy. Here are some Euphoria
objects:
1 -- examples of atoms :
2 0
3 1000
4 98.6
5 -1 e6
6 23 _100_000
7 x
8 $
9
10 -- examples of sequences :
11 {2 , 3 , 5 , 7 , 11 , 13 , 17 , 19}
12 {1 , 2 , {3 , 3 , 3} , 4 , {5 , {6}}}
13 {{ " jon " , " smith " } , 52389 , 97.25}
14 {} -- the 0 - element sequence
By default, number literals use base 10, but you can have integer literals written in other bases, namely binary (base
2), octal (base 8), and hexadecimal (base 16). To do this, the number is prefixed by a 2-character code that lets Euphoria
know which base to use.
Code Base
0b 2 = Binary
0t 8 = Octal
0d 10 = Decimal
0x 16 = Hexadecimal
For example:
0 b101 -- > decimal 5
0 t101 -- > decimal 65
35
CHAPTER 14. DEFINITION 14.1. OBJECTS
Additionally, hexadecimal integers can also be written by prefixing the number with the # character.
For example:
# FE -- 254
# A000 -- 40960
# FFFF00008 -- 68718428168
-#10 -- -16
Only digits and the letters A, B, C, D, E, F, in either uppercase or lowercase, are allowed in hexadecimal numbers.
Hexadecimal numbers are always positive, unless you add a minus sign in front of the # character. So for instance
1. FFFFFFFF is a huge positive number (4294967295), not -1, as some machine-language programmers might expect.
Sometimes, and especially with large numbers, it can make reading numeric literals easier when they have embedded
grouping characters. We are familiar with using commas (periods in Europe) to group large numbers by three-digit
subgroups. In Euphoria we use the underscore character to achieve the same thing, and we can group them anyway that
is useful to us.
1 atom big = 32 _873_787 -- Set big to the value 32873787
2
Sequences can be nested to any depth, i.e. you can have sequences within sequences within sequences and so on
to any depth (until you run out of memory). Brace brackets are used to construct sequences out of a list of expressions.
These expressions can be constant or evaluated at run-time. e.g.
{ x +6 , 9 , y * w +2 , sin (0.5) }
All sequences can include a special end of sequence marker which is the $ character. This is for convience of editing
lists that may change often as development proceeds.
sequence seq_1 = { 10 , 20 , 30 , $ }
sequence seq_2 = { 10 , 20 , 30 }
The Hierarchical Objects part of the Euphoria acronym comes from the hierarchical nature of nested sequences.
This should not be confused with the class hierarchies of certain object-oriented languages.
Why do we call them atoms? Why not just numbers? Well, an atom is just a number, but we wanted to have a
distinctive term that emphasizes that they are indivisible (thats what atom means in Greek). In the world of physics you
can split an atom into smaller parts, but you no longer have an atom--only various particles. You can split a number
into smaller parts, but you no longer have a number--only various digits.
Atoms are the basic building blocks of all the data that a Euphoria program can manipulate. With this analogy,
sequences might be thought of as molecules, made from atoms and other molecules. A better analogy would be that
sequences are like directories, and atoms are like files. Just as a directory on your computer can contain both files and
other directories, a sequence can contain both atoms and other sequences (and those sequences can contain atoms and
sequences and so on).
. object
. / \
. / \
. atom sequence
36
CHAPTER 14. DEFINITION 14.1. OBJECTS
As you will soon discover, sequences make Euphoria very simple and very powerful. Understanding atoms and
sequences is the key to understanding Euphoria.
Performance Note:
Does this mean that all atoms are stored in memory as eight-byte floating-point numbers? No. The Euphoria
interpreter usually stores integer-valued atoms as machine integers (four bytes) to save space and improve execution
speed. When fractional results occur or integers get too big, conversion to IEEE eight-byte floating-point format
happens automatically.
or
-- Using three double - quotes
" " " ABCDEFG " " "
b " 1001 00110110 0110 _0111 1 _0101_1010 " -- == > {#9 ,#36 ,#67 ,#15 A }
When you put too many hex characters together they are split up appropriately for you:
x " 656667 AE " -- 8 - bit == > {#65 ,#66 ,#67 ,# AE }
5. If they contain the back-slash \ character, that character must immediately be followed by one of the special escape
codes. The back-slash and escape code will be replaced by the appropriate single character equivalent. If you need
to include double-quote, end-of-line, back-slash, or TAB characters inside a double-quoted string, you need to enter
them in a special manner.
e.g.
37
CHAPTER 14. DEFINITION 14.1. OBJECTS
" Bill said \ n \ t \ " This is a back - slash \\ character \ " .\ n "
3 Bill said
3 Bill said
3 _____Bill said
Extended string literals are useful when the string contains new-lines, tabs, or back-slash characters because they do
not have to be entered in the special manner. The back-quote form can be used when the string literal contains a set of
three double-quote characters, and the triple quote form can be used when the text literal contains back-quote characters.
If a literal contains both a back quote and a set of three double-quotes, you will need to concatenate two literals.
object TQ , BQ , QQ
TQ = This text contains " " " for some reason .
BQ = " " " This text contains a back quote for some reason . " " "
QQ = " " " This text contains a back quote " " " & and " " " for some reason .
38
CHAPTER 14. DEFINITION 14.1. OBJECTS
1. they begin with the pair b" and end with a double-quote (") character
2. they can only contain binary digits (0-1), and space, underscore, tab, newline, carriage-return. Anything else is
invalid.
6. The non-digits are treated as punctuation and used to delimit individual values.
1. They begin with the pair x" and end with a double-quote (") character
2. They can only contain hexadecimal digits (0-9 A-F a-f), and space, underscore, tab, newline, carriage-return.
Anything else is invalid.
4. Each pair of contiguous hex digits represents a single sequence element with a value from 0 to 255
6. The non-digits are treated as punctuation and used to delimit individual values.
x " 1 2 34 5678 _AbC " == {0 x01 , 0 x02 , 0 x34 , 0 x56 , 0 x78 , 0 xAB , 0 x0C }
Character strings may be manipulated and operated upon just like any other sequences. For example the string we
first looked at ABCDEFG is entirely equivalent to the sequence:
{65 , 66 , 67 , 68 , 69 , 70 , 71}
which contains the corresponding ASCII codes. The Euphoria compiler will immediately convert ABCDEFG to the
above sequence of numbers. In a sense, there are no strings in Euphoria, only sequences of numbers. A quoted string is
really just a convenient notation that saves you from having to type in all the ASCII codes. It follows that is equivalent
to . Both represent the sequence of zero length, also known as the empty sequence. As a matter of programming style,
it is natural to use to suggest a zero length sequence of characters, and to suggest some other kind of sequence. An
individual character is an atom. It must be entered using single quotes. There is a difference between an individual
character (which is an atom), and a character string of length 1 (which is a sequence). e.g.
Again, B is just a notation that is equivalent to typing 66. There are no characters in Euphoria, just numbers
(atoms). However, it is possible to use characters without ever having to use their numerical representation.
Keep in mind that an atom is not equivalent to a one-element sequence containing the same value, although there are
a few built-in routines that choose to treat them similarly.
39
CHAPTER 14. DEFINITION 14.2. IDENTIFIERS
14.2 Identifiers
An identifier is just the name you give something in your program. This can be a variable, constant, function, procedure,
parameter, or namespace. An identifier must begin with either a letter or an underscore, then followed by zero or more
letters, digits or underscore characters. There is no theoretical limit to how large an identifier can be but in practice it
should be no more than about 30 characters.
Identifiers are case-sensitive. This means that "Name" is a different identifier from "name", or "NAME", etc...
Examples of valid identifiers:
1 n
2 color26
3 ShellSort
4 quick_sort
5 a_very_long_indentifier_that_is_really_too_long_for_its_own_good
6 _alpha
14.3 Comments
Comments are ignored by Euphoria and have no effect on execution speed. The editor displays comments in red.
There are three forms of comment text:
The line format comment is started by two dashes and extends to the end of the current line.
40
CHAPTER 14. DEFINITION 14.4. EXPRESSIONS
e.g.
The multi-line format comment is started by /* and extends to the next occurrence of */, even if that occurs on a
different line.
e.g.
On the first line only of your program, you can use a special comment beginning with the two character sequence
#!. This is mainly used to tell Unix shells which program to execute the script program with.
e.g.
This informs the Linux shell that your file should be executed by the Euphoria interpreter, and gives the full path to
the interpreter. If you make your file executable, you can run it, just by typing its name, and without the need to type
eui. On Windows this line is just treated as a comment (though Apache Web server on Windows does recognize it.).
If your file is a shrouded .il file, use eub.exe instead of eui.
Line comments are typically used to annotate a single (or small section) of code, whereas multi-line comments are
typically used to give larger pieces of documentation inside the source text.
14.4 Expressions
Like other programming languages, Euphoria lets you calculate results by forming expressions. However, in Euphoria you
can perform calculations on entire sequences of data with one expression, where in most other languages you would have
to construct a loop. In Euphoria you can handle a sequence much as you would a single number. It can be copied, passed
to a subroutine, or calculated upon as a unit. For example,
{1 ,2 ,3} + 5
is an expression that adds the sequence 1,2,3 and the atom 5 to get the resulting sequence 6,7,8.
We will see more examples later.
As we will soon see you can also apply these operators to sequences.
41
CHAPTER 14. DEFINITION 14.4. EXPRESSIONS
6 1 or 1 -- 1 ( true )
7 1 or 0 -- 1 ( true )
8 0 or 1 -- 1 ( true )
9 0 or 0 -- 0 ( false )
10
11 1 xor 1 -- 0 ( false )
12 1 xor 0 -- 1 ( true )
13 0 xor 1 -- 1 ( true )
14 0 xor 0 -- 0 ( false )
15
16 not 1 -- 0 ( false )
17 not 0 -- 1 ( true )
You can also apply these operators to numbers other than 1 or 0. The rule is: zero means false and non-zero means
true. So for instance:
5 and -4 -- 1 ( true )
not 6 -- 0 ( false )
Computing a result that is too big (i.e. outside of -1e300 to +1e300) will result in one of the special atoms +infinity
or -infinity. These appear as inf or -inf when you print them out. It is also possible to generate nan or -nan. nan
means not a number, i.e. an undefined value (such as inf divided by inf). These values are defined in the IEEE
floating-point standard. If you see one of these special values in your output, it usually indicates an error in your program
logic, although generating inf as an intermediate result may be acceptable in some cases. For instance, 1/inf is 0, which
may be the right answer for your algorithm.
Division by zero, as well as bad arguments to math library routines, e.g. square root of a negative number, log of a
non-positive number etc. cause an immediate error message and your program is aborted.
The only reason that you might use unary plus is to emphasize to the reader of your program that a number is positive.
The interpreter does not actually calculate anything for this.
42
CHAPTER 14. DEFINITION 14.4. EXPRESSIONS
When applied to a sequence, a unary (one operand) operator is actually applied to each element in the sequence to
yield a sequence of results of the same length. If one of these elements is itself a sequence then the same rule is applied
again recursively. e.g.
x = -{1 , 2 , 3 , {4 , 5}} -- x is { -1 , -2 , -3 , { -4 , -5}}
If a binary (two-operand) operator has operands which are both sequences then the two sequences must be of the same
length. The binary operation is then applied to corresponding elements taken from the two sequences to get a sequence
of results. e.g.
1 x = {5 , 6 , 7 , 8} + {10 , 10 , 20 , 100}
2 -- x is {15 , 16 , 27 , 108}
3 x = {{1 , 2 , 3} , {4 , 5 , 6}} + { -1 , 0 , 1} -- ERROR : 2 != 3
4 -- but
5 x = {{1 , 2 , 3} + { -1 , 0 , 1} , {4 , 5 , 6} + { -1 , 0 , 1}} -- CORRECT
6 -- x is {{0 , 2 , 4} , {3 , 5 , 7}}
If a binary operator has one operand which is a sequence while the other is a single number (atom) then the single
number is effectively repeated to form a sequence of equal length to the sequence operand. The rules for operating on
two sequences then apply. Some examples:
1 y = {4 , 5 , 6}
2 w = 5 * y -- w is {20 , 25 , 30}
3
4 x = {1 , 2 , 3}
5 z = x + y -- z is {5 , 7 , 9}
6 z = x < y -- z is {1 , 1 , 1}
7
8 w = {{1 , 2} , {3 , 4} , {5}}
9 w = w * y -- w is {{4 , 8} , {15 , 20} , {30}}
10
11 w = {1 , 0 , 0 , 1} and {1 , 1 , 1 , 0} -- {1 , 0 , 0 , 0}
12 w = not {1 , 5 , -2 , 0 , 0} -- w is {0 , 0 , 0 , 1 , 1}
13
14 w = {1 , 2 , 3} = {1 , 2 , 4} -- w is {1 , 1 , 0}
15
Note: When you wish to compare two strings (or other sequences), you should not (as in some other languages) use
the = operator:
if " APPLE " = " ORANGE " then -- ERROR !
= is treated as an operator, just like +, * etc., so it is applied to corresponding sequence elements, and the sequences
must be the same length. When they are equal length, the result is a sequence of ones an zeros. When they are not
equal length, the result is an error. Either way youll get an error, since an if-condition must be an atom, not a sequence.
Instead you should use the equal() built-in routine:
if equal ( " APPLE " , " ORANGE " ) then -- CORRECT
In general, you can do relational comparisons using the compare() built-in routine:
if compare ( " APPLE " , " ORANGE " ) = 0 then -- CORRECT
Especially useful is the idiom compare(x, "") = 1 to determine whether x is a non empty sequence. compare(x,
"") = -1 would test for x being an atom, but atom(x) = 1 does the same faster and is clearer to read.
43
CHAPTER 14. DEFINITION 14.4. EXPRESSIONS
Then x becomes: 5, 11,22,33, 9, 0.5, 13. Now if we ask for x[2] we get 11,22,33 and if we ask for x[2][3]
we get the atom 33. If you try to subscript with a number that is outside of the range 1 to the number of elements, you will
get a subscript error. For example x[0], x[-99] or x[6] will cause errors. So will x[1][3] since x[1] is not a sequence.
There is no limit to the number of subscripts that may follow a variable, but the variable must contain sequences that are
nested deeply enough. The two dimensional array, common in other languages, can be easily represented with a sequence
of sequences:
1 x = {
2 {5 , 6 , 7 , 8 , 9} , -- x [1]
3 {1 , 2 , 3 , 4 , 5} , -- x [2]
4 {0 , 1 , 0 , 1 , 0} -- x [3]
5 }
where we have written the numbers in a way that makes the structure clearer. An expression of the form x[i][j] can be
used to access any element.
The two dimensions are not symmetric however, since an entire row can be selected with x[i], but you need to use
vslice() in the Standard Library to select an entire column. Other logical structures, such as n-dimensional arrays, arrays
of strings, structures, arrays of structures etc. can also be handled easily and flexibly:
3-D array:
1 y = {
2 {{1 ,1} , {3 ,3} , {5 ,5}} ,
3 {{0 ,0} , {0 ,1} , {9 ,1}} ,
4 {{ -1 ,9} ,{1 ,1} , {2 ,2}}
5 }
6
7 -- y [2][3][1] is 9
Array of strings:
s = { " Hello " , " World " , " Euphoria " , " " , " Last One " }
A Structure:
1 employee = {
2 { " John " ," Smith " } ,
3 45000 ,
4 27 ,
5 185.5
6 }
To access fields or elements within a structure it is good programming style to make up an enum that names the
various fields. This will make your program easier to read. For the example above you might have:
1 enum NAME , SALARY , AGE , WEIGHT
2 enum FIRST_NAME , LAST_NAME
3
4 employees = {
5 {{ " John " ," Smith " } , 45000 , 27 , 185.5} , -- a [1]
6 {{ " Bill " ," Jones " } , 57000 , 48 , 177.2} , -- a [2]
44
CHAPTER 14. DEFINITION 14.4. EXPRESSIONS
7 -- .... etc .
8 }
9
The length() built-in function will tell you how many elements are in a sequence. So the last element of a sequence
s, is:
s [ length ( s )]
Similarly,
s [ length ( s ) -1]
The $ may only appear between square braces and it equals the length of the sequence that is being subscripted.
Where theres nesting, e.g.:
s [ $ - t [$ -1] + 1]
The first $ above refers to the length of s, while the second $ refers to the length of t (as youd probably expect).
An example where $ can save a lot of typing, make your code clearer, and probably even faster is:
longname [ $ ][ $ ] -- last element of the last element
The expressions are evaluated, and any subscripting is performed, from left to right. It is possible to have function
calls in the right-hand-side expression, or in any of the left-hand-side expressions. If a function call has the side-effect
of modifying the lhs var, it is not defined whether those changes will appear in the final value of the lhs var, once the
assignment has been completed. To be sure about what is going to happen, perform the function call in a separate
statement, i.e. do not try to modify the lhs var in two different ways in the same statement. Where there are no left-
hand-side subscripts, you can always assume that the final value of the lhs var will be the value of rhs expr, regardless of
any side-effects that may have changed lhs var.
Euphoria data structures are almost infinitely flexible.
Arrays in many languages are constrained to have a fixed number of elements, and those elements must all be of
the same type. Euphoria eliminates both of those restrictions by defining all arrays (sequences) as a list of zero or more
Euphoria objects whose element count can be changed at any time. You can easily add a new structure to the employee
sequence above, or store an unusually long name in the NAME field and Euphoria will take care of it for you. If you
wish, you can store a variety of different employee structures, with different sizes, all in one sequence. However, when
you retrieve a sequence element, it is not guaranteed to be of any type. You, as a programmer, need to check that the
retrieved data is of the type youd expect, Euphoria will not. The only thing it will check is whether an assignment is
legal. For example, if you try to assign a sequence to an integer variable, Euphoria will complain at the time your code
does the assignment.
Not only can a Euphoria program represent all conventional data structures but you can create very useful, flexible
structures that would be hard to declare in many other languages.
Note that expressions in general may not be subscripted, just variables. For example: 5+2,6-1,7*8,8+1[3] is not
supported, nor is something like: date()[MONTH]. You have to assign the sequence returned by date() to a variable, then
subscript the variable to get the month.
45
CHAPTER 14. DEFINITION 14.4. EXPRESSIONS
3 4 & 5 -- {4 , 5}
4
7 x = {}
8 y = {1 , 2}
9 y = y & x -- y is still {1 , 2}
You can delete element i of any sequence s by concatenating the parts of the sequence before and after i:
s = s [1.. i -1] & s [ i +1.. length ( s )]
This works even when i is 1 or length(s), since s[1..0] is a legal empty slice, and so is s[length(s)+1..length(s)].
14.4.8 Sequence-Formation
Finally, sequence-formation, using braces and commas:
{a , b , c , ... }
is also an operator. It takes n operands, where n is 0 or more, and makes an n-element sequence from their values.
e.g.
x = { apple , orange *2 , {1 ,2 ,3} , 99/4+ foobar }
46
CHAPTER 14. DEFINITION 14.4. EXPRESSIONS
length(sequence s)
Returns the length of a sequence s.
This is the number of elements in s. Some of these elements may be sequences that contain elements of their own,
but length just gives you the top-level count. Note however that the length of an atom is always 1. e.g.
length ({5 ,6 ,7}) -- 3
length ({1 , {5 ,5 ,5} , 2 , 3}) -- 4 ( not 6!)
length ({}) -- 0
length (5) -- 1
The length of the new sequence is always 1 greater than the length of the original sequence. The item to be added to
the sequence can be any atom or sequence.
The length of the new sequence is always one greater than the length of the original sequence. The item to be added
to the sequence can be any atom or sequence.
These two built-in functions, append() and prepend(), have some similarities to the concatenate operator, &, but
there are clear differences. e.g.
1 -- appending a sequence is different
2 append ({1 ,2 ,3} , {5 ,5 ,5}) -- {1 ,2 ,3 ,{5 ,5 ,5}}
3 {1 ,2 ,3} & {5 ,5 ,5} -- {1 ,2 ,3 ,5 ,5 ,5}
47
CHAPTER 14. DEFINITION 14.5. PRECEDENCE CHART
The length of the returned sequence is one more than the one of in what. This is the same rule as for append() and
prepend() above, which are actually special cases of insert().
The length of splice(in what, what, position) always is length(in what) + length(what), like for concate-
nation using &.
lowest precedence
{ , , , }
48
CHAPTER 14. DEFINITION 14.5. PRECEDENCE CHART
Thus 2+6*3 means 2+(6*3) rather than (2+6)*3. Operators on the same line above have equal precedence and are
evaluated left to right. You can force any order of operations by placing round brackets ( ) around an expression. For
instance, 6/3*5 is 2*5, not 6/15.
Different languages or contexts may have slightly different precedence rules. You should be careful when translating
a formula from a language to another; Euphoria is no exception. Adding superfluous parentheses to explicitly denote
the exact order of evaluation does not cost much, and may help either readers used to some other precedence chart or
translating to or from another context with slightly different rules. Watch out for and and or, or * and /.
The equals symbol = used in an assignment statement is not an operator, its just part of the syntax of the language.
49
Chapter 15
Declarations
15.1 Identifiers
Identifiers, which encompass all explicitly declared variable, constant or routine names, may be of any length. Upper
and lower case are distinct. Identifiers must start with a letter or underscore and then be followed by any combination of
letters, digits and underscores. The following reserved words have special meaning in Euphoria and cannot be used as
identifiers:
1 and export public
2 as fallthru retry
3 break for return
4 by function routine
5 case global switch
6 constant goto then
7 continue if to
8 do ifdef type
9 else include until
10 elsedef label while
11 elsif loop with
12 elsifdef namespace without
13 end not xor
14 entry or
15 enum override
16 exit procedure
50
CHAPTER 15. DECLARATIONS 15.1. IDENTIFIERS
15.1.1 procedures
These perform some computation and may contain a list of parameters, e.g.
1 procedure empty ()
2 end procedure
3
There are a fixed number of named parameters, but this is not restrictive since any parameter could be a variable-length
sequence of arbitrary objects. In many languages variable-length parameter lists are impossible. In C, you must set up
strange mechanisms that are complex enough that the average programmer cannot do it without consulting a manual or
a local guru.
A copy of the value of each argument is passed in. The formal parameter variables may be modified inside the procedure
but this does not affect the value of the arguments. Pass by reference can be achieved using indexes into some fixed
sequence.
Performance Note:
The interpreter does not actually copy sequences or floating-point numbers unless it becomes necessary. For example,
y = {1 ,2 ,3 ,4 ,5 ,6 ,7 ,8.5 , " ABC " }
x = y
The statement x = y does not actually cause a new copy of y to be created. Both x and y will simply point to the
same sequence. If we later perform x[3] = 9, then a separate sequence will be created for x in memory (although
there will still be just one shared copy of 8.5 and "ABC"). The same thing applies to copies of arguments passed
in to subroutines.
For a number of procedures or functions--see below--some parameters may have the same value in many cases. The
most expected value for any parameter may be given a default value. Omitting the value of such a parameter on a given
call will cause its default value to be passed.
51
CHAPTER 15. DECLARATIONS 15.1. IDENTIFIERS
5 foo ( " abc " ) -- prints out 4 = 3 + 1. n was not specified , so was set to 1.
6 foo ( " abc " , 3) -- prints out 6 = 3 + 3
Any expression may be used in a default value. Parameters that have been already mentioned may even be part of the
expression:
1 procedure baz ( sequence s , integer n = length ( s ))
2 ? n
3 end procedure
4
15.1.2 functions
These are just like procedures, but they return a value, and can be used in an expression, e.g.
1 function max ( atom a , atom b )
2 if a >= b then
3 return a
4 else
5 return b
6 end if
7 end function
However, Euphoria does not have variable lists. When you return a sequence, you still have to dispatch its contents to
variables as needed. And you cannot pass a sequence of parameters to a routine, unless using call func or call proc, which
carries a performance penalty.
We will use the general term subroutine, or simply routine when a remark is applicable to both procedures and
functions.
Defaulted parameters can be used in functions exactly as they are in procedures. See the section above for a few
examples.
52
CHAPTER 15. DECLARATIONS 15.1. IDENTIFIERS
15.1.4 types
These are special functions that may be used in declaring the allowed values for a variable. A type must have exactly one
parameter and should return an atom that is either true (non-zero) or false (zero). Types can also be called just like other
functions. See Specifying the Type of a variable.
Although there are no restrictions to using defaulted parameters with types, their use is so much constrained by a type
having exactly one parameter that they are of little practical help there.
You cannot use a type to perform any adjustment to the value being checked, if only because this value may be the
temporary result of an expression, not an actual variable.
15.1.5 variables
These may be assigned values during execution e.g.
1 -- x may only be assigned integer values
2 integer x
3 x = 25
4
When you declare a variable you name the variable (which protects you against making spelling mistakes later on) and
you define which sort of values may legally be assigned to the variable during execution of your program.
The simple act of declaring a variable does not assign any value to it. If you attempt to read it before assigning any
value to it, Euphoria will issue a run-time error as variable xyz has never been assigned a value.
To guard against forgetting to initialize a variable, and also because it may make the code clearer to read, you can
combine declaration and assignment:
integer n = 5
This is equivalent to
integer n
n = 5
It is not infrequent that one defines a private variable that bears the same name as one already in scope. You can
reuse the value of that variable when performing an initialization on declare by using a default namespace for the current
file:
1 namespace app
2
3 integer n
4 n =5
5
6 procedure foo ()
7 integer n = app : n + 2
8 ? n
9 end procedure
10
15.1.6 constants
These are variables that are assigned an initial value that can never change e.g.
53
CHAPTER 15. DECLARATIONS 15.1. IDENTIFIERS
The result of any expression can be assigned to a constant, even one involving calls to previously defined functions,
but once the assignment is made, the value of the constant variable is locked in.
Constants may not be declared inside a subroutine.
15.1.7 enum
An enumerated value is a special type of constant where the first value defaults to the number 1 and each item after that
is incremented by 1 by default. An optional by keyword can be supplied to change the increment value. As with sequences,
enums can also be terminated with a $ for ease of editing enum lists that may change frequently during development.
enum ONE , TWO , THREE , FOUR
You can change the value of any one item by assigning it a numeric value. Enums can only take numeric values. You
cannot set the starting value to an expression or other variable. Subsequent values are always the previous value plus one,
unless they too are assigned a default value.
enum ONE , TWO , THREE , ABC =10 , DEF , XYZ
Euphoria sequences use integer indexes, but with enum you may write code like this:
enum X , Y
sequence point = { 0 ,0 }
point [ X ] = 3
point [ Y ] = 4
There is also a special form of enum, an enum type. This is a simple way to write a user-defined type based on the
set of values in a specific enum group. The type created this way can be used anywhere a normal user-defined type can
be use.
For example,
1 enum type RGBA RED , GREEN , BLUE , ALPHA end type
2
However there is one significant difference when it comes to enum types. For normal types, when calling the type
function, it returns either 0 or 1. The enum type function returns 0 if the argument is not a member of the enum set, and
it returns a positive integer when the argument is a member. The value returned is the ordinal number of the member
in the enums definition, regardless of what the members value is. As an exception to this, if two enums share the same
value, then they will share the same ordinal number. The ordinal numbers of enums surrounding these will continue to
increment as if every enum had a unique ordinal number, causing some numbers to be skipped.
For example,
1 enum type color RED =4 , GREEN =7 , BLACK =1 , BLUE =3 , PINK =10 end type
2
54
CHAPTER 15. DECLARATIONS 15.2. SPECIFYING THE TYPE OF A VARIABLE
9 constant color_names = { " rouge " , " vert " , " noir " , " bleu " , " rose " }
10
Note that none of the enums have an ordinal number with a value of 3. This is simply skipped.
By default, unless an enum member is being specifically set to some value, its value will be one more than the previous
members value, with the first default value being 1. This default can be overridden. The syntax is:
enum by DELTA member1 , member2 , ... , memberN
where DELTA is a literal number with an optional operation code (*, +, -, /) preceding it.
Examples:
enum by 2 A ,B , C =6 , D -- > values are 1 ,3 ,6 ,8
enum by -2 A =10 , B ,C , D -- > values are 10 ,8 ,6 ,4
enum by * 2 A ,B ,C ,D , E -- > values are 1 ,2 ,4 ,8 ,16
enum by / 3 A =81 , B ,C ,D , E -- > values are 81 ,27 ,9 ,3 ,1
3 global integer x , y , z
4
The types: object, sequence, atom and integer are predefined. Variables of type object may take on any value.
Those declared with type sequence must always be sequences. Those declared with type atom must always be atoms.
Variables declared with type integer must be atoms with integer values from -1073741824 to +1073741823 inclusive.
You can perform exact calculations on larger integer values, up to about 15 decimal digits, but declare them as atom,
rather than integer.
Note:
In a procedure or function parameter list like the one for fred() above, a type name may only be followed by a
single parameter name.
Performance Note:
Calculations using variables declared as integer will usually be somewhat faster than calculations involving variables
declared as atom. If your machine has floating-point hardware, Euphoria will use it to manipulate atoms that are not
55
CHAPTER 15. DECLARATIONS 15.2. SPECIFYING THE TYPE OF A VARIABLE
integers. If your machine doesnt have floating-point hardware (this may happen on old 386 or 486 PCs), Euphoria
will call software floating-point arithmetic routines contained in euid.exe (or in Windows). You can force eui.exe
to bypass any floating-point hardware, by setting an environment variable:
SET NO87 =1
The slower software routines will be used, but this could be of some advantage if you are worried about the floating-
point bug in some early Pentium chips.
5 hour h1 , h2
6
7 h1 = 10 -- ok
8 h2 = 25 -- error ! program aborts with a message
Variables h1 and h2 can only be assigned integer values in the range 0 to 23 inclusive. After each assignment to h1 or
h2 the interpreter will call hour(), passing the new value. The value will first be checked to see if it is an integer (because
of integer x). If it is, the return statement will be executed to test the value of x (i.e. the new value of h1 or h2). If
hour() returns true, execution continues normally. If hour() returns false then the program is aborted with a suitable
diagnostic message.
hour can be used to declare subroutine parameters as well:
procedure set_time ( hour h )
set time() can only be called with a reasonable value for parameter h, otherwise the program will abort with a
message.
A variables type will be checked after each assignment to the variable (except where the compiler can predetermine that
a check will not be necessary), and the program will terminate immediately if the type function returns false. Subroutine
parameter types are checked each time that the subroutine is called. This checking guarantees that a variable can never
have a value that does not belong to the type of that variable.
Unlike other languages, the type of a variable does not affect any calculations on the variable, nor the way its contents
are displayed. Only the value of the variable matters in an expression. The type just serves as an error check to prevent
any corruption of the variable. User-defined types can catch unexpected logical errors in your program. They are not
designed to catch or correct user input errors. In particular, they cannot adjust a wrong value to some other, presumably
legal, one.
Type checking can be turned off or on between subroutines using the with type check or without type check (see
specialstatements). It is initially on by default.
56
CHAPTER 15. DECLARATIONS 15.2. SPECIFYING THE TYPE OF A VARIABLE
Euphorias method of defining types is simpler than what you will find in other languages, yet Euphoria provides the
programmer with greater flexibility in defining the legal values for a type of data. Any algorithm can be used to include
or exclude values. You can even declare a variable to be of type object which will allow it to take on any value. Routines
can be written to work with very specific types, or very general types.
For many programs, there is little advantage in defining new types, and you may wish to stick with the four predefined
types. Unlike other languages, Euphorias type mechanism is optional. You dont need it to create a program.
However, for larger programs, strict type definitions can aid the process of debugging. Logic errors are caught close to
their source and are not allowed to propagate in subtle ways through the rest of the program. Furthermore, it is easier to
reason about the misbehavior of a section of code when you are guaranteed that the variables involved always had a legal
value, if not the desired value.
Types also provide meaningful, machine-checkable documentation about your program, making it easier for you or
others to understand your code at a later date. Combined with the subscript checking, uninitialized variable checking,
and other checking that is always present, strict run-time type checking makes debugging much easier in Euphoria than in
most other languages. It also increases the reliability of the final program since many latent bugs that would have survived
the testing phase in other languages will have been caught by Euphoria.
Anecdote 1:
In porting a large C program to Euphoria, a number of latent bugs were discovered. Although this C program was
believed to be totally correct, we found: a situation where an uninitialized variable was being read; a place where
element number -1 of an array was routinely written and read; and a situation where something was written just
off the screen. These problems resulted in errors that werent easily visible to a casual observer, so they had survived
testing of the C code.
Anecdote 2:
The Quick Sort algorithm presented on page 117 of Writing Efficient Programs by Jon Bentley has a subscript
error! The algorithm will sometimes read the element just before the beginning of the array to be sorted, and will
sometimes read the element just after the end of the array. Whatever garbage is read, the algorithm will still work
- this is probably why the bug was never caught. But what if there isnt any (virtual) memory just before or just
after the array? Bentley later modifies the algorithm such that this bug goes away--but he presented this version
as being correct. Even the experts need subscript checking!
Performance Note:
When typical user-defined types are used extensively, type checking adds only 20 to 40 percent to execution time.
Leave it on unless you really need the extra speed. You might also consider turning it off for just a few heavily-
executed routines. Profiling can help with this decision.
15.2.2 integer
An Euphoria integer is a mathematical integer restricted to the range -1,073,741,824 to +1,073,741,823. As a result,
a variable of the integer type, while allowing computations as fast as possible, cannot hold 32-bit machine addresses, even
though the latter are mathematical integers. You must use the atom type for this purpose. Also, even though the product
of two integers is a mathematical integer, it may not fit into an integer, and should be kept in an atom instead.
15.2.3 atom
An atom can hold three kinds of data:
Mathematical integers in the range -power(2,53) to +power(2,53)
Floating point numbers, in the range -power(2,1024)+1 to +power(2,1024)-1
Large mathematical integers in the same range, but with a fuzz that grows with the magnitude of the integer.
power(2,53) is slightly above 9.1015 , power(2,1024) is in the 10308 range.
Because of these constraints, which arise in part from common hardware limitations, some care is needed for specific
purposes:
57
CHAPTER 15. DECLARATIONS 15.3. SCOPE
The sum or product of two integers is an atom, but may not be an integer.
Memory addresses, or handles acquired from anything non Euphoria, including the operating system, must be stored
as an atom.
This is not an Euphoria bug. The IEEE 754 standard for floating point numbers provides for 53 bits of precision for any
real number, and an accurate computation of a-a1 would require 54 of them. Intel FPU chips do have 64 bit precision
registers, but the low order 16 bits are only used internally, and Intel recommends against using them for high precision
arithmetic. Their SIMD machine instruction set only uses the IEEE 754 defined format.
15.2.4 sequence
A sequence is a type that is a container. A sequence has elements which can be accessed through their index, like in
my sequence[3]. sequences are so generic as being able to store all sorts of data structures: strings, trees, lists, anything.
Accesses to sequences are always bound checked, so that you cannot read or write an element that does not exist, ever. A
large amount of extraction and shape change operations on sequences is available, both as built-in operations and library
routines. The elements of a sequence can have any type.
sequences are implemented very efficiently. Programmers used to pointers will soon notice that they can get most
usual pointer operations done using sequence indexes. The loss in efficiency is usually hard to notice, and the gain in code
safety and bug prevention far outweighs it.
15.2.5 object
This type can hold any data Euphoria can handle, both atoms and sequences.
The object() type returns 0 if a variable is not initialized, else 1.
15.3 Scope
15.3.1 Why scopes, and what are they?
The scope of an identifier is the portion of the program where its declaration is in effect, i.e. where that identifier is visible.
Euphoria has many pre-defined procedures, functions and types. These are defined automatically at the start of any
program. The Euphoria editor shows them in magenta. These pre-defined names are not reserved. You can override them
with your own variables or routines.
It is possible to use a user-defined identifier before it has been declared, provided that it will be declared at some point
later in the program.
For example, procedures, functions and types can call themselves or one another recursively. Mutual recursion, where
routine A calls routine B which directly or indirectly calls routine A, implies one of A or B being called before it is defined.
This was traditionally the most frequent situation which required using the routine id() mechanism, but is now supported
directly. See Indirect Routine Calling for more details on the routine id() mechanism.
58
CHAPTER 15. DECLARATIONS 15.3. SCOPE
If it is declared within a for, while, loop or switch, its scope starts at the declaration and ends at the respective
end statement.
In an if statement, the scope starts at the declaration and ends either at the next else, elsif or end if statement.
If a variable is declared within a routine (known as a private variable) and outside one of the structures listed above,
the scope of the variable starts at the declaration and ends at the routines end statement.
If a variable is declared outside of a routine (known as a module variable), and does not have a scope modifier, its
scope starts at the declaration and ends at the end of the file it is declared in.
The scope of a constant that does not have a scope modifier, starts at the declaration and ends at the end of the file
it is declared in.
The scope of a enum that does not have a scope modifier, starts at the declaration and ends at the end of the file it
is declared in.
The scope of all procedures, functions and types, which do not have a scope modifier, starts at the beginning of the
source file and ends at the end of the source file in which they are declared. In other words, these can be accessed by any
code in the same file.
Constants, enums, module variables, procedures, functions and types, which do not have a scope modifier are referred
to as local. However, these identifiers can have a scope modifier preceding their declaration, which causes their scope to
extend beyond the file they are declared in.
If the keyword global precedes the declaration, the scope of these identifiers extends to the whole application. They
can be accessed by code anywhere in the application files.
If the keyword public precedes the declaration, the scope extends to any file that explicitly includes the file in which
the identifier is declared, or to any file that includes a file that in turn public includes the file containing the
public declaration.
If the keyword export precedes the declaration, the scope only extends to any file that directly includes the file in
which the identifier is declared.
When you Z a Euphoria file in another file, only the identifiers declared using a scope modifier are accessible to the
file doing the include. The other declarations in the included file are invisible to the file doing the include, and you will
get an error message, Errors resolving the following references, if you try to use them.
There is a variant of the include statement, called public include, which will be discussed later and behaves differently
on public symbols.
Note that constant and enum declarations must be outside of any subroutine.
Euphoria encourages you to restrict the scope of identifiers. If all identifiers were automatically global to the whole
program, you might have a lot of naming conflicts, especially in a large program consisting of files written by many
different programmers. A naming conflict might cause a compiler error message, or it could lead to a very subtle bug,
where different parts of a program accidentally modify the same variable without being aware of it. Try to use the most
restrictive scope that you can. Make variables private to one routine where possible, and where that is not possible, make
them local to a file, rather than global to the whole program. And whenever an identifier needs to be known from a few
files only, make it public or export so as to hide it from whoever does not need to see it and might some day define
the same identifier.
For example:
1 -- sublib . e
2 export procedure bar ()
3 ?0
4 end procedure
5
6 -- some_lib . e
7 include sublib . e
8 export procedure foo ()
9 ?1
10 end procedure
59
CHAPTER 15. DECLARATIONS 15.3. SCOPE
13 -- my_app . exw
14 include some_lib . e
15 foo () -- ok , declared in some_lib . e
16 bar () -- error ! bar () is not declared here
Why not declare foo() as global, as it is meant to be used anywhere? Well, one could, but this will increase the
risks of name conflicts. This is why, for instance, all public identifiers from the standard library have public scope. global
should be used rarely, if ever. Because earlier versions of Euphoria didnt have public or export, it has to remain there
for a while. One should be very sure of not polluting any foreign files symbol table before using global scope. Built-in
identifiers act as if declared as global but they are not declared in any Euphoria coded file.
4 john : x += 1
5 bill : x += 2
In this case, the variable x was declared in two different files, and you want to refer to both variables in your file. Using
the namespace identifier of either john or bill, you can attach a prefix to x to indicate which x you are referring to.
We sometimes say that john refers to one namespace, while bill refers to another distinct namespace. You can attach
a namespace identifier to any user-defined variable, constant, procedure or function. You can do it to solve a conflict, or
simply to make things clearer. A namespace identifier has local scope. It is known only within the file that declares it,
i.e. the file that contains the include statement. Different files might define different namespace identifiers to refer to the
same included file.
There is a special, reserved namespace, eu for referring to built-in Euphoria routines. This can be useful when a built-in
routine has been overridden:
1 procedure puts ( integer fn , object text )
2 eu : puts ( fn , " Overloaded puts says : " & text )
3 end procedure
4
Files can also declare a default namespace to be used with the file. When a file with a default namespace is included, if
the include statement did not specify a namespace, then the default namespace will be automatically declared in that file.
If the include statement declares a namespace for the newly included file, then the specified namespace will be available
instead of the default. No two files can use the same namespace identifier. If two files with the same default namespaces
are included, at least one will be required to have a different namespace to be specified.
To declare a default namespace in a file, the first token (whitespace and comments are ignored) should be namespace
followed by the desired name:
60
CHAPTER 15. DECLARATIONS 15.3. SCOPE
A namespace that is declared as part of an include statement is local to the file where the include statement is.
A default namespace declared in a file is considered a public symbol in that file. Namespaces and other symbols (e.g.,
variables, functions, procedures and types) can have the same name without conflict. A namespace declared through an
include statement will mask a default namespace declared in another file, just like a normal local variable will mask a
public variable in another file. In this case, rather than using the default namespace, declare a new namespace through
the include statement.
Note that declaring a namespace, either through the include statement or as a default namespace does not require
that every symbol reference must be qualified with that namespace. The namespace simply allows the user to deconflict
symbols in different files with the same name, or to allow the programmer to be explicit about where symbols are coming
from for the purposes of clarity, or to avoid possible future conflicts.
A qualified reference does not absolutely restrict the reference to symbols that actually reside within the specified file.
It can also apply to symbols included by that file. This is especially useful for multi-file libraries. Programmers can use a
single namespace for the library, even though some of the visible symbols in that library are not declared in the main file:
1 -- lib . e
2 namespace lib
3
9 -- sublib . e
10 public procedure sub ()
11 ...
12
13 -- app . ex
14 include lib . e
15
16 lib : main ()
17 lib : sub ()
5 -- app2 . ex
6 include lib . e
7 lib : main ()
8 lib : sub () -- error . sub () is visible in lib2 . e but not in app2 . ex
61
CHAPTER 15. DECLARATIONS 15.3. SCOPE
Public symbols can only be seen by the file that explicitly includes the file where those public symbols are declared.
For example,
-- Parent file : foo . e --
include bar . e
showit () -- execute a public routine in bar . e
If however, a file wants a third file to also see the symbols that it can, it needs to do a public include.
For example,
1 -- Parent file : foo . e --
2 public include bar . e
3 showit () -- execute a public routine in bar . e
4
The public include facility is designed to make having a library composed of multiple files easy for an application
to use. It allows the main library file to expose symbols in files that it includes as if the application had actually included
them. That way, symbols meant for the end user can be declared in files other than the main file, and the library can still
be organized however the author prefers without affecting the end user.
Another example
Given that we have two files LIBA.e and LIBB.e ...
1 -- LIBA . e --
2 public constant
3 foo1 = 1 ,
4 foo2 = 2
5
and
-- LIBB . e --
-- I want to pass on just the constants not
-- the functions from LIBA . e .
public include LIBA . e
62
CHAPTER 15. DECLARATIONS 15.3. SCOPE
The export scope modifier is used to limit the extent that symbols can be accessed. It works just like public except
that export symbols are only ever passed up one level only. In other words, if a file wants to use an export symbol, that
file must include it explicitly.
In this example above, code in LIBB.e can see both the public and export symbols declared in LIBA.e (foo1, foo2
foobarr1 and foobarr2) because it explicitly includes LIBA.e. And by using the public prefix on the include of
LIBA.e, it also allows any file that includes LIBB.e to the public symbols from LIBA.e but they will not see any export
symbols declared in LIBA.e.
In short, a public include is used expose public symbols that are included, up one level but not any export
symbols that were include.
So, if a name is used at a block level, Euphoria will first check for its declaration in the same block, and if not found
will check the enclosing blocks until it reaches the routine level, in which case it checks the routine (including parameter
names), and then check the file that the block is declared in and finally check the global/public/export symbols.
By the way, Euphoria will not allow a name to be declared if it is already declared in the same scope, or enclosing
block or enclosing routine. Thus the following examples are illegal...
integer a
if x then
integer a -- redefinition not allowed .
end if
1 if x then
2 integer a
3 if y then
4 integer a -- redefinition not allowed .
5 end if
6 end if
63
CHAPTER 15. DECLARATIONS 15.3. SCOPE
5 end procedure
6 ? a
In this situation, the second declaration of a is said to shadow the first one. The output from this example will be ...
2
1
Symbols all declared in the same file (be they in blocks, routines or at the file level) are easy to check by Euphoria
for scope clashes. However, a problem can arise when symbol names declared as global/public/export in different files
are placed in the same scope during include processing. As it is quite possible for these files to come from independent
developers that are not aware of each others symbol names, the potential for name clashes is high. A name clash is just
when the same name is declared in the same scope but in different files. Euphoria cannot generally decide which name
you were referring to when this happens, so it needs you help to resolve it. This is where the namespace concept is used.
A namespace is just a name that you assign to an include file so that your code can exactly specify where an identifier
that your code is using actually comes from. Using a namespace with an identifier, for example:
include somefile . e as my_lib
include another . e
my_lib : foo ()
enables Euphoria to resolve the identifier (foo) as explicitly coming from the file associated with the namespace
my lib. This means that if foo was also declared as global/public/export in another.e then that foo would be ignored
and the foo in somefile.e would be used instead. Without that namespace, Euphoria would have complained (Errors
resolving the following references:)
If you need to use both foo symbols you can still do that by using two different namespaces. For example:
include somefile . e as my_lib
include another . e as her_ns
my_lib : foo () -- Calls the one in somefile . e
her_ns : foo () -- Calls the one in another . e
Note that there is a reserved namespace name that is always in use. The special namespace eu is used to let Euphoria
know that you are accessing a built-in symbol rather than one of the same name declared in someones file.
For example...
include somefile . e as my_lib
result = my_lib : find ( something ) -- Calls the find in somefile . e
xy = eu : find (X , Y ) -- Calls Euphoria s built - in find
The controlling variable used in a for statement is special. It is automatically declared at the beginning of the loop
block, and its scope ends at the end of the for-loop. If the loop is inside a function or procedure, the loop variable cannot
have the same name as any other variable declared in the routine or enclosing block. When the loop is at the top level,
outside of any routine, the loop variable cannot have the same name as any other file-scoped variable. You can use the
same name in many different for-loops as long as the loops are not nested. You do not declare loop variables as you
would other variables because they are automatically declared as atoms. The range of values specified in the for statement
defines the legal values of the loop variable.
Variables declared inside other types of blocks, such as a loop, while, if or switch statement use the same scoping
rules as a for-loop index.
64
CHAPTER 15. DECLARATIONS 15.3. SCOPE
A warning will be issued when you do this, because it can be very confusing, and would probably break code, for the
new routine to change the behavior of the former routine. Code that was calling the former routine expects no difference
in service, so there should not be any.
If an identifier is declared global, public or export, but not override, and there is a built-in of the same name, Euphoria
will not assume an override, and will choose the built-in. A warning will be generated whenever this happens.
65
Chapter 16
Assignment statement
An assignment statement assigns the value of an expression to a simple variable, or to a subscript or slice of a variable.
e.g.
x = a + b
y[i] = y[i] + 1
y [ i .. j ] = {1 , 2 , 3}
The previous value of the variable, or element(s) of the subscripted or sliced variable are discarded. For example,
suppose x was a 1000-element sequence that we had initialized with:
object x
This is perfectly legal since x is declared as an object. The previous value of x, namely the 1000-element sequence,
would simply disappear. Actually, the space consumed by the 1000-element sequence will be automatically recycled due
to Euphorias dynamic storage allocation.
Note that the equals symbol = is used for both assignment and for equality testing. There is never any confusion
because an assignment in Euphoria is a statement only, it cant be used as an expression (as in C).
Instead of saying:
galaxy [ q_row ][ q_col ][ q_size ] = galaxy [ q_row ][ q_col ][ q_size ] * 10
66
CHAPTER 16. ASSIGNMENT STATEMENT 16.1. ASSIGNMENT WITH OPERATOR
When the left-hand-side contains multiple subscripts/slices, the op= form will usually execute faster than the longer
form. When you get used to it, you may find the op= form to be slightly more readable than the long form, since you
dont have to visually compare the left-hand-side against the copy of itself on the right side.
You cannot use assignment with operators while declaring a variable, because that variable is not initialized when you
perform the assignment.
67
Chapter 17
Branching Statements
17.1 if statement
An if statement tests a condition to see whether it is true or false, and then depending on the result of that test, executes
the appropriate set of statements.
The syntax of if is
1 IFSTMT ==: IFTEST [ ELSIF ...] [ ELSE ] ENDIF
2 IFTEST ==: if ATOMEXPR [ LABEL ] then [ STMTBLOCK ]
3 ELSIF ==: elsif ATOMEXPR then [ STMTBLOCK ]
4 ELSE ==: else [ STMTBLOCK ]
5 ENDIF ==: end if
Description of syntax
An if statement consists of the keyword if, followed by an expression that evaluates to an atom, optionally followed
by a label clause, followed by the keyword then. Next is a set of zero or more statements. This is followed by zero
or more elsif clauses. Next is an optional else clause and finally there is the keyword end followed by the keyword
if.
An elsif clause consists of the key word elsif, followed by an expression that evaluates to an atom, followed by the
keyword then. Next is a set of zero or more statements.
An else clause consists of the keyword else followed by a set of zero or more statements.
In Euphoria, false is represented by an atom whose value is zero and true is represented by an atom that has any
non-zero value.
When an expression being tested is true, Euphoria executes the statements immediately following the then keyword
after the expression, up to the corresponding elsif or else, whichever comes next, then skips down to the
corresponding end if.
When an expression is false, Euphoria skips over any statements until it comes to the next corresponding elsif or
else, whichever comes next. If this is an elsif then its expression is tested otherwise any statements following the
else are executed.
For example:
1 if a < b then
2 x = 1
3 end if
4
68
CHAPTER 17. BRANCHING STATEMENTS 17.2. SWITCH STATEMENT
12 if char = a then
13 x = 1
14 elsif char = b or char = B then
15 x = 2
16 elsif char = c then
17 x = 3
18 else
19 x = -1
20 end if
Notice that elsif is a contraction of else if, but its cleaner because it does not require an end if to go with it.
There is just one end if for the entire if statement, even when there are many elsif clauses contained in it.
The if and elsif expressions are tested using short circuit evaluation.
An if statement can have a label clause just before the first then keyword. See the section on Header Labels. Note
that an elsif clause can not have a label.
13 [ case else ]
14 [ code block ]
15 [[ break [ label ]]
16 end switch
69
CHAPTER 17. BRANCHING STATEMENTS 17.2. SWITCH STATEMENT
10 end if
11 if not breaking and equal ( temp , val3 ) then
12 [ code block 3]
13 [ breaking = true ]
14 end if
15 ...
16 if not breaking then
17 [ code block 4]
18 [ breaking = true ]
19 end if
The <val> in a case must be either an atom, literal string, constant or enum. Multiple values for a single case can
be specified by separating the values by commas. By default, control flows to the end of the switch block when the next
case is encountered. The default behavior can be modified in two ways. The default for a particular switch block can
be changed so that control passes to the next executable statement whenever a new case is encountered by using with
fallthru in the switch statement:
1 switch x with fallthru do
2 case 1 then
3 ? 1
4 case 2 then
5 ? 2
6 break
7 case else
8 ? 0
9 end switch
Note that when with fallthru is used, the break statement can be used to jump out of the switch block. The
behavior of individual cases can be changed by using the fallthru statement:
1 switch x do
2 case 1 then
3 ? 1
4 fallthru
5 case 2 then
6 ? 2
7 case else
8 ? 0
9 end switch
Note that the break statement before case else was omitted, because the equivalent action is taken automatically
by default.
1 switch length ( x ) do
2 case 1 then
3 -- do something
4 fallthru
5 case 2 then
6 -- do something extra
7 case 3 then
8 -- do something usual
9
10 case else
11 -- do something else
12 end switch
The label "name" is optional and if used it gives a name to the switch block. This name can be used in nested
switch break statements to break out of an enclosing switch rather than just the owning switch.
Example:
70
CHAPTER 17. BRANCHING STATEMENTS 17.3. IFDEF STATEMENT
6 case 4 , 2 , 7 then
7 FuncB ()
8 switch alt label " LBLb " do
9 case " X " then
10 FuncC ()
11 break " LBLa "
12
16 case else
17 FuncE ()
18 end switch
19 FuncF ()
20
21 case 3 then
22 FuncG ()
23 break
24
25 case else
26 FuncH ()
27 end switch
28 FuncM ()
Of course, the elsifdef and elsedef clauses are optional, just like elsif and else are option in an if statement.
The major differences between and if and ifdef statement are that ifdef is executed at parse time not runtime,
and ifdef can only test for the existence of a defined word whereas if can test any boolean expression.
Note that since the ifdef statement executes at parse time, run-time values cannot be checked, only words defined
by the -D command line switch, or by the with define directive, or one of the special predefined words.
The purpose of ifdef is to allow you to change the way your program operates in a very efficient manner. Rather
than testing for a specific condition repeatedly during the running of a program, ifdef tests for it once during parsing
and then generates the precise IL code to handle the condition.
For example, assume you have some debugging code in your application that displays information to the screen.
Normally you would not want to see this display so you set a condition so it only displays during a debug session. The
71
CHAPTER 17. BRANCHING STATEMENTS 17.3. IFDEF STATEMENT
first example below shows how would could do this just using the if statement, and the second example shows the same
thing but using the idef statement.
-- Example 1. --
if find ( " - DEBUG " , command_line ()) then
writefln ( " Debug x =[] , y =[] " , {x , y })
end if
-- Example 1. --
ifdef DEBUG then
writefln ( " Debug x =[] , y =[] " , {x , y })
end ifdef
As you can see, they are almost identical. However, in the first example, everytime the program gets to this point in
the code, it tests the command line for the -DEBUG switch before deciding to display the information or not. But in the
second example, the existence of DEBUG is tested once at parse time, and if it exists then, Euphoria generates the IL code
to do the display. Thus when the program is running then everytime it gets to this point in the code, it does not check
that DEBUG exists, instead it already knows it does so it just does the display. If however, DEBUG did not exist at parse
time, then the IL code for the display would simply be omitted, meaning that during the running of the program, when it
gets to this point in the code, it does not recheck for DEBUG, instead it already knows it doesnt exist and the IL code
to do the display also doesnt exist so nothing is displayed. This can be a much needed performance boost for a program.
Euphoria predefines some words itself:
Euphoria is released with the common version scheme of Major, Minor and Release version identifiers in the form of
major.minor.release. When 4.0.5 is released, EU4 0 5 will be defined and EU4 0 will still be defined, but EU4 0 4 will no
longer be defined. When 4.1 is released, EU4 0 will no longer be defined, but EU4 1 will be defined. Finally, when 5.0 is
released, EU4 will no longer be defined, but EU5 will be defined.
GUI - Platform is Windows and is being executed with the GUI version of the interpreter (euiw.exe)
72
CHAPTER 17. BRANCHING STATEMENTS 17.3. IFDEF STATEMENT
More examples
1 -- file : myproj . ex
2 puts (1 , " Hello , I am " )
3 ifdef EUC then
4 puts (1 , " a translated " )
5 end ifdef
6 ifdef EUI then
7 puts (1 , " an interpreted " )
8 end ifdef
9 ifdef EUB then
10 puts (1 , " a bound " )
11 end ifdef
12 ifdef EUB_SHROUD then
13 puts (1 , " , shrouded " )
14 end ifdef
15 puts (1 , " program .\ n " )
73
CHAPTER 17. BRANCHING STATEMENTS 17.3. IFDEF STATEMENT
It is possible for one or more of the above definitions to be true at the same time. For instance, EUC and EUC DLL will
both be true when the source file has been translated to a DLL. If you wish to know if your source file is translated and
not a DLL, then you can
ifdef EUC and not EUC_DLL then
-- translated to an application
end ifdef
or by command line:
eui -D MY_WORD myprog . ex
This can handle many tasks such as change the behavior of your application when running on Linux vs. Windows,
enable or disable debug style code or possibly work differently in demo/shareware applications vs. registered applications.
You should surround code that is not portable with ifdef like:
1 ifdef WINDOWS then
2 -- Windows specific code .
3 elsedef
4 include std / error . e
5 crash ( " This program must be run with the Windows interpreter . " )
6 end ifdef
When writing include files that you cannot run on some platform, issue a crash call in the include file. Yet make
sure that public constants and procedures are defined for the unsupported platform as well.
1 ifdef UNIX then
2 include std / bash . e
3 end ifdef
4
The reason for doing this is so that the user that includes your include file sees an OS not supported message instead
of an undefined reference message.
Defined words must follow the same character set of an identifier, that is, it must start with either a letter or underscore
and contain any mixture of letters, numbers and underscores. It is common for defined words to be in all upper case,
however, it is not required.
A few examples:
1 for a = 1 to length ( lines ) do
2 ifdef DEBUG then
3 printf (1 , " Line % i is % i characters long \ n " , {a , length ( lines [ a ])})
4 end ifdef
5 end for
6
7 sequence os_name
8 ifdef UNIX then
9 include unix_ftp . e
10 elsifdef WINDOWS then
11 include win32_ftp . e
74
CHAPTER 17. BRANCHING STATEMENTS 17.3. IFDEF STATEMENT
12 elsedef
13 crash ( " Operating system is not supported " )
14 end ifdef
15
The ifdef statement is very efficient in that it makes the decision only once during parse time and only emits the
TRUE portions of code to the resulting interpreter. Thus, in loops that are iterated many times there is zero performance
hit when making the decision. Example:
1 while 1 do
2 ifdef DEBUG then
3 puts (1 , " Hello , I am a debug message \ n " )
4 end ifdef
5 -- more code
6 end while
If DEBUG is defined, then the interpreter/translator actually sees the code as being:
while 1 do
puts (1 , " Hello , I am a debug message \ n " )
-- more code
end while
Now, if DEBUG is not defined, then the code the interpreter/translator sees is:
while 1 do
-- more code
end while
Do be careful to put the numbers after the platform names for Windows:
1 -- This puts () routine will never be called
2 -- even when run by the Windows interpreter !
3 ifdef WINDOWS then
4 puts (1 , " I am on Windows \ n " )
5 end ifdef
75
Chapter 18
Loop statements
An iterative code block repeats its own execution zero, one or more times. There are several ways to specify for how long
the process should go on, and how to stop or otherwise alter it. An iterative block may be informally called a loop, and
each execution of code in a loop is called an iteration of the loop.
Euphoria has three flavors of loops. They all may harbor a Header Labels, in order to make exiting or resuming them
more flexible.
Example 2
1 while sequence ( Line ) with entry do
2 proc ( Line )
3 entry
4 Line = gets ( handle )
5 end while
Example 3
1 while true label " main " do
2 res = funcA ()
3 if res > 5 then
4 if funcB () > some_value then
5 continue " main " -- go to start of loop
6 end if
7 procC ()
8 end if
9 procD ( res )
10 for i = 1 to res do
11 if i > some_value then
12 exit " main " -- exit the " main " loop , not just this for loop .
76
CHAPTER 18. LOOP STATEMENTS 18.2. LOOP UNTIL STATEMENT
13 end if
14 procF (i , res )
15 end if
16
A while statement differs from a loop statement because the body of a loop is executed at least once, since testing
takes place after the body completes. However in a while statement, the test is taken before the body is executed.
This block of code simply starts at the first line and runs each in turn. But it could be written more simply and flexibly
by using a for statement.
77
CHAPTER 18. LOOP STATEMENTS 18.3. FOR STATEMENT
for i = 1 to 6 do
printf (1 , " % d \ n " , i )
end for
Now its just three lines of code rather than six. More importantly, if we needed to change the program to print the
numbers from 1 to 100, we only have to change one line rather than add 94 new lines.
for i = 1 to 100 do -- One line change .
printf (1 , " % d \ n " , i )
end for
However, adding together floating point numbers that are not the ratio of an integer by a power of 2 -- 0.3 is not
such a ratio--leads to some fuzz in the value of the index. In some cases, you might get unexpected results because
of this fuzz, which arises from a common hardware limitation. For instance, floor(10*0.1) is 1 as expected, but
floor(0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1) is 0.
The loop variable is declared automatically and exists until the end of the loop. Outside of the loop the variable has
no value and is not even declared. If you need its final value, copy it into another variable before leaving the loop. The
compiler will not allow any assignments to a loop variable. The initial value, loop limit and increment must all be atoms.
If no increment is specified then +1 is assumed. The limit and increment values are established only on entering the loop,
and are not affected by anything that happens during the execution of the loop.
78
Chapter 19
Flow control statements
Program execution flow refers to the order in which program statements are run in. By default, the next statement to run
after the current one is the next statement physically located after the current one.
Example:
a = b + c
printf (1 , " The result of adding % d and % d is % d " , {b ,c , a })
In that example, b is added to c, assigning the result to a, and then the information is displayed on the screen using
the printf statement.
However, there are many times in which the order of execution needs to be different from the default order, to get the
job done. Euphoria has a number of flow control statements that you can use to arrange the execution order of statements.
A set of statements that are run in their order of appearance is called a block. Blocks are good ways to organize code
in easily identifiable chunks. However it can be desirable to leave a block before reaching the end, or slightly alter the
default course of execution.
But sometimes you need to leave a block that encloses the current one. Euphoria has two methods available for you
to do this. The safest method, in terms of future maintenance, is to name the block you want to exit from and use that
name on the exit statement. The other method is to use a number on the exit statement that refers to the depth that
you want to exit from.
79
CHAPTER 19. FLOW CONTROL STATEMENTS 19.1. EXIT STATEMENT
A blocks name is always a string literal and only a string literal. You cannot use a variable that contains the blocks
name on an exit statement. The name comes after the label keyword, just before the do keyword.
Example:
1 integer b
2 b = 0
3 for i = 1 to 20 label " main " do
4 for j = 1 to 20 do
5 b += i + j
6 ? {i , j , b }
7 if b > 50 then
8 b = 0
9 exit " main "
10 end if
11 end for
12 end for
13 ? b
The exit main causes execution flow to leave the for block named main.
The same thing could be achieved using the exit N format...
1 integer b
2 b = 0
3 for i = 1 to 20 do
4 for j = 1 to 20 do
5 b += i + j
6 ? {i , j , b }
7 if b > 50 then
8 b = 0
9 exit 2 -- exit 2 levels of depth
10 end if
11 end for
12 end for
13
14 ? b
But using this method means you have to take more care when changing the program so that if you change the depth,
you also need to change the exit statement.
Note:
A special form of exit N is exit 0. This leaves all levels of loop, regardless of the depth. Control continues after
the outermost loop block. Likewise, exit -1 exits the second outermost loop, and so on.
For easier and safer program maintenance, the explicit label form is to be preferred. Other forms are variously sensitive
to changes in the program organization. Yet, they may prove more convenient in short, short lived programs, and are
provided mostly for this purpose.
For information on how to associate a string to a block of code, see the section Header Labels.
80
CHAPTER 19. FLOW CONTROL STATEMENTS 19.2. BREAK STATEMENT
An exit without any label or number in a while statement or a for statement causes immediate termination of that
loop, with control passing to the first statement after the loop.
Example:
1 for i = 1 to 100 do
2 if a [ i ] = x then
3 location = i
4 exit
5 end if
6 end for
3 while TRUE do
4 ...
5 if some_condition then
6 exit
7 end if
8 ...
9 end while
i.e. an infinite while-loop that actually terminates via an exit statement at some arbitrary point in the body of the
loop.
Performance Note:
Euphoria optimizes this type of loop. At run-time, no test is performed at the top of the loop. Theres just a simple
unconditional jump from end while back to the first statement inside the loop.
81
CHAPTER 19. FLOW CONTROL STATEMENTS 19.3. CONTINUE STATEMENT
14 ? b
The same optional parameters that can be used in an exit statement can apply to a continue statement.
82
CHAPTER 19. FLOW CONTROL STATEMENTS 19.5. WITH ENTRY STATEMENT
12 file_handles [ i ] = fh
13 end for
Since retry does not change the value of i and tries again opening the same file, there has to be a way to break from
the loop, which the exit statement provides.
The same optional parameters that can be used in an exit statement can apply to a retry statement.
11 return ret
12 end function
Instead of performing an initial test, which may crash because from has not been assigned a value yet, the first iteration
jumps at the point where from is being computed. The following iterations are normal. To emphasize the fact that the
first iteration is not normal, the entry clause must be added to the loop header, after the condition.
The entry statement is not supported for for loops, because they have a more rigid nature structure than while or
loop constructs.
Label names must be double quoted constant strings. Characters that would be illegal in an Euphoria identifier may
appear in a label name, since it is a regular string.
Header Labels do not count as possible goto targets.
Use goto in production code when all the following applies:
you want to proceed with a statement which is not the following one;
83
CHAPTER 19. FLOW CONTROL STATEMENTS 19.7. HEADER LABELS
Note: If a flow control statement has both an entry clause and a label clause, the entry clause must come before
the label clause:
while 1 label " top " with entry do -- WRONG
84
Chapter 20
Short-Circuit Evaluation
When the condition tested by if, elsif, until, or while contains and or or operators, short circuit evaluation will be used.
For example,
if a < 0 and b > 0 then ...
If a < 0 is false, then Euphoria will not bother to test if b is greater than 0. It will know that the overall result is false
regardless. Similarly,
if a < 0 or b > 0 then ...
if a < 0 is true, then Euphoria will immediately decide that the result is true, without testing the value of b, since the
result of this test would be irrelevant.
In general, whenever we have a condition of the form:
A and B
where A and B can be any two expressions, Euphoria will take a short-cut when A is false and immediately make the
overall result false, without even looking at expression B.
Similarly, with:
A or B
when A is true, Euphoria will skip the evaluation of expression B, and declare the result to be true.
If the expression B contains a call to a function, and that function has possible side-effects, i.e. it might do more
than just return a value, you will get a compile-time warning. Older versions (pre-2.1) of Euphoria did not use short circuit
evaluation, and its possible that some old code will no longer work correctly, although a search of the Euphoria archives
did not turn up any programs that depend on side-effects in this way, but other Euphoria code might do so.
The expression, B, could contain something that would normally cause a run-time error. If Euphoria skips the evaluation
of B, the error will not be discovered. For instance:
if x != 0 and 1/ x > 10 then -- divide by zero error avoided
Without short-circuiting, you would have a problem when x contains less than 2 items. With short-circuiting, the
assignment to x[2] will only be done when x has at least 2 items. Similarly:
85
CHAPTER 20. SHORT-CIRCUIT EVALUATION
1 -- find a or A in s
2 i = 1
3 while i <= length ( s ) and s [ i ] != a and s [ i ] != A do
4 i += 1
5 end while
In this loop the variable i might eventually become greater than length(s). Without short-circuit evaluation, a subscript
out-of-bounds error will occur when s[i] is evaluated on the final iteration. With short-circuiting, the loop will terminate
immediately when i <= length(s) becomes false. Euphoria will not evaluate s[i] != a and will not evaluate s[i] != A.
No subscript error will occur.
Short-circuit evaluation of and and or takes place inside decision making expressions. These are found in the if
statement, while statement and the loop until statement. It is not used in other contexts. For example, the assignment
statement:
x = 1 or {1 ,2 ,3 ,4 ,5} -- x should be set to {1 ,1 ,1 ,1 ,1}
If short-circuiting were used here, we would set x to 1, and not even look at 1,2,3,4,5. This would be wrong. Short-
circuiting can be used in if/elsif/until/while conditions because we only care if the result is true or false, and conditions
are required to produce an atom as a result.
86
Chapter 21
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). Its 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
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. Heres
an example...
We have two files, a.e and b.e ...
87
CHAPTER 21. SPECIAL TOP-LEVEL STATEMENTS 21.1. INCLUDE STATEMENT
-- 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
dannys 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 cathys 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.
1 -- - mainprog . ex ---
2 include anne . e as anne
3 include bob . e as bob
4
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 youve 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
88
CHAPTER 21. SPECIAL TOP-LEVEL STATEMENTS 21.2. WITH / WITHOUT
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 hasnt 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 dont 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:
89
CHAPTER 21. SPECIAL TOP-LEVEL STATEMENTS 21.2. WITH / WITHOUT
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.
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.
90
CHAPTER 21. SPECIAL TOP-LEVEL STATEMENTS 21.2. WITH / WITHOUT
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 warn-
ings. 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 doesnt (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. Eu-
phoria 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() proce-
dure.
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. Other-
wise, 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
91
CHAPTER 21. SPECIAL TOP-LEVEL STATEMENTS 21.2. WITH / WITHOUT
translator
cmdline
mixed profile
not reached
custom
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
92
Part V
Formal Syntax
93
Chapter 22
Formal Syntax
22.1 Basics
The syntax of Euphoria is described using a form of BNF notation.
ALPHA ==: ( a - z ) | ( A - Z )
DIGIT ==: ( 0 - 9 )
USCORE ==: _
EOL ==: new line character
STATEMENT ==:
LISTDELIM ==: ,
94
CHAPTER 22. FORMAL SYNTAX 22.2. STATEMENTS
22.2 Statements
22.2.1 Directives
INCLUDESTMT
WITHSTMT
NAMESPACE
22.2.4 Routines
PROCDECLARE
FUNCDECLARE
TYPEDECLARE
95
CHAPTER 22. FORMAL SYNTAX 22.3. SEQUENCE SLICE
RETURN
22.2.5 include
INCLUDESTMT
NOTE that after the file reference, the only text allowed is the keyword as or the start of a comment. Nothing else is
permitted on the same text line.
See Also: include statement
22.4 if
IFSTMT
22.5 ifdef
IFDEFSTMT
96
CHAPTER 22. FORMAL SYNTAX 22.6. BREAK
22.5.1 switch
SWITCHSTMT
SWITCHSTMT ==: SWITCHTEST CASE [ CASE ...] [ CASEELSE ] [ ENDSWITCH ]
SWITCHTEST ==: switch EXPRESSION [ WITHFALL ] [ LABEL ] do
WITHFALL ==: ( with | without ) fallthru
CASE ==: case CASELIST then [ STMTBLOCK ]
CASELIST ==: EXPRESSION [( LISTDELIM EXPRESSION ) ...]
CASEELSE ==: case else
ENDSWITCH ==: end switch
22.6 break
BREAKSTMT
BREAKSTMT ==: break [ STRINGLIT ]
22.7 continue
CONTINUESTMT
CONTINUESTMT ==: continue [ STRINGLIT ]
22.8 retry
RETRYSTMT
RETRYSTMT ==: retry [ STRINGLIT ]
22.9 exit
EXITSTMT
EXITSTMT ==: exit [ STRINGLIT ]
22.10 fallthru
FALLTHRUSTMT
FALLTHRUSTMT ==: fallthru
97
CHAPTER 22. FORMAL SYNTAX 22.11. FOR
22.11 for
FORSTMT
FORSTMT ==: for FORIDX [ LABEL ] do [ STMTBLK ] end for
FORIDX ==: IDENTIFIER = NUMEXPR to NUMEXPR [ by NUMEXPR ]
22.12 while
WHILESTMT
WHILESTMT ==:
while BOOLEXPR [ WITHENTRY ] [ LABEL ] do STMTBLK [ ENTRY ] end while
WITHENTRY ==: with entry
ENTRY ==: entry [ STMTBLK ]
22.13 loop
LOOPSTMT
LOOPSTMT ==:
loop [ WITHENTRY ] [ LABEL ] do STMTBLK [ ENTRY ] until BOOLEXPR end loop
22.14 goto
GOTOSTMT
GOTOSMT ==: goto LABEL
Notes:
98
CHAPTER 22. FORMAL SYNTAX 22.17. DECLARE AN ENUMERATED VALUE
Notes:
The procedure statement block must not contain a return statememt.
See Also: procedures
Notes:
The function statement block must contain a return statememt.
See Also: functions
Notes:
The type statement block must contain a return statememt.
It must return an integer; 0 means that the supplied argument is not of the correct type.
See Also: types
99
CHAPTER 22. FORMAL SYNTAX 22.22. RETURN THE RESULT OF A FUNCTION
100
Chapter 23
Euphoria Internals
Interpreter
Translator
Backend
Library
The Euphoria interpreter has two parts: the frontend and the backend. The frontend is a parser that converts source-
code into a set of Intermediate Language (IL) instructions. The backend then takes the IL instructions and executes
the program.
When the interpreter executes source-code, the frontend parses and prepares the code, and then the backend executes
the code.
When the shrouder executes source-code, only the frontend is run producing an .il file. This .il file may be run by
the backend as an independent step to execute the program.
When the binder executes source-code, the .il instructions produced by the frontend are combined with the backend
to produce a stand-alone executable program. The executable program may then be run independetly at any time.
When the translator executes source-code, the .il instructions are translated into C-code. This C-code is compiled
with an installed C compiler producing an executable program.
The library is called by the backend for the many builtins included in Euphoria.
101
CHAPTER 23. EUPHORIA
23.2. INTERNALS
THE C REPRESENTATIONS OF A EUPHORIA SEQUENCE AND A EUPHORIA ATOM
* - - - - - - - -* - - - - - - - -* - - - - - - - -* - - - - - - - -* - - - - - - - -* - - - - - - - -* - - - - - - - -* - - - - - - - - o
o NOVALUE = -2*2^29 -1
o < - - - - - - - - - - - ATOM_INT - - - - - - - - -[ -2*2^29..4*2^29) - - - - - - > o
| < - - - - - - - - - - - - - - - - ATOM_DBL - - - - - - -[ -3*2^29..4*2^29) - - - - - - - - - - - - > o
- - >| | < - - IS_SEQUENCE [ -4*2^29.. -3*2^29)
- - >| o < - - - IS_DBL_OR_SEQUENCE [ -4*2^29.. -2*2^29 -1)
- - >| sequence | < - - - - - - -
| < - - - - - - - - - - - - - - - - - - atom - - - - - - - - - - - - - - - >|
- - - - - - - >| double | < - - - - - - - -
|<-------- integer - - - - - - - - - >|
| < - - - - - - - - - - - - - - - - - - - - - object - - - - - - - - - - - - - - - - - - - - - - >|
Euphoria integers are stored in object variables as-is. An object variable is a four byte signed integer. Legal integer
values for Euphoria integers are between -1,073,741,824 ( -230 ) and +1,073,741,823 ( 230 -1 ). Unsigned hexadecimal
numbers from C000 0000 to FFFF FFFF are the negative integers and numbers from 0000 0000 to 3FFF FFFF are the
positive integers. The hexadecimal values not used as integers are thus 4000 0000 to BFFF FFFF. Other values are for
encoded pointers. Pointers are always 8 byte aligned. So a pointer is stored in 29-bits instead of 32 and can fit in a
hexadecimal range 0x2000 0000 long. The pointers are encoded in such a way that their encoded values will never be
in the range of the integers. Pointers to sequence structures (struct s1) are encoded into a range between 8000 0000 to
9FFF FFFF. Pointers to structures for doubles (struct d) are encoded into a range between A000 0000 to BFFF FFFF. A
special value NOVALUE is at the end of the range of encoded pointers is BFFF FFFF and it signifies that there is no value
yet assigned to a variable and it also signifies the end of a sequence. In C, values of this type are stored in the object
type. The range 4000 0000 to 7FFF FFFF is unused.
A double structure struct d could indeed contain a value that is legally in the range of a Euphoria integer. So the
encoded pointer to this structure is recognized by the interpreter as an integer but in this internals document when we
say Euphoria integer we mean it actually is a C integer in the legal Euphoria integer range.
// Sequence Header
struct s1
{
object_ptr base ; // base is such that base [1] is the first element
long length ; // this is the sequence length
long ref ; // ref is the number of as virtual copies of this sequence
long postfill ; // is how many extra objects could fit at the end of base
cleanup_ptr cleanup ; // this is a pointer to a Euphoria routine that is run
// just before the sequence is freed .
}
However, we allocate more than this structure. Inside the allocated data but past the structure, there also is an area
of pre free space; sequence data pointed to by base[1] to base[$], $ being the length; a NOVALUE terminator for the
sequence, and an area of post fill space. In memory, immediately following the structure there is the following data stored:
object pre_fill_space []; // could have 0 ( not exist ) or more elements before used data
object base [1.. $ ]; // sequence members pointed to by base
object base [ $ +1]; // a magic number terminating the sequence members ( NOVALUE )
object post_fill_space [];// could have 0 ( not exist ) or more elements after used data
102
CHAPTER 23. EUPHORIA
23.2. INTERNALS
THE C REPRESENTATIONS OF A EUPHORIA SEQUENCE AND A EUPHORIA ATOM
Field Description
base This contains the address of the first element less the
length of one element. Thus base[1] points to the first
element and base[0] points to a fictitious element just
before the first one, which is never used.
Initially, base contains the address of the last member of
the sequence header but as the sequence is resized, it can
point to the last member or anywhere after.
length Contains the current number of elements in the sequence.
ref Contains the count of references to this sequence. Only
when this is zero, can the RAM used by the sequence be
returned to the system for reuse.
postfill The size of post fill space in element spaces. Rather than
using bytes, postfill is measured in objects which are each
address wide elements. If this is non-zero, we can append
to the sequence with at most postfill new elements
before needing to reallocate RAM.
pre fill space There are 0 or more spaces before base[1]. We can calcu-
late the free space in *objects* at the front of a sequence,
s1, in C by
(&s1.base[1] - (object ptr)(1+&s1)).
In EUPHORIA, you will have to divide by the size of a
C POINTER on the difference. When elements are re-
moved from the front of a sequence, we simply adjust the
address in base to point to the new first element and re-
duce the length count. If we want to prepend and this
pre fill space has some positive size, then we make room
by decrementing base and increment the length. The
new data is then assigned to base[1].
base[1]..base[length] sequence data This is actual data.
base[$+1] This is always set to NOVALUE.
post fill space There are 0 or more spaces after base[length+1]. The
number of spaces is stored in postfill. If postfill
is non-zero we can append by incrementing the length,
decrementing postfill and assigning the new data to
base[$]. When we remove from the end of the sequence,
we increment postfill and decrement the length.
// Atom Header
struct d
{
double dbl ; // the actual value of a double number .
long ref ; // ref is the number of virtual copies of this double
cleanup_ptr cleanup ; // this is a pointer to a Euphoria routine that is run
// just before the sequence is freed .
}
Now offset of the ref in struct d must be the same as the offset of the ref in struct s1. To this end, the 64bit
implementation of 4.1 has these members in a different order.
103
CHAPTER 23. EUPHORIA INTERNALS 23.3. THE EUPHORIA OBJECT MACROS AND FUNCTIONS
Returns
true if object is a Euphoria integer and not an encoded pointer.
Note
IS ATOM INT() will return true even though the argument is out of the Euphoria integer range when the argument is
positive. These values are not possible encoded pointers.
Returns
true if the object is an encoded pointer to a double struct.
Assumption
o must not be a Euphoria integer.
23.4.3 IS ATOM
104
CHAPTER 23. EUPHORIA INTERNALS 23.5. TYPE CONVERSION FUNCTIONS AND MACROS
Returns
true if the object is a Euphoria integer or an encoded pointer to a struct d.
23.4.4 IS SEQUENCE
Returns
true if the object is an encoded pointer to a struct s1.
Assumption
o is not NOVALUE.
Returns
true if the object is an encoded pointer of either kind of structure.
Returns
an object with the same value as x. x must be with in the integer range of a legal Euphoria integer type.
Returns
an object with the same value as x.
Assumption
x must be an unsigned integer with in the integer range of a C unsigned int type.
Example
MAKE UINT(4*1000*1000*1000) will make a Euphoria value of four billion by creating a double.
105
CHAPTER 23. EUPHORIA INTERNALS 23.5. TYPE CONVERSION FUNCTIONS AND MACROS
Returns
an object with an argument of a pointer to a struct s1 The pointer is encoded into a range for sequences and returned.
23.5.4 NewString
Returns
an object representation of a Euphoria byte string s. The returned encoded pointer is a sequence with all of the bytes
from s copied over.
Returns
an object with an argument of a pointer to a struct d The pointer is encoded into a range for doubles and returned.
23.5.6 NewDouble
Returns
an object with an argument a double dbl. A struct d is allocated and dbl is assigned to the value part of that structure.
The pointer is encoded into the range for doubles and returned.
Returns
The pointer to a struct d from the object o.
Assumption
IS ATOM INT(o) is FALSE and IS ATOM DBL(o) is TRUE.
106
CHAPTER 23. EUPHORIA INTERNALS 23.6. CREATING OBJECTS
Returns
The pointer to a struct s1 from the object o.
Assumption
IS SEQUENCE(o) is TRUE and o is not NOVALUE.
Returns
a unsigned long value by truncating what xs value is to an integer
Comment
Any object may be passed. A sequence results in a runtime failure. There may be a cast of a double to a smaller ranged
long type.
Returns
A sequence object with size members which are not yet set to a value.
23.7.1 NOVALUE
Indicates that a variable has not been assigned and also terminates a sequence.
23.7.2 MININT
107
CHAPTER 23. EUPHORIA INTERNALS 23.7. OBJECT CONSTANTS
23.7.3 MAXINT
HIGH BITS is an integer value such that if another integer value c lies outside of the range between MININT and
MAXINT, c+HIGH BITS will be non-negative.
23.7.5 Parser
Inserting tokens into the token buffer is the easiest way to add features to the EUPHORIA parser. The tokens are
two-element sequences one of the class of token and the other the tokens value:
<class>,<value>
Each of the class values are capitalized words for some keyword or VARIABLE. The list of constants is in reswords.e.
Often it is enough to only examin the class. In the case of variables, it is important to know which variable. In this case
the second element, comes into play.
You can use putback() to put tokens into the token buffer. The tokens will be pulled out by the parser in a filo manner,
like a stack.
108
CHAPTER 23. EUPHORIA INTERNALS 23.7. OBJECT CONSTANTS
important to know exactly what these opcodes do and what they are for. In this section we will document what they are
for, and how they manipulate the instruction pointer, and stack.
IF instruction:
The IF instruction is used for making runtime branch statements. The IF instruction takes the top of the stack as
the condition value, if the condition is 0, it passes control to the address stored just below the top of the stack. If the
condition is non-zero and an atom the instruction pointer just past the failure address.
[ IF instruction ] [ test value ] [ failure address ]
INTEGER CHECK instruction:
The INTEGER CHECK is used to ensure that something has a value considered to be integer to the EUPHORIA
language definition. The instruction takes the next argument as a pointer to a value and determines whether this value
is in the legal integer range, regardless of how that number is represented. If not in legal range, then the program ends
execution in a type-check failure error message.
[ INTEGER CHECK instruction ] [ test pointer ]
ATOM CHECK instruction:
The ATOM CHECK is used to determine whether something has a numeric value rather than a sequence. The
instruction takes an argument as a pointer to a value and determines whether the value is an atom. If it is not an atom,
then the program ends execution in a type-check failure error message.
[ ATOM CHECK instruction ] [ test pointer ]
IS AN INTEGER instruction:
The IS AN INTEGER instruction is used to determine whether something has a value considered to be integer to the
EUPHORIA language definition. The instruction takes the argument as a pointer to a value and determines whether this
value is in the legal integer range, regardless of how that number is represented. If it is in the integer range then the
value pointed by the second argument will be 1 otherwise it will be 0.
[ IS AN INTEGER instruction ] [ test pointer ][ return value pointer ]
109
Part VI
Mini-Guides
110
Chapter 24
Debugging and Profiling
24.1 Debugging
Extensive run-time checking provided by the Euphoria interpreter catches many bugs that in other languages might take
hours of your time to track down. When the interpreter catches an error, you will always get a brief report on your screen,
and a detailed report in a file called ex.err. These reports include a full English description of what happened, along
with a call-stack traceback. The file ex.err will also have a dump of all variable values, and optionally a list of the most
recently executed statements. For extremely large sequences, only a partial dump is shown. If the name ex.err is not
convenient, or if a nondefault path is required, you can choose another file name, anywhere on your system, by calling
crash file().
In addition, you are able to create user-defined types that precisely determine the set of legal values for each of your
variables. An error report will occur the moment that one of your variables is assigned an illegal value.
Sometimes a program will misbehave without failing any run-time checks. In any programming language it may be a
good idea to simply study the source code and rethink the algorithm that you have coded. It may also be useful to insert
print statements at strategic locations in order to monitor the internal logic of the program. This approach is particularly
convenient in an interpreted language like Euphoria since you can simply edit the source and rerun the program without
waiting for a re-compile/re-link.
111
CHAPTER 24. DEBUGGING AND PROFILING 24.2. THE TRACE SCREEN
However, you cannot dynamically set or free breakpoints while tracing. You must abort program, edit, change setting,
save and run again.
At the top of your program, so you can start tracing from the beginning of execution. More commonly, you will want
to trigger tracing when a certain routine is entered, or when some condition arises. e.g.
if x < 0 then
trace (1)
end if
You can turn off tracing by executing a trace(0) statement. You can also turn it off interactively by typing q to quit
tracing. Remember that with trace must appear outside of any routine, whereas trace() can appear inside a routine or
outside.
You might want to turn on tracing from within a type. Suppose you run your program and it fails, with the ex.err
file showing that one of your variables has been set to a strange, although not illegal value, and you wonder how it could
have happened. Simply create a type for that variable that executes trace(1) if the value being assigned to the variable
is the strange one that you are interested in. e.g.
When positive int() returns, you will see the exact statement that caused your variable to be set to the strange
value, and you will be able to check the values of other variables. You will also be able to check the output screen to see
what has happened up to this precise moment. If you define positive int() so it returns zero for the strange value (99)
instead of one, you can force a diagnostic dump into ex.err.
Remember that the argument to trace() does not need to be a constant. It only needs to be 0, 1, 2 or 3, but these
values may be the result from any expression passed to trace(). Other values will cause trace() to fail.
When a trace(1) or trace(2) statement is executed by the interpreter, your main output screen is saved and a trace
screen appears. It shows a view of your program with the statement that will be executed next highlighted, and several
statements before and after showing as well. You cannot scroll the window further up or down though. Several lines at
the bottom of the screen are reserved for displaying variable names and values. The top line shows the commands that
you can enter at this point:
112
CHAPTER 24. DEBUGGING AND PROFILING 24.2. THE TRACE SCREEN
Command Action
113
CHAPTER 24. DEBUGGING AND PROFILING 24.3. THE TRACE FILE
and easier.
When a traced program requests keyboard input, the main output screen will appear, to let you type your input as
you normally would. This works fine for a gets() (read one line) input. When a get key() (quickly sample the keyboard)
is called you will be given 8 seconds to type a character, otherwise it is assumed that there is no input for this call to
get key(). This allows you to test the case of input and also the case of no input for get key().
24.4 Profiling
If you specify a with profile or with profile time (Windows only) directive, then a special listing of your program,
called a profile, will be produced by the interpreter when your program finishes execution. This listing is written to the
file ex.pro in the current directory.
There are two types of profiling available: execution-count profiling, and time profiling. You get execution-count
profiling when you specify with profile. You get time profiling when you specify with profile time. You can not mix
the two types of profiling in a single run of your program. You need to make two separate runs.
We ran the sieve8k.ex benchmark program in demo\bench under both types of profiling. The results are in sieve8k.
pro (execution-count profiling) and sieve8k.pro2 (time profiling).
Execution-count profiling shows precisely how many times each statement in your program was executed. If the
statement was never executed the count field will be blank.
Time profiling shows an estimate of the total time spent executing each statement. This estimate is expressed as a
percentage of the time spent profiling your program. If a statement was never sampled, the percentage field will be blank.
If you see 0.00 it means the statement was sampled, but not enough to get a score of 0.01.
Only statements compiled with profile or with profile time are shown in the listing. Normally you will specify
either with profile or with profile time at the top of your main .ex* file, so you can get a complete listing. View
this file with the Euphoria editor to see a color display.
Profiling can help you in many ways:
It lets you see which statements are heavily executed, as a clue to speeding up your program
It lets you verify that your program is actually working the way you intended
It can provide you with statistics about the input data
It lets you see which sections of code were never tested dont let your users be the first!
Sometimes you will want to focus on a particular action performed by your program. For example, in the Language
War game, we found that the game in general was fast enough, but when a planet exploded, shooting 2500 pixels off
in all directions, the game slowed down. We wanted to speed up the explosion routine. We did not care about the rest
of the code. The solution was to call profile(0) at the beginning of Language War, just after with profile time,
to turn off profiling, and then to call profile(1) at the beginning of the explosion routine and profile(0) at the end
114
CHAPTER 24. DEBUGGING AND PROFILING 24.5. SOME FURTHER NOTES ON TIME PROFILING
of the routine. In this way we could run the game, creating numerous explosions, and logging a lot of samples, just for
the explosion effect. If samples were charged against other lower-level routines, we knew that those samples occurred
during an explosion. If we had simply profiled the whole program, the picture would not have been clear, as the lower-level
routines would also have been used for moving ships, drawing phasors etc. profile() can help in the same way when you
do execution-count profiling.
will reserve space for 100000 samples (for example). If the buffer overflows youll see a warning at the top of ex.pro. At
100 samples per second your program can run for 250 seconds before using up the default 25000 samples. Its not feasible
for Euphoria to dynamically enlarge the sample buffer during the handling of an interrupt. Thats why you might have
to specify it in your program. After completing each top-level executable statement, Euphoria will process the samples
accumulated so far, and free up the buffer for more samples. In this way the profile can be based on more samples than
you have actually reserved space for.
The percentages shown in the left margin of ex.pro, are calculated by dividing the number of times that a particular
statement was sampled, by the total number of samples taken. e.g. if a statement were sampled 50 times out of a total
of 500 samples, then a value of 10.0 (10 per cent) would appear in the margin beside that statement. When profiling
is disabled with profile(0), interrupts are ignored, no samples are taken and the total number of samples does not
increase.
By taking more samples you can get more accurate results. However, one situation to watch out for is the case where
a program synchronizes itself to the clock interrupt, by waiting for time() to advance. The statements executed just after
the point where the clock advances might never be sampled, which could give you a very distorted picture. e.g.
while time () < LIMIT do
end while
x += 1 -- This statement will never be sampled
Sometimes you will see a significant percentage beside a return statement. This is usually due to time spent
deallocating storage for temporary and private variables used within the routine. Significant storage deallocation time can
also occur when you assign a new value to a large sequence.
If disk swapping starts to happen, you may see large times attributed to statements that need to access the swap file,
such as statements that access elements of a large swapped-out sequence.
115
Chapter 25
Binding and Shrouding
The shroud command converts a Euphoria program, typically consisting of a main file plus many include files, into
a single, compact file. A single file is easier to distribute, and it allows you to distribute your program to others without
releasing your source code.
A shrouded file does not contain any Euphoria source code statements. Rather, it contains a low-level Intermediate
Language (IL) that is executed by the back-end of the interpreter. A shrouded file does not require any parsing. It starts
running immediately, and with large programs you will see a quicker start-up time. Shrouded files must be run using the
interpreter back-end: eubw.exe (Windows) or eub.exe (Unix). This backend is freely available, and you can give it to
any of your users who need it. Its stored in euphoria\bin in the Euphoria interpreter package. You can run your .il
file with:
On Windows use:
eub myprog . il
eubw myprog . il
On Unix use:
eub myprog . il
Although it does not contain any source statements, a .il file will generate a useful ex.err dump in case of a run-time
error.
The shrouder will remove any routines and variables that your program doesnt use. This will give you a smaller .il
file. There are often a great number of unused routines and unused variables. For example, your program might include
several third party include files, plus some standard files from euphoria\include, but only use a few items from each
file. The unused items will be deleted.
25.1.2 Options
-full debug: Make a somewhat larger .il file that contains enough debug information to provide a full ex.err dump
when a crash occurs. Normally, variable names and line-number information is stripped out of the .il file, so the
ex.err will simply have no-name where each variable name should be, and line numbers will only be accurate to
the start of a routine or the start of a file. Only the private variable values are shown, not the global or local values.
In addition to saving space, some people might prefer that the shrouded file, and any ex.err file, not expose as
much information.
116
CHAPTER 25. BINDING AND SHROUDING 25.2. THE BIND COMMAND
-list: Produce a listing in deleted.txt of the routines and constants that were deleted.
The Euphoria interpreter will not perform tracing on a shrouded file. You must trace your original source.
On Unix, the shrouder will make your shrouded file executable, and will add a ! line at the top, that will run eub.exe.
You can override this ! line by specifying your own ! line at the top of your main Euphoria file.
Always keep a copy of your original source. Theres no way to recover it from a shrouded file.
eubind does the same thing as eushroud, and includes the same options. It then combines your shrouded .il file
with the interpreter backend (eub.exe, eubw.exe or eub) to make a single, stand-alone executable file that you can
conveniently use and distribute. Your users need not have Euphoria installed. Each time your executable file is run, a
quick integrity check is performed to detect any tampering or corruption. Your program will start up very quickly since no
parsing is needed.
The Euphoria interpreter will not perform tracing on a bound file since the source statements are not there.
25.2.2 Options:
-c config-file: A Euphoria config file to use when binding.
-con: (Windows only): This option will create a Windows console program instead of a Windows GUI program.
Console programs can access standard input and output, and they work within the current console window, rather
than popping up a new one.
-eub path-to-backend Allows specification of the backend runner to use instead of the default, installed version.
-full debug: Same as shroud above. If Euphoria detects an error, your executable will generate either a partial, or
a full, ex.err dump, according to this option.
-i dir: A directory to add to the paths to use for searching for included files.
-icon filename[.ico]: (Windows only) When you bind a program, you can patch in your own customized icon,
overwriting the one in euiw.exe. eui.exe contains a 32x32 icon using 256 colors. It resembles an E) shape.
Windows will display this shape beside euiw.exe, and beside your bound program, in file listings. You can also
load this icon as a resource, using the name euiw (see euphoria\demo\win32\window.exw for an example).
When you bind your program, you can substitute your own 32x32 256-color icon file of size 2238 bytes or less.
Other dimensions may also work as long as the file is 2238 bytes or less. The file must contain a single icon image
(Windows will create a smaller or larger image as necessary). The default E) icon file, euphoria.ico, is included
in the euphoria\bin directory.
-out executable file: This option lets you choose the name of the executable file created by the binder. Without
this option, eubind will choose a name based on the name of the main Euphoria source file.
117
CHAPTER 25. BINDING AND SHROUDING 25.2. THE BIND COMMAND
A one-line Euphoria program will result in an executable file as large as the back-end you are binding with, but the size
increases very slowly as you add to your program. When bound, the entire Euphoria editor, ed.ex, adds only 27K
to the size of the back-end.
The first two items returned by command line() will be slightly different when your program is bound. See the procedure
description for the details.
A bound executable file can handle standard input and output redirection. e.g.
myprog . exe < file . in > file . out
If you were to write a small .bat file, say myprog.bat, that contained the line eui myprog.ex you would not be
able to redirect input and output. The following will not work:
myprog . bat < file . in > file . out
You could however use redirection on individual lines within the .bat file.
118
Chapter 26
Euphoria To C Translator
26.1 Introduction
The Euphoria to C Translator (translator) will translate any Euphoria program into equivalent C source code.
There are versions of the translator for Windows and Unix operating Systems. After translating a Euphoria program
to C, you can compile and link using one of the supported C compilers. This will give you an executable file that will
typically run much faster than if you used the Euphoria interpreter.
The translator can translate and then compile itself into an executable file for each platform. The translator is also used
in translating/compiling the front-end portion of the interpreter. The source code for the translator is in euphoria\source.
It is written 100% in Euphoria.
26.2.1 Notes:
Warnings are turned off when compiling directly or with makefiles. If you turn them on, you may see some harmless
messages about variables declared but not used, labels defined but not used, function prototypes not declared etc.
For the -gcc option on Windows you will need a eu.a compiled with MinGW or Cygwin. The official distribution
may only contain eu.lib compiled with Watcom. Also, the -stack and -con options may not produce the expected
result with GCC C.
119
CHAPTER 26. EUPHORIA TO C TRANSLATOR 26.4. COMMAND-LINE OPTIONS
When the C compiling and linking is finished, you will have a file called allsorts.exe or simply allsorts on *nix
systems. The C source files will have been removed to avoid clutter.
When you run the allsorts executable, it should run the same as if you had typed:
eui allsorts
to run it with the Interpreter, except that it should run faster, showing reduced times for the various sorting algorithms
in euphoria\demo\allsorts.ex.
After creating your executable file, the translator removes all the C files that were created. If you want to look at these
files, youll need to run the translator again, using either the -keep or -makefile options.
26.4.2 -keep
Normally, after building your .exe file, the translator will delete all C files and object files produced by the Translator. If
you want it to keep these files, add the -keep option to the Translator command-line. e.g.
euc - keep sanity . ex
Note: On *nix systems, you can also use -so. Both will produce a *nix shared library.
Please see Dynamic Link Libraries
When creating a Windows GUI program, if the -con option is used, when running your Windows program, you will
have a blank console window appear and remain the duration of your application. By default, a GUI program is assumed.
The resulting executable will contain all the resources from myapp.rc compiled into the executable. Please see Using
Resource Files.
120
CHAPTER 26. EUPHORIA TO C TRANSLATOR 26.4. COMMAND-LINE OPTIONS
The total stack space (in bytes) that you specify will be divided up among all the tasks that you have running (assuming
you have more than one). Each task has its own private stack space. If it exceeds its allotment, youll get a run-time
error message identifying the task and giving the size of its stack space. Most non-recursive tasks can run with call stacks
as small as 2000 bytes, but to be safe, you should allow more than this. A deeply-recursive task could use a great deal of
space. It all depends on the maximum levels of calls that a task might need. At run-time, as your program creates more
simultaneously-active tasks, the stack space allotted to each task will tend to decrease.
FREEBSD
LINUX
OSX
WINDOWS
NETBSD
OPENBSD
Use one of these options to translate code into C for the specified platform. The default will always be the host
platform of the translator that is executed, so euc.exe will default to Windows, and euc will default to the platform upon
which it was built.
The resulting output can be compiled by the appropriate compiler on the specified platform, or, possibly a cross
platform compiler, if you have one configured.
121
CHAPTER 26. EUPHORIA TO C TRANSLATOR 26.5. DYNAMIC LINK LIBRARIES
On Windows, when using Watcom, the message will refer to wmake, the Watcom version of make. On BSD platforms,
you may need to use gmake, as the generated makefiles are in GNU format, not BSD.
You can also get a partial makefile using the -makefile-partial switch. This generates a makefile that you can use
to include into another makefile for a larger project. This is useful for including the file dependencies for your code into
the larger project.
would be exported as 0foo or maybe 1foo etc. The underscore and digit are added to prevent naming conflicts.
The digit refers to the Euphoria file where the identifier is defined. The main file is numbered as 0. The include files are
numbered in the order they are encountered by the compiler. You should check the C source to be sure.
For Watcom, the Translator also creates an EXPORT command, added to objfiles.lnk for each exported identifier,
so foo() would be exported as foo.
With Watcom, if you specify the -makefile option, you can edit the objfiles.lnk file to rename the exported
identifiers, or remove ones that you dont want to export. Then build with the generated makefile.
Having nice exported names is not critical, since the name need only appear once in each Euphoria program that
uses the shared dynamically loading library, i.e. in a single define c func() or define c proc() statement. The author of a
shared dynamically loading library should probably provide his users with a Euphoria include file containing the necessary
define c func() and define c proc() statements, and he might even provide a set of Euphoria wrapper routines to call
the routines in the shared dynamically loading library.
When you call open dll(), any top-level Euphoria statements in the shared dynamically loading library will be executed
automatically, just like a normal program. This gives the library a chance to initialize its data structures prior to the first
call to a library routine. For many libraries no initialization is required.
122
CHAPTER 26. EUPHORIA TO C TRANSLATOR 26.6. USING RESOURCE FILES
To pass Euphoria data (atoms and sequences) as arguments, or to receive a Euphoria object as a result, you will need
to use the following constants in euphoria\include\dll.e:
1 -- Euphoria types for shared dynamically loading library arguments
2 -- and return values :
3
4 global constant
5 E_INTEGER = #06000004 ,
6 E_ATOM = #07000004 ,
7 E_SEQUENCE = #08000004 ,
8 E_OBJECT = #09000004
Use these in define c proc() and define c func() just as you currently use C INT, C UINT etc. to call C shared
dynamically loading libraries.
Currently, file numbers returned by open(), and routine ids returned by routine id(), can be passed and returned, but
the library and the main program each have their own separate ideas of what these numbers mean. Instead of passing the
file number of an open file, you could instead pass the file name and let the shared dynamically loading library open it.
Unfortunately there is no simple solution for passing routine ids. This might be fixed in the future.
A Euphoria shared dynamically loading library currently may not execute any multitasking operations. The Translator
will give you an error message about this.
Euphoria shared dynamically loading library can also be used by C programs as long as only 31-bit integer values are
exchanged. If a 32-bit pointer or integer must be passed, and you have the source to the C program, you could pass
the value in two separate 16-bit integer arguments (upper 16 bits and lower 16 bits), and then combine the values in the
Euphoria routine into the desired 32-bit atom.
FILEVERSION 4 ,0 ,0 ,9
PRODUCTVERSION 4 ,0 ,0 ,9
FILEFLAGSMASK 0 x3fL
FILEFLAGS 0 x0L
FILEOS 0 x4L
FILETYPE 0 x1L
FILESUBTYPE 0 x0L
BEGIN
BLOCK " StringFileInfo "
BEGIN
BLOCK "040904 B0 "
BEGIN
VALUE " Comments " , " http :// myapplication . com \0"
VALUE " CompanyName " , " John Doe Computing \0"
VALUE " FileDescription " , " Cool App \0
VALUE " FileVersion " , "4.0.0\0"
123
CHAPTER 26. EUPHORIA TO C TRANSLATOR 26.7. EXECUTABLE SIZE AND COMPRESSION
One other item you may wish to include is a manifest file which lets Windows know that controls should use the new
theming engines available in >= Windows XP. Simply append:
1 24 " coolapp . manifest "
Version, Product and Manfiest information may change with new releases of Microsoft Windows. You should consult
MSDN for up to date information about using resource files with your application. MSDN About Resource Files.
124
CHAPTER 26. EUPHORIA TO C TRANSLATOR 26.8. INTERPRETER VS. TRANSLATOR
Nevertheless, your compiled executable file will likely be larger than the same Euphoria program bound with the
interpreter back-end. This is partly due to the back-end being a compressed executable. Also, Euphoria statements are
extremely compact when stored in a bound file. They need more space after being translated to C, and compiled into
machine code. Future versions of the Translator will produce faster and smaller executables.
26.8.1 Note:
The Translator assumes that your program has no run-time errors in it that would be caught by the Interpreter. The
Translator does not check for: subscript out of bounds, variable not initialized, assigning the wrong type of data to a
variable, etc.
You should debug your program with the Interpreter. The Translator checks for certain run-time errors, but in the
interest of speed, most are not checked. When translated C code crashes youll typically get a very cryptic machine
exception. In most cases, the first thing you should do is run your program with the Interpreter, using the same inputs,
and preferably with type check turned on. If the error only shows up in translated code, you can use with trace
and trace(3) to get a ctrace.out file showing a circular buffer of the last 500 Euphoria statements executed. If a
translator-detected error message is displayed (and stored in ex.err), you will also see the offending line of Euphoria
source whenever with trace is in effect. with trace will slow your program down, and the slowdown can be extreme
when trace(3) is also in effect.
26.10 Disclaimer:
This is what we believe to be the case. We are not lawyers. If its important to you, you should read all licences and the
legal comments in them, to form your own judgment. You may need to get professional legal opinion as well.
125
CHAPTER 26. EUPHORIA TO C TRANSLATOR 26.11. FREQUENTLY ASKED QUESTIONS
26.11.2 What if I want to change the compile or link options in my generated makefile?
Feel free to do so, thats one reason for producing a makefile.
26.12.1 Note:
On Windows, if you call a C routine that uses the cdecl calling convention (instead of stdcall), you must specify a +
character at the start of the routines name in define c proc() and define c func(). If you dont, the call may not work
when running the eui Interpreter.
In some cases a huge Euphoria routine is translated to C, and it proves to be too large for the C compiler to process.
If you run into this problem, make your Euphoria routine smaller and simpler. You can also try turning off C optimization
in your makefile for just the .c file that fails. Breaking up a single constant declaration of many variables into separate
constant declarations of a single variable each, may also help. Euphoria has no limits on the size of a routine, or the size
of a file, but most C compilers do. The Translator will automatically produce multiple small .c files from a large Euphoria
file to avoid stressing the C compiler. It wont however, break a large routine into smaller routines.
126
Chapter 27
Indirect routine calling
Euphoria does not have function pointers. However, it enables you to call any routine, including some internal to the
interpreter, in an indirect way, using two different sets of identifiers.
Because value() is defined as public, that routine is in scope. This ensures the call succeeds. A failed call returns
-1, else a small nonnegative integer.
You can then feed this integer to call func() or call proc() as appropriate. It does not matter whether the routine
is still in scope at the time you make that call. Once the id is gotten, its valid.
Calling a function
where
argument sequence is the list of the parameters to pass, enclosed into curly braces
127
CHAPTER 27. INDIRECT ROUTINE CALLING 27.1. INDIRECT CALLING A ROUTINE CODED IN EUPHORIA
1 include get . e
2
This is equivalent to
result = value ( " Model 36 A " , 6 , GET_LONG_ANSWER )
Calling a procedure
The same formalism applies, but using call proc() instead. The differences are almost the same as between c func()
and c proc().
1 include std / pretty . e
2
The difference with c proc() is that you can call an external function using c proc() and thus ignore its return value,
like in C. Note that you cannot use call proc() to invoke a Euphoria function, only C functions.
23 -- Initialize foo ID
24 switch user_opt ( " dev " ) do
128
CHAPTER 27. INDIRECT ROUTINE CALLING 27.2. CALLING EUPHORIAS INTERNALS
25 case 1 then
26 foo_id = routine_id ( " foo_dev1 " )
27 case 2 then
28 foo_id = routine_id ( " foo_dev2 " )
29 case else
30 foo_id = routine_id ( " foo_dev3 " )
31 end switch
One last word: when calling a routine indirectly, its full parameter list must be passed, even if some of its parameters
are defaulted. This limitation may be overcome in future versions.
argument is either an atom, or a sequence standing for one or more parameters. Since the first parameter does not
need to be a constant, you may use some sort of dynamic calling. The circumstances where it is useful are rare.
The complete list of known values for id is to be found in the file source/execute.h.
Defining new identifiers and overriding machine func() or machine proc() to handle them is an easy way to extend
the capabilities of the interpreter.
129
Chapter 28
Multitasking in Euphoria
28.1 Introduction
Euphoria allows you to set up multiple, independent tasks. Each task has its own current statement that it is executing,
its own call stack, and its own set of private variables. Tasks run in parallel with each other. That is, before any given task
completes its work, other tasks can be given a chance to execute. Euphorias task scheduler decides which task should be
active at any given time.
130
CHAPTER 28. MULTITASKING IN EUPHORIA 28.4. A SMALL EXAMPLE
This example shows the main task (which all Euphoria programs start off with) creating two additional real-time tasks.
We call them real-time because they are scheduled to get control every few seconds.
You should try copy/pasting and running this example. Youll see that task 1 gets control every 2.5 to 3 seconds, while
task 2 gets control every 5 to 5.1 seconds. In between, the main task (task 0), has control as it checks for a q character
to abort execution.
27 atom t1 , t2
28
35 t1_running = TRUE
36 t2_running = TRUE
37
131
CHAPTER 28. MULTITASKING IN EUPHORIA 28.5. COMPARISON WITH EARLIER MULTITASKING SCHEMES
At the machine level, the first task loads the value of x into a register, then loses control to the second task which
increments x and stores the result back into x in memory. Eventually control goes back to the first task which also
increments x *using the value of x in the register*, and then stores it into x in memory. So x has only been incremented
once instead of twice as was intended. To avoid this problem, each thread would need something like:
lock x
x = x + 1
unlock x
where lock and unlock would be special primitives that are safe for threading. Its often the case that programmers
forget to lock data, but their program seems to run ok. Then one day, many months after theyve written the code, the
program crashes mysteriously.
Cooperative multitasking is much safer, and requires far fewer expensive locking operations. Tasks relinquish control
at safe points once they have completed a logical operation.
28.7 Summary
For a complete function reference, refer to the Library Documentation Multitasking.
132
Chapter 29
Euphoria Database System (EDS)
29.1 Introduction
While you can connect Euphoria to most databases (MySQL, SQLite, PostgreSQL, etc.), sometimes you dont need that
kind of power. The Euphoria Database System (EDS) is a simple, easy-to-use, flexible, Euphoria-oriented database for
storing data that works better for cases where you need more than a text file and dont quite need or want the power and
complexity of larger database packages.
Its up to you to interpret the meaning of the key and data. In keeping with the spirit of Euphoria, you have total
flexibility. Unlike most other database systems, an EDS record is not required to have either a fixed number of fields, or
fields with a preset maximum length.
133
CHAPTER 29. EUPHORIA DATABASE SYSTEM (EDS) 29.3. HOW TO ACCESS THE DATA
In many cases there will not be any natural key value for your records. In those cases you should simply create a
meaningless, but unique, integer to be the key. Remember that you can always access the data by record number. Its
easy to loop through the records looking for a particular field value.
29.6 Scalability
Internal pointers are 4 bytes. In theory that limits the size of a database file to 4 Gb. In practice, the limit is 2 Gb because
of limitations in various C file functions used by Euphoria. Given enough user demand, EDS databases could be expanded
well beyond 2 Gb in the future.
The current algorithm allocates four bytes of memory per record in the current table. So youll need at least 4 Mb
RAM per million records on disk.
The binary search for keys should work reasonably well for large tables.
Inserts and deletes take slightly longer as a table gets larger.
At the low end of the scale, its possible to create extremely small databases without incurring much disk space
overhead.
134
CHAPTER 29. EUPHORIA DATABASE SYSTEM (EDS) 29.7. EDS API
29.8 Disclaimer
Do not store valuable data without a backup. RDS will not be responsible for any damage or data loss.
135
Chapter 30
The User Defined Pre-Processor
The user defined pre-processor, developed by Jeremy Cowgar, opens a world of possibilities to the Euphoria programmer.
In a sentence, it allows one to create (or use) a translation process that occurs transparently when a program is run. This
mini-guide is going to explore the pre-processor interface by first giving a quick example, then explaining it in detail and
finally by writing a few useful pre-processors that can be put immediately to work.
Any program can be used as a pre-processor. It must, however, adhere to a simple specification:
1. Accept a parameter -i filename which specifies which file to read and process.
2. Accept a parameter -o filename which specifies which file to write the result to.
3. Exit with a zero error code on success or a non-zero error code on failure.
It does not matter what type of program it is. It can be a Euphoria script, an executable written in the C programming
language, a script/batch file or anything else that can read one file and write to another file. As Euphoria programmers,
however, we are going to focus on writing pre-processors in the Euphoria programming language. As a benefit, we will
describe later on how you can easily convert your pre-processor to a shared library that Euphoria can make use of directly
thus improving performance.
136
CHAPTER 30. THE USER DEFINED PRE-PROCESSOR 30.2. PRE-PROCESS DETAILS
So, that is our pre-processor. Now, how do we make use of it? First lets create a simple test program that we can
watch it work with. Name this file thedate.ex.
-- thedate . ex
Rather simple, but it shows off the pre-processor we have created. Now, lets run it, but first without a pre-processor
hook defined.
NOTE: Through this document I am going to assume that you are working in Windows. If not, you can make the
appropriate changes to the shell type examples.
C :\ MyProjects \ datesub > eui thedate . ex
The date this was run is @DATE@
Not very helpful? Ok, lets tell Euphoria how to use the pre-processor that we just created and then see what happens.
C :\ MyProjects \ datesub > eui -p eui : datesub . ex thedate . ex
The date this was run is 2009 -08 -05 19:36:22
If you got something similar to the above output, good job, it worked! If not, go back up and check your code for
syntax errors or differences from the examples above.
What is this -p paramater? In short, -p tells eui or euc that there is a pre-processor. The definition of the pre-processor
comes next and can be broken into 2 required sections and 1 optional section. Each section is divided by a colon (:).
For example, -p e,ex:datesub.ex
1. e,ex tells Euphoria that when it comes across a file with the extension e or ex that it should run a pre-processor
2. datesub.ex tells Euphoria which pre-processor should be run. This can be a .ex file or any other executable
command.
3. An optional section exists to pass options to the pre-processor but we will go into this later.
Thats it for the quick introduction. I hope that the wheels are turning in your head already as to what can be
accomplished with such a system. If you are interested, please continue reading and see where things will get very
interesting!
137
CHAPTER 30. THE USER DEFINED PRE-PROCESSOR 30.3. COMMAND LINE OPTIONS
-p e:datesub.ex - This will be executed for every .e file and the command to call is datesub.ex.
-p "de,dex,dew:dot4.dll:-verbose -no-dbc" - Files with de, dex, dew extensions will be passed to the
dot4.dll process. dot4.dll will get the optional parameters -verbose -no-dbc passed to it.
is a valid command line. Its possible that hello.ex may include a file named greeter.le and that file may include
a file named person.de. Thus, all three pre-processors will be called upon even though the main file is only processed by
datesub.ex
Then you can execute any of those files directly without the -p parameters on the command line. This eu.cfg file
can be local to a project, local to a user or global on a system. Please read about the eu.cfg file for more information.
138
CHAPTER 30. THE USER DEFINED PRE-PROCESSOR 30.4. DLL/SHARED LIBRARY INTERFACE
1 -- datesub . ex
2 include std / datetime . e -- now () and format ()
3 include std / io . e -- read_file () and write_file ()
4 include std / search . e -- match_replace ()
5
15 return 0
16 end function
17
Its beginning to look a little more like a well structured program. Youll notice that we took the actual pre-processing
functionality out the the top level program making it into an exported function named preprocess. That function takes
three parameters:
3. options - options that the user may wish to pass on verbatim to the pre-processor
It should return 0 on no error and non-zero on an error. This is to keep a standard with the way error levels from
executables function. In that convention, its suggested that 0 be OK and 1, 2, 3, etc... indicate different types of error
conditions. Although the function could return a negative number, the main routine cannot exit with a negative number.
To use this new process, we simply translate it through euc,
If all went correctly, you now have a datesub.dll file. Im sure you can guess on how it should be used, but for the sake
of being complete,
On such a simple file and such a simple pre-processor, you probably are not going to notice a speed difference but as
things grow and as the pre-processor gets more complicated, compiling to a shared library is your best option.
139
CHAPTER 30. THE USER DEFINED PRE-PROCESSOR 30.5. ADVANCED EXAMPLES
1 -- datesub . ex
2 include std / cmdline . e -- command line parsing
3 include std / datetime . e -- now () and format ()
4 include std / io . e -- read_file () and write_file ()
5 include std / map . e -- map accessor functions ( get ())
6 include std / search . e -- match_replace ()
7
8 sequence cmdopts = {
9 { " f " , 0 , " Date format " , { NO_CASE , HAS_PARAMETER , " format " } }
10 }
11
17 content = match_replace ( " @DATE@ " , content , format ( now () , map : get ( opts ,
18 " f " )))
19
22 return 0
23 end function
24
Here we simply used cmdline.e to handle the command line parsing for us giving out command line program a nice
interface, such as parameter validation and an automatic help screen. At the same time we also added a parameter for
the date format to use. This is optional and if not supplied, %Y-%m-%d is used.
The final version of datesub.ex and thedate.ex are located in the demo/preproc directory of your Euphoria
installation.
30.5.2 Others
TODO: this needs done still.
Euphoria includes two more demos of pre-processors. They are ETML and literate. Please explore demo/preproc for
these examples and explanations.
140
CHAPTER 30. THE USER DEFINED PRE-PROCESSOR 30.5. ADVANCED EXAMPLES
make40 - Will process any 3.x script on the fly making sure that it will run in 4.x. It does this by converting variables,
constants and routine names that are the same as new 4.x keywords into something acceptable to 4.x. Thus, 3.x
programs can run in the 4.x interpreter and translator with out any user intervention.
dot4 - Adds all sorts of syntax goodies to Euphoria such as structured sequence access, one line if statements, DOT
notation for any function/routine call, design by contract and more.
Other Ideas
Include a Windows .RC file that defines a dialog layout and generate code that will create the dialog and interact
with it.
Object Oriented system for Euphoria that translates into pure Euphoria code, thus has the raw speed of Euphoria.
Include a Yacc, Lex, ANTLR parser definition directly that then generates a Euphoria parser for the given syntax.
Instead of writing interpreters such as a QBasic clone, simply write a pre-processor that converts QBasic code into
Euphoria code, thus you can run eui -p bas:qbasic.ex hello.bas directly.
Include a XML specification, which in turn, gives you nice accessory functions for working with XML files matching
that schema.
If you have ideas of helpful pre-processors, please put the idea out on the forum for discussion.
141
Chapter 31
Euphoria Trouble-Shooting Guide
If you get stuck, here are some things you can do:
1. Type: guru followed by some keywords associated with your problem. For example, guru declare global
include
3. Read the relevant parts of the documentation, i.e. Euphoria Programming Language v4.0 or API Reference.
with trace
trace (1)
1. The Euphoria Forum has a search facility. You can search the archive of all previous messages. There is a good
chance that your question has already been discussed.
142
CHAPTER 31. EUPHORIA TROUBLE-SHOOTING GUIDE 31.1. COMMON PROBLEMS AND SOLUTIONS
free_console ()
1. Make sure that you are using the -batch parameter to eui. This causes Euphoria to not present the normal Press
any key to continue... prompt when a warning or error occurs. The web server will not respond to this prompt and
your application will hang waiting for ENTER to be pressed.
2. Use the -wf parameter to write all warnings to a file instead of the console. The warnings that Euphoria will write
to the console may interfere with the actual output of your web content.
3. Look for an ex.err file in your cgi-bin directory. Turn on with trace / trace(3) to see what statements are
executed (see ctrace.out in your cgi-bin). On Windows you should always use eui.exe to run CGI programs, or
you may have problems with standard output. With Apache Web Server, you can have a first line in your program
of:
4. !.\eui.exe to run your program using eui.exe in the current (cgi-bin) directory. Be careful that your first line ends
with the line breaking characters appropriate for your platform, or the ! wont be handled correctly. You must also
set the execute permissions on your program correctly, and ex.err and ctrace.out must be writable by the server
process or they wont be updated.
143
CHAPTER 31. EUPHORIA TROUBLE-SHOOTING GUIDE 31.1. COMMON PROBLEMS AND SOLUTIONS
or use number:
include std / locale . e as locale
string = locale : number (10)
-- string is probably "10.00" if called in the U . S .
-- It depends on the locale preferences set on your computer .
Number formats according to the locale setting on your computer and strangely, this means to give you two decimal
places whether or not you supply an integer value for the U.S. locale.
Besides %d, you can also try other formats, such as %x (Hex) or %f (floating-point).
144
CHAPTER 31. EUPHORIA TROUBLE-SHOOTING GUIDE 31.1. COMMON PROBLEMS AND SOLUTIONS
145
Chapter 32
Platform Specific Issues
32.1 Introduction
OpenEuphoria currently supports Euphoria on many different platforms. More platforms will be added in the future.
**DOS** platform support has been discontinued.
**Windows** in particular, the 32-bit x86 compatible version of Windows. The minimum version is Windows 95
Original Equipment Manufacturer Service Release 2.5. EUPHORIA will work on all old and new versions of Windows
written after Windows 95. However, to use all of the features you must use Windows XP or later. See .
Linux. Linux is based on the UNIX operating system. It has recently become very popular on PCs. There are many
distributors of Linux, including Red Hat, Debian, Caldera, etc. Linux can be obtained on a CD for a very low price. Linux
is an open-source operating system.
FreeBSD. FreeBSD is also based on the UNIX operating system. It is very popular on Internet server machines. Its
also open source.
Apples OS X. OS X is also based on the UNIX operating system. While it is closed source, it is gaining a wide
following due to its ease of use and power.
OpenBSD. Open BSD is also a UNIX-like Operating System and is developed by volunteers.
NetBSD. Net BSD is also a UNIX-like Operating System and is designed to be easily portable to other hardware
platforms.
Euphoria source files use various file extensions. The common extensions are:
extension application
.e Euphoria include file
.ew Euphoria include file for a Windowed (GUI) application
only
.ex Console main program file
or any executable program
.exw Windowed (GUI) main program file
or a Windows specific program
.exu Unix specific program
It is convenient to use these file extensions, but they are not mandatory.
The Euphoria for Windows installation file contains eui.exe. It runs Euphoria programs on the Windows 32bit platform.
The Euphoria for Linux .tar file contains only eui. It runs Euphoria programs on the Linux platform.
Other versions of Euphoria are installed by first installing the Linux version of Euphoria, replacing eui with the version
of eui for that Operating System, then rebuilding the other binaries from the source.
Sometimes youll find that the majority of your code will be the same on all platforms, but some small parts will have
to be written differently for each platform. Use the ifdef statement to tell you which platform you are currently running
on.
You can also use the platform and platform name functions:
printf (1 , " Our platform number is : % d " , { platform ()})
146
CHAPTER 32. PLATFORM SPECIFIC ISSUES 32.1. INTRODUCTION
The evaluation of platform occurs at runtime, you may even use a switch statement with it.
1 switch platform () do
2 case WINDOWS then
3 -- Windows code
4 case LINUX then
5 -- LINUX code
6 case FREEBSD , NETBSD then
7 -- BSD code
8 ... etc
9 case else
10 crash ( " Unsupported platform " )
11 end switch
With parse-time evalution you get faster execution, for there is no conditional in the final code. You can put this
deeply inside a loop without penalty. You can test for UNIX to see if the platform has UNIX like properties and thus will
work on new UNIX like platforms without modification. You can even put statements that are top-level, such as constant
and routine defintions. However, since the interpreter skips over the platforms you are not running on, syntax errors can
hide in this construct and if you misspell an OS name you will not get warned.
1 ifdef UNIX then
2 public constant SLASH = /
3 public constant SLASHES = " / "
4 public constant EOLSEP = " \ n "
5 public constant PATHSEP = :
6 public constant NULLDEVICE = " / dev / null "
7 ifdef OSX then
8 public constant SHARED_LIB_EXT = " dylib "
9 elsedef
10 public constant SHARED_LIB_EXT = " so "
11 end ifdef
12
13 public constant FOO = SLASH == PATHSEP -- this has a hidden syntax error
14
24 elsifdef TRASHOS then -- this symbol is never defined -- no error here either
25
26 end ifdef
147
CHAPTER 32. PLATFORM SPECIFIC ISSUES 32.2. THE DISCONTINUED DOS32 PLATFORM
In this above example, we have constant declarations which are different according to OS such things. The line with
FOO has a syntax error but your interpreter will not catch it if you are running WINDOWS. There is no OS with the name
TRASHOS. I simply made it up and this construct will not warn you about mistakes like these.
Run-time evalution provides you something that is always syntax-checked and you can even make expressions using
comparatives to avoid both parse-time and run-time branching all together.
1 add_code = {
2 -- first int argument is at stack offset +4 , 2 nd int is at +8
3 #8 B , #44 , #24 , #04 , -- mov eax , +4[ esp ]
4 #03 , #44 , #24 , #08 , -- add eax , +8[ esp ]
5 # C2 , #00 , #08 * ( platform () = WINDOWS ) -- ret 8
6 -- pop 8 bytes off the stack
7 }
This is machine code to be put into memory as an example from demo/callmach.ex. Here if platform() = WINDOWS
is true, then the code will pop 8 bytes off of the stack, if not it will pop 0 bytes off of the stack. This has to be done because
of where the function call conventions are implemented in the various compilers. We use Watcom C for WINDOWS and
GCC for the others. Now if the programmer had put a non-existent symbol, such as ARCH64, the parser would stop, point
out the error, and the programmer would then fix it.
148
CHAPTER 32. PLATFORM SPECIFIC ISSUES 32.4. THE UNIX PLATFORMS
Now with these lines the interpreter is forced to give you a runtime error, report where in the program the standard
input or output is used. It can be hard to find the offending I/O statement in programs that contain many commented
out or debug mode only console I/O statements.
If you actually *want* to use the console, and there is something on the console that you want your user to read,
you should prompt them and wait for his input before terminating. To prevent the console from quickly disappearing you
might include a statement such as:
include std / console . e
149
CHAPTER 32. PLATFORM SPECIFIC ISSUES 32.5. INTERFACING WITH C CODE
When porting code from Windows to Unix, youll notice the following differences:
Some of the numbers assigned to the 16 main colors in graphics.e are different. If you use the constants defined in
graphics.e you wont have a problem. If you hard-code your color numbers you will see that blue and red have been
switched etc.
The key codes for special keys such as Home, End, arrow keys are different, and there are some additional differences
when you run under XTERM.
The Enter key is code 10 (line-feed) on Linux, where on Windows it was 13 (carriage-return).
Other OSes use / (slash) on file paths. Windows use \ (backslash). If you use the SLASH constant from
std/filesys.e you dont have to worry about this however.
Calls to system() and system exec() that contain Windows commands will obviously have to be changed to the
corresponding Linux or FreeBSD command. e.g. DEL becomes rm, and MOVE becomes mv. Often
you can use a standard library call instead and it will be portable across platforms. For example you can use
filesys:create directory or filesys:delete file.
When running an interpreter or translator for a UNIX platform, platform will return one of the several symbols for
UNIX and a parsetime branch (with ifdef/end ifdef) with UNIX and the symbol that is that of the specific OS will be
followed.
We assume that the environment is always run from some kind of CLI in two routines: The routine has console always
returns 0, and maybe any key never waits for key input.
1 include dll . e
2
3 atom user32
4 integer LoadIcon , icon
150
CHAPTER 32. PLATFORM SPECIFIC ISSUES 32.5. INTERFACING WITH C CODE
struct example {
int a ; // offset 0
char * b ; // offset 4
char c ; // offset 8
long d ; // offset 12
};
The address that you get from allocate is always at least 4-byte aligned. This is useful, since WINDOWS structures
are supposed to start on a 4-byte boundary. Fields within a C structure that are 4-bytes or more in size must start on a
4-byte boundary in memory. 2-byte fields must start on a 2-byte boundary. To achieve this you may have to leave small
gaps within the structure. In practice it is not hard to align most structures since 90% of the fields are 4-byte pointers or
4-byte integers.
You can set the fields using something like:
poke4 ( p + 0 , a )
poke4 ( p + 4 , b )
151
CHAPTER 32. PLATFORM SPECIFIC ISSUES 32.5. INTERFACING WITH C CODE
poke4 ( p + 8 , c )
poke4 ( p +12 , d )
Tip:
For readability, make up Euphoria constants for the field offsets. See Example below.
1 constant RECT_LEFT = 0 ,
2 RECT_TOP = 4 ,
3 RECT_RIGHT = 8 ,
4 RECT_BOTTOM = 12 ,
5 RECT_SIZEOF = 16
6
The Euphoria code that accesses C routines and data structures may look a bit ugly, but it will typically form just a
small part of your program, especially if you use Win32Lib, EuWinGUI, or Irv Mullins X Windows library. Most of your
program will be written in pure Euphoria, which will give you a big advantage over those forced to code in C.
6 WndProcAddress = call_back ( id )
routine id uniquely identifies a Euphoria procedure or function by returning an integer value. This value can be used
later to call the routine. You can also use it as an argument to the call back function.
In the example above, The 32-bit call-back address, WndProcAddress, can be stored in a C structure and passed to
Windows via the RegisterClass() C API function.
This gives Windows the ability to call the Euphoria routine, WndProc(), whenever the user performs an action
on a certain class of window. Actions include clicking the mouse, typing a key, resizing the window etc.
See the window.exw demo program for the whole story.
Note:
It is possible to get a call-back address for any Euphoria routine that meets the following conditions: * the routine
must be a function, not a procedure * it must have from 0 to 9 parameters * the parameters should all be of type
atom (or integer etc.), not sequence * the return value should be an integer value up to 32-bits in size
152
CHAPTER 32. PLATFORM SPECIFIC ISSUES 32.5. INTERFACING WITH C CODE
You can create as many call-back addresses as you like, but you should not call call back for the same Euphoria routine
multiple times - each call-back address that you create requires a small block of memory.
The values that are passed to your Euphoria routine can be any 32-bit unsigned atoms, i.e. non-negative. Your
routine could choose to interpret large positive numbers as negative if that is desirable. For instance, if a C routine tried
to pass you -1, it would appear as hex FFFFFFFF. If a value is passed that does not fit the type you have chosen for a
given parameter, a Euphoria type-check error may occur (depending on type check)
No error will occur if you declare all parameters as atom.
Normally, as in the case of WndProc() above, Windows initiates these call-backs to your routines. It is also possible
for a C routine in any .dll to call one of your Euphoria routines. You just have to declare the C routine properly, and
pass it the call-back address.
Heres an example of a WATCOM C routine that takes your call-back address as its only parameter, and then calls
your 3-parameter Euphoria routine:
/* 1 - parameter C routine that you call from Euphoria */
unsigned EXPORT APIENTRY test1 (
LRESULT CALLBACK (* eu_callback )( unsigned a ,
unsigned b ,
unsigned c ))
{
/* Your 3 - parameter Euphoria routine is called here
via eu_callback pointer */
return (* eu_callback )(111 , 222 , 333);
}
The C declaration above declares test1 as an externally-callable C routine that takes a single parameter. The single
parameter is a pointer to a routine that takes 3 unsigned parameters - i.e. your Euphoria routine.
In WATCOM C, CALLBACK is the same as stdcall. This is the calling convention thats used to call
WINDOWS API routines, and the C pointer to your Euphoria routine should be declared this way too, or youll get an
error when your Euphoria routine tries to return to your .DLL.
If you need your Euphoria routine to be called using the cdecl convention, you must code the call to call back() as:
myroutineaddr = call_back ({ + , id })
The plus sign and braces indicate the cdecl convention. The simple case, with no braces, is stdcall.
In the example above, your Euphoria routine will be passed the three values 111, 222 and 333 as arguments. Your
routine will return a value to test1. That value will then be immediately returned to the caller of test1 (which could be at
some other place in your Euphoria program).
A call-back address can be passed to the UNIX signal() function to specify a Euphoria routine to handle various signals
(e.g. SIGTERM). It can also be passed to C routines such as qsort(), to specify a Euphoria comparison function.
153
Chapter 33
Performance Tips
If your program is way too slow, the tips below will probably not solve your problem. You should find a better overall
algorithm.
The easiest way to gain a bit of speed is to turn off run-time type-checking. Insert the line:
without type_check
at the top of your main .ex file, ahead of any include statements. Youll typically gain between 0 and 20 percent
depending on the types you have defined, and the files that you are including. Most of the standard include files do some
user-defined type-checking. A program that is completely without user-defined type-checking might still be speeded up
slightly.
Also, be sure to remove, or comment-out, any
with trace
with profile
with profile_time
statements. with trace (even without any calls to trace), and with profile can easily slow you down by 10% or more.
with profile time might slow you down by 1%. Each of these options will consume extra memory as well.
Calculations using integer values are faster than calculations using floating-point numbers
Declare variables as integer rather than atom where possible, and as sequence rather than object where possible.
This usually gains you a few percent in speed.
In an expression involving floating-point calculations, its usually faster to write constant numbers in floating point
form, e.g. when x has a floating-point value, say, x = 9.9
change:
x = x * 5
to:
x = x * 5.0
This saves the interpreter from having to convert integer 5 to floating-point 5.0 each time.
154
CHAPTER 33. PERFORMANCE TIPS 33.2. MEASURING PERFORMANCE
Euphoria does short-circuit evaluation of if, elsif, and while conditions involving and and or. Euphoria will stop
evaluating any condition once it determines if the condition is true or not. For instance in the if-statement:
The speed of access to private variables, local variables and global variables is the same.
There is no performance penalty for defining constants versus plugging in hard-coded literal numbers. The speed of:
y = x * MAX
There is no performance penalty for having lots of comments in your program. Comments are completely ignored.
They are not executed in any way. It might take a few milliseconds longer for the initial load of your program,
but thats a very small price to pay for future maintainability, and when you bind your program, or translate your
program to C, all comments are stripped out, so the cost becomes absolute zero.
You might rewrite the small chunk of code in different ways to see which way is faster.
155
CHAPTER 33. PERFORMANCE TIPS 33.3. HOW TO SPEED-UP LOOPS
becomes:
1 x = screen_memory
2 for i = 0 to 199 do
3 poke (x , 0)
4 x = x + 320
5 end for
When you have a sequence with multiple levels of subscripting, it is faster to change code like:
for i = 1 to 1000 do
y [ a ][ i ] = y [ a ][ i ]+1
end for
to:
1 ya = y [ a ]
2 for i = 1 to 1000 do
3 ya [ i ] = ya [ i ] + 1
4 end for
5 y [ a ] = ya
So you are doing two subscript operations per iteration of the loop, rather than four. The operations, ya = y[a] and
y[a] = ya are very cheap. They just copy a pointer. They dont copy a whole sequence.
There is a slight cost when you create a new sequence using a,b,c. If possible, move this operation out of a critical
loop by storing it in a variable before the loop, and referencing the variable inside the loop.
156
CHAPTER 33. PERFORMANCE TIPS 33.7. OPERATIONS ON SEQUENCES
versus:
z = repeat (0 , 5) -- if necessary
for i = 1 to 5 do
z[i] = x[i] + y[i]
end for
In most interpreted languages, it is much faster to process a whole sequence (array) in one statement, than it is to
perform scalar operations in a loop. This is because the interpreter has a large amount of overhead for each statement it
executes.
Euphoria is different. Euphoria is very lean, with little interpretive overhead, so operations on sequences dont always
win. The only solution is to time it both ways. The per-element cost is usually lower when you process a sequence in one
statement, but there are overheads associated with allocation and deallocation of sequences that may tip the scale the
other way.
When you write a loop that grows a sequence, by appending or concatenating data onto it, the time will, in general,
grow in proportion to the square of the number (N) of elements you are adding. However, if you can use one of the
special optimized forms of append(), prepend() or concatenation listed above, the time will grow in proportion to just N
(roughly). This could save you a huge amount of time when creating an extremely long sequence.
(You could also use repeat() to establish the maximum size of the sequence, and then fill in the elements in a loop,
as discussed below.)
to:
157
CHAPTER 33. PERFORMANCE TIPS 33.10. LIBRARY / BUILT-IN ROUTINES
For example:
-- Instead of ...
some_val = some_val * 3
-- Use ...
some_val *= 3
whenever left-hand-side contains at least two subscripts, or at least one subscript and a slice. In all simpler cases the
two forms run at the same speed (or very close to the same).
because append() has to allocate and reallocate space as x grows in size. With repeat(), the space for x is allocated
once at the beginning. (append() is smart enough not to allocate space with every append to x. It will allocate somewhat
more than it needs, to reduce the number of reallocations.)
These built-in operations are also optimize to make changes in place (where possible), rather than creating copies of
sequences via slices.
158
CHAPTER 33. PERFORMANCE TIPS 33.11. SEARCHING
with:
and_bits (x , p -1)
for greater speed when p is a positive power of 2. x must be a non-negative integer that fits in 32-bits.
arctan is faster than arccos or arcsin.
33.11 Searching
Euphorias find is the fastest way to search for a value in a sequence up to about 50 elements. Beyond that, you might
consider a map or other implementation of a hash table (demo\hash.ex) or a binary tree (demo\tree.ex).
33.12 Sorting
In most cases you can just use the shell sort routine in sort.e.
If you have a huge amount of data to sort, you might try one of the sorts in demo\allsorts.e (e.g. great sort). If
your data is too big to fit in memory, dont rely on Euphorias automatic memory swapping capability. Instead, sort a few
thousand records at a time, and write them out to a series of temporary files. Then merge all the sorted temporary files
into one big sorted file.
If your data consists of integers only, and they are all in a fairly narrow range, try the bucket sort in demo\allsorts.e.
159
CHAPTER 33. PERFORMANCE TIPS 33.15. USING THE EUPHORIA TO C TRANSLATOR
160
Part VII
Included Tools
161
Chapter 34
EuTEST - Unit Testing
34.1 Introduction
The testing system gives you the ability to check if the library, interpreter and translator works properly by use of unit
tests. The unit tests are Euphoria include files that include unittest.e at the top, several test-routines for comparison
between expected value and true value and at the end of the program a call to test report(). There are error control
files for when we expect the interpreter to fail but we want it to fail with a particular error message. You may use this
section as an outline for testing your own code.
162
CHAPTER 34. EUTEST - UNIT TESTING 34.3. THE UNIT TEST FILES
-i: is for specify the include path which will be passed to both the interpreter and the translator when interpreting
and translating the test.
-cc: is for specifying the compiler. This can be any one of -wat, djg, or gcc. Each of these represent the kind of
compiler we will request the translator to use.
-process-log: Is for processing a log created by a previous invocation of eutest.ex output is sent to standard output
as a report of how the tests went. By default this is in ASCII format. Use -html to make it HTML format.
-D NO INET: This is for keeping tests from trying to use the Internet. The tests have to be written to support them
by using ifdef/end ifdef statements. Since in some Euphoria unit tests -D NO INET TESTS is used in its place,
you must use both options to prevent them from trying to connect through the Internet.
test_report ()
Please see the Unit Testing Framework, for information on how to construct these files.
t foo.d/interpreter/OSNAME/ control.err
t foo.d/OSNAME/ control.err
t foo.d/control.err
The OSNAME is the name of the operating system. Which is either UNIX or Win32.
Now, if t foo.d/Win32/control.err exists, then the testing program eutest.ex expects t foo.e to fail when run
with the WINDOWS interpreter. However, this is not necessarily true for other platforms. In WINDOWS, eutest runs it,
watches it fail, then compares the ex.err file to t foo.d/Win32/control.err. If they ex.err is different from control.err
an error message is written to the log. Now on, say NetBSD, t file.e is tested with the expectation it will return 0 and the
tests will all pass unless t foo.d/UNIX/control.err or t foo.d/control.err also exist. Thus you can have different
expectations for differing platforms. Some feature that is not possible to implement under WINDOWS can be put into a
unit test and the resulting ex.err file can be put into a control file for WINDOWS. This means we do not need to have
163
CHAPTER 34. EUTEST - UNIT TESTING 34.5. TEST COVERAGE
all of these errors that we expect to get drawing our attention away from errors that need our attention. On the other
hand, if an unexpected error message not like t foo.d/Win32/control.err gets generated in the Windows case then
eutest will tell us that.
How do we construct these control files? You dont really need to, you can take an ex.err file that results from
running a stable interpreter on a test and rename it and move it to the appropriate place.
Unix :
$ make coverage
Then, in your build directory, eutest will run the tests to create the coverage database unit-test.edb, and will
post-process the results, placing the HTML reports into a unit-test subdirectory from your build directory.
-coverage-db <file> This one allows you to specify a specific location and name for the database where coverage
information is stored. Its an EDS database. By default, the DB is eui-cvg.edb.
-coverage-erase Tells the interpreter to start over. By default, multiple runs accumulate coverage in the DB to
allow coverage analysis based on a suite of unit test files.
-coverage-exclude <pattern> Specifies a regular expression that is used to exclude files from coverage analysis.
-coverage-pp <post-processor> Supported by eutest only (i.e., not the interpreter itself). Tells eutest how to
post process the coverage data. <post-processor> must be the path to a the post processing application. After
running the suite of tests, eutest will execute this program with the path to the coverage db as an argument.
164
CHAPTER 34. EUTEST - UNIT TESTING 34.5. TEST COVERAGE
comments, declarations or end clauses of code blocks that do not create any executable code. Red lines are those that
were never executed, and lines that were executed are colored green. The line number is displayed in the left margin, and
the number of times each line was executed is displayed just to the left of where the source code begins.
-v Verbose output
165
Chapter 35
EuDOC - Source Documentation Tool
Writing and managing documentation for your programs is made easier with the eudoc tool. eudoc, written entirely in
Euphoria, converts text comments embedded in your program, as well as information about routines and identifiers, into
documentation that can be saved in a variety of formats, including plain text and HTML.
Since Euphoria comments do not slow down the execution of programs, documentation written inside source-code
introduces no speed penalty but is very convenient.
eudoc can also incorporate documentation written externally from your source-code.
You write your material using Creole style markup to format documention. This gives you creative control using
elements like headers, fonts, cross-references, tables, etc. The creole program takes the output of eudoc and produces
HTML-formatted documentation.
A third party program like htmldoc or wkhtmltopdf may then be used to convert HTML to PDF. creole will also
output LaTeX files directly that can be used to create professional PDF files for online viewing or publishing.
Produces...
generic text , thus tagged , will be extracted by eudoc
write your documentation here ...
166
CHAPTER 35. EUDOC - SOURCE DOCUMENTATION TOOL 35.4. ASSEMBLY FILE
!! CONTEXT : favorite . ex
@ [ hello |]
==== hello
< eucode >
include favorite . ex
public procedure hello ( sequence name )
</ eucode >
= Title
== Section
* bullet
* lists are
* easy to produce
|| tables || are |
| easy to produce | // with bold headers // |
167
CHAPTER 35. EUDOC - SOURCE DOCUMENTATION TOOL 35.6. DOCUMENTATION SOFTWARE
Title **
Section **
easy to produce
tables are
easy to produce with bold headers
-- euphoria code is colorized
for i =1 to 5 do
? i
end for
168
Chapter 36
Ed - Euphoria Editor
36.1 Introduction
The Euphoria download package includes a handy, text-mode editor, ed, thats written completely in Euphoria. Many
people find ed convenient for editing Euphoria programs and other files, but there is no requirement that you use it.
36.2 Summary
Usage:
1. ed filename
2. ed
After any error, just type ed, and youll be placed in the editor, at the line and column where the error was detected.
The error message will be at the top of your screen.
Euphoria-related files are displayed in color. Other text files are in mono. Youll know that you have misspelled
something when the color does not change as you expect. Keywords are blue. Names of routines that are built in to
the interpreter appear in magenta. Strings are green, comments are red, most other text is black. Balanced brackets
(on the same line) have the same color. You can change these colors as well as several other parameters of ed. See
user-modifiable parameters near the top of ed.ex.
The arrow keys move the cursor left, right, up or down. Most other characters are immediately inserted into the file.
In Windows, you can associate various types of files with ed.bat. You will then be put into ed when you double-click
on these types of files - e.g. .e, .pro, .doc etc. Main Euphoria files ending in .ex, .exd or .exw might better be
associated with eui.exe, euid.exe, or euiw.exe, respectively.
ed is a multi-file/multi-window text-based editor. Esc c will split your screen so you can view and edit up to 10 files
simultaneously, with cutting and pasting between them. You can also use multiple edit windows to view and edit different
parts of a single file.
169
CHAPTER 36. ED - EUPHORIA EDITOR 36.4. ESCAPE COMMANDS
Press and release the Esc key, then press one of the following keys:
170
CHAPTER 36. ED - EUPHORIA EDITOR 36.4. ESCAPE COMMANDS
172
CHAPTER 36. ED - EUPHORIA EDITOR 36.11. LINE TERMINATOR
173
Chapter 37
EuDis - Disassembling Euphoria code
37.1 Introduction
In the Euphoria source directory is a program named dis.ex, which can be used for parsing Euphoria code and outputting
detailed disassembly of the intermediate language (i.e., byte code) used by Euphoria, as well as the symbol table. The
purpose of this tool is for low level debugging, especially for developing Euphoria itself, or for understanding why certain
code performs the way it does.
It uses the actual Euphoria front end to parse your code. When Euphoria is installed, there should be a shell script
or batch file (depending on your operating system) called eudis or eudis.bat, respectively, that can be used to analyze
your code:
$ eudis myapp . ex
saved to [/ path / to / myapp . ex . dis ]
When run, eudis will say where its output was saved. The file name, including extension, is used as the base for its
output. By default, it outputs four files:
.dis The main disassembly file. This shows the IL code representation both raw and symbolically.
.sym The symbol table. This shows details for the entire symbol table for your code.
.line Line table information. Unless tracing is enabled, this will be blank.
174
CHAPTER 37. EUDIS - DISASSEMBLING EUPHORIA CODE 37.2. HTML OUTPUT
--dir <dir> Specify the output directory for the html files
Suppress dependencies. Will not generate file and routine dependency graphs.
--std show standard library information, by default this is not shown
-t parse the code as though it were being translated
175
Chapter 38
EuDist - Distributing Programs
38.1 Introduction
EuDist is a tool that makes distributing your program easier. Its designed to gather all of the Euphoria files that your
program uses and put them into a directory. This can also be useful for sending example code for bug reports.
176
Part VIII
API Reference
177
Chapter 39
Built-in Methods
178
Chapter 40
Command Line Handling
40.1 Constants
40.1.1 NO PARAMETER
This option switch does not have a parameter. See cmd parse
40.1.3 NO CASE
179
CHAPTER 40. COMMAND LINE HANDLING 40.1. CONSTANTS
40.1.5 MANDATORY
include std / cmdline . e
namespace cmdline
public constant MANDATORY
This option switch must be supplied on command line. See cmd parse
40.1.6 OPTIONAL
include std / cmdline . e
namespace cmdline
public constant OPTIONAL
This option switch does not have to be on command line. See cmd parse
40.1.7 ONCE
include std / cmdline . e
namespace cmdline
public constant ONCE
This option switch must only occur once on the command line. See cmd parse
40.1.8 MULTIPLE
include std / cmdline . e
namespace cmdline
public constant MULTIPLE
This option switch may occur multiple times on a command line. See cmd parse
40.1.9 HELP
include std / cmdline . e
namespace cmdline
public constant HELP
This option switch triggers the help display. See cmd parse
40.1.10 VERSIONING
include std / cmdline . e
namespace cmdline
public constant VERSIONING
This option switch sets the program version information. If this optionis chosen by the user cmd parse will display the
program version information and then end the program with a zero error code.
180
CHAPTER 40. COMMAND LINE HANDLING 40.1. CONSTANTS
40.1.13 NO VALIDATION
Do not cause an error for an invalid parameter after the first extra item has been found. This can be helpful for
processes such as the Interpreter itself that must deal with command line parameters that it is not meant to handle. At
expansions after the first extra are also disabled.
For instance:
eui -D TEST greet.ex -name John -greeting Bye -D TEST is meant for eui, but -name and -greeting options are
meant for greet.ex. See cmd parse
eui @euopts.txt greet.ex @hotmail.com here hotmail.com is not expanded into the command line but eu-
opts.txt is.
Only display the option list in show help. Do not display other information such as program name, options, etc... See
cmd parse
40.1.16 AT EXPANSION
Expand arguments that begin with @ into the command line. (default) For example, @filename will expand the
contents of file named filename as if the files contents were passed in on the command line. Arguments that come after
the first extra will not be expanded when NO VALIDATION AFTER FIRST EXTRA is specified.
181
CHAPTER 40. COMMAND LINE HANDLING 40.1. CONSTANTS
40.1.17 NO AT EXPANSION
include std / cmdline . e
namespace cmdline
public enum NO_AT_EXPANSION
Do not expand arguments that begin with @ into the command line. Normally @filename will expand the file names
contents as if the files contents were passed in on the command line. This option supresses this behavior.
Supply a message to display and pause just prior to abort() being called.
40.1.19 NO HELP
include std / cmdline . e
namespace cmdline
public enum NO_HELP
The number of times that the routine has been called by cmd parse for this option. See cmd parse
The options value as found on the command line. See cmd parse
182
CHAPTER 40. COMMAND LINE HANDLING 40.2. ROUTINES
The value 1 if the command line indicates that this option is to remove any earlier occurrences of it. See cmd parse
40.1.25 EXTRAS
The extra parameters on the cmd line, not associated with any specific option. See cmd parse
40.2 Routines
40.2.1 command line
A sequence, of strings, where each string is a word from the command-line that started your program.
Returns:
1. The path, to either the Euphoria executable, (eui, eui.exe, euid.exe euiw.exe) or to your bound executable file.
2. The next word, is either the name of your Euphoria main file, or (again) the path to your bound executable file.
3. Any extra words, typed by the user. You can use these words in your program.
There are as many entries as words, plus the two mentioned above.
The Euphoria interpreter itself does not use any command-line options. You are free to use any options for your own
program. It does have command line switches though.
The user can put quotes around a series of words to make them into a single argument.
If you convert your program into an executable file, either by binding it, or translating it to C, you will find that all
command-line arguments remain the same, except for the first two, even though your user no longer types eui on the
command-line (see examples below).
Example 1:
1 -- The user types : eui myprog myfile . dat 12345 " the end "
2
3 cmd = command_line ()
4
5 -- cmd will be :
6 {
7 " myprog " ,
8 " myfile . dat " ,
9 " 12345 " ,
10 " the end " }
183
CHAPTER 40. COMMAND LINE HANDLING 40.2. ROUTINES
Example 2:
1 -- Your program is bound with the name " myprog . exe "
2 -- and is stored in the directory c :\ myfiles
3 -- The user types : myprog myfile . dat 12345 " the end "
4
5 cmd = command_line ()
6
7 -- cmd will be :
8 {
9
See Also:
Retrieves the list of switches passed to the interpreter on the command line.
Returns:
Comments:
Example 1:
euiw -d helLo
-- will result in
-- option_switches () being {" - D " ," helLo "}
See Also:
184
CHAPTER 40. COMMAND LINE HANDLING 40.2. ROUTINES
Parameters:
1. opts : a sequence of options. See the cmd parse for details.
2. add help rid : an object. Either a routine id or a set of text strings. The default is -1 meaning that no additional
help text will be used.
3. cmds : a sequence of strings. By default this is the output from command line()
4. parse options : An option set of behavior modifiers. See the cmd parse for details.
Comments:
opts is identical to the one used by cmd parse
add help rid can be used to provide additional help text. By default, just the option switches and their descriptions
will be displayed. However you can provide additional text by either supplying a routine id of a procedure that accepts
no parameters; this procedure is expected to write text to the stdout device. Or you can supply one or more lines of
text that will be displayed.
Example 1:
1 -- in myfile . ex
2 constant description = {
3 " Creates a file containing an analysis of the weather . " ,
4 " The analysis includes temperature and rainfall data " ,
5 " for the past week . "
6 }
7
8 show_help ({
9 { " q " , " silent " , " Suppresses any output to console " , NO_PARAMETER , -1} ,
10 { " r " , 0 , " Sets how many lines the console should display " ,
11 { HAS_PARAMETER , " lines " } , -1}} , description )
Outputs:
myfile . ex options :
-q , -- silent Suppresses any output to console
-r lines Sets how many lines the console should display
185
CHAPTER 40. COMMAND LINE HANDLING 40.2. ROUTINES
Example 2:
1 -- in myfile . ex
2 constant description = {
3 " Creates a file containing an analysis of the weather . " ,
4 " The analysis includes temperature and rainfall data " ,
5 " for the past week . "
6 }
7 procedure sh ()
8 for i = 1 to length ( description ) do
9 printf (1 , " >> % s < <\ n " , { description [ i ]})
10 end for
11 end procedure
12
13 show_help ({
14 { " q " , " silent " , " Suppresses any output to console " , NO_PARAMETER , -1} ,
15 { " r " , 0 , " Sets how many lines the console should display " ,
16 { HAS_PARAMETER , " lines " } , -1}} , routine_id ( " sh " ))
Outputs:
myfile . ex options :
-q , -- silent Suppresses any output to console
-r lines Sets how many lines the console should display
Parse command line options, and optionally call procedures that relate to these options
Parameters:
1. opts : a sequence of records that define the various command line switches and options that are valid for the
application: See Comments: section for details
2. parse options : an optional list of special behavior modifiers: See Parse Options section for details
3. cmds : an optional sequence of command line arguments. If omitted the output from command line() is used.
Returns:
A map, containing the set of actual options used in cmds. The returned map has one special key, EXTRAS that are values
passed on the command line that are not part of any of the defined options. This is commonly used to get the list of files
entered on the command line. For instance, if the command line used was myprog -verbose file1.txt file2.txt
then the EXTRAS data value would be "file1.txt", "file2.txt".
When any command item begins with an @ symbol then it is assumed that it prefixes a file name. That file will then
be opened and its contents used to add to the command line, as if the file contents had actually been