0% found this document useful (1 vote)
2K views795 pages

Euphoria User Manual

Guide For The Euphoria Programing Language.

Uploaded by

Unknown020
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (1 vote)
2K views795 pages

Euphoria User Manual

Guide For The Euphoria Programing Language.

Uploaded by

Unknown020
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 795

Version 4.

User Manual
Published 2012-10-13 20:11 UTC
Contents

I Euphoria Programming Language v4.0 1


1 Quick Overview 2

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

3 Whats new in 4.0? 8


3.1 General Changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
3.2 Executable name changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
3.3 Language Enhancements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
3.4 Tool Additions / Enhancements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

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

8 Set Up the Euphoria Configuration File (eu.cfg) 21


8.1 Configuration file format . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
8.2 Config File Locations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22

ii
8.3 Config File Notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22

III Using Euphoria 23


9 Example Programs 24
9.1 Hello, World . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
9.2 Sorting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
9.3 What to Do? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26

10 Creating Euphoria programs 28


10.1 Running a Program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
10.2 Running under Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29

11 Editing a Program 30

12 Distributing a Program 31

13 Command line switches 32


13.1 Further notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33

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

19 Flow control statements 79


19.1 exit statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
19.2 break statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
19.3 continue statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
19.4 retry statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
19.5 with entry statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
19.6 goto statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
19.7 Header Labels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84

20 Short-Circuit Evaluation 85

21 Special Top-Level Statements 87


21.1 include statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
21.2 with / without . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89

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

23 Euphoria Internals 101


23.1 The Euphoria Data Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
23.2 The C Representations of a Euphoria Sequence and a Euphoria Atom . . . . . . . . . . . . . . . . . . . 102
23.3 The Euphoria Object Macros and Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
23.4 Type Value Functions and Macros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
23.5 Type Conversion Functions and Macros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
23.6 Creating Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
23.7 Object Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107

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

26 Euphoria To C Translator 119


26.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
26.2 C Compilers Supported . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
26.3 How to Run the Translator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
26.4 Command-Line Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
26.5 Dynamic Link Libraries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
26.6 Using Resource Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
26.7 Executable Size and Compression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
26.8 Interpreter vs. Translator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
26.9 Legal Restrictions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
26.10 Disclaimer: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
26.11 Frequently Asked Questions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
26.12 Common Problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126

27 Indirect routine calling 127


27.1 Indirect calling a routine coded in Euphoria . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
27.2 Calling Euphorias internals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129

28 Multitasking in Euphoria 130


28.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
28.2 Why Multitask? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
28.3 Types of Tasks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
28.4 A Small Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
28.5 Comparison with earlier multitasking schemes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
28.6 Comparison with multithreading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
28.7 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132

29 Euphoria Database System (EDS) 133


29.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
29.2 Structure of an EDS database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
29.3 How to access the data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
29.4 How does storage get recycled? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
29.5 Security / Multi-user Access . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
29.6 Scalability . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
29.7 EDS API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
29.8 Disclaimer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
29.9 Warning: Use the right file mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135

30 The User Defined Pre-Processor 136


30.1 A Quick Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
30.2 Pre-process Details . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
30.3 Command Line Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
30.4 DLL/Shared Library Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
30.5 Advanced Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140

31 Euphoria Trouble-Shooting Guide 142


31.1 Common Problems and Solutions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142

32 Platform Specific Issues 146


32.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146
32.2 The Discontinued DOS32 Platform . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
32.3 The WINDOWS Platform . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
32.4 The Unix Platforms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
32.5 Interfacing with C Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150

33 Performance Tips 154


33.1 General Tips . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
33.2 Measuring Performance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155
33.3 How to Speed-Up Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
33.4 Converting Multiplies to Adds in a Loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
33.5 Saving Results in Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
33.6 In-lining of Routine Calls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
33.7 Operations on Sequences . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
33.8 Some Special Case Optimizations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
33.9 Assignment with Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
33.10 Library / Built-In Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158
33.11 Searching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159
33.12 Sorting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159
33.13 Taking Advantage of Cache Memory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159
33.14 Using Machine Code and C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159
33.15 Using The Euphoria To C Translator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160

VII Included Tools 161


34 EuTEST - Unit Testing 162
34.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162
34.2 The eutest Program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162
34.3 The Unit Test Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
34.4 The Error Control Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
34.5 Test Coverage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164

35 EuDOC - Source Documentation Tool 166


35.1 Documentation tags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166
35.2 Generic documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166
35.3 Source documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166
35.4 Assembly file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
35.5 Creole markup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
35.6 Documentation software . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168

36 Ed - Euphoria Editor 169


36.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169
36.2 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169
36.3 Special Keys . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169
36.4 Escape Commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170
36.5 Recalling Previous Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172
36.6 Cutting and Pasting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172
36.7 Use of Tabs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172
36.8 Long Lines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172
36.9 Maximum File Size . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172
36.10 Non-text Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172
36.11 Line Terminator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173
36.12 Source Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173

37 EuDis - Disassembling Euphoria code 174


37.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174
37.2 HTML Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174

38 EuDist - Distributing Programs 176


38.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176
38.2 Command Line Switches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176

VIII API Reference 177


39 Built-in Methods 178

40 Command Line Handling 179


40.1 Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179
40.2 Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183

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

43 File System 225


43.1 Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225
43.2 Directory Handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226
43.3 File name parsing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 236
43.4 File Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 246
43.5 File Handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 247

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

45 Operating System Helpers 283


45.1 Operating System Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283
45.2 Environment. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 284
45.3 Interacting with the OS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288
45.4 Miscellaneous . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 290

46 Pipe Input/Output 291


46.1 Notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291
46.2 Accessor Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291
46.3 Opening/Closing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 292
46.4 Read/Write Process . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293

47 Pretty Printing 295


47.1 Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296
48 Multi-tasking 300
48.1 General Notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 300
48.2 Warning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 300
48.3 Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 300

49 Types - Extended 307


49.1 Predefined character sets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310
49.2 Support Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313
49.3 Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 315

50 Utilities 329
50.1 Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 329

51 Data type conversion 331


51.1 Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331

52 Input Routines 341


52.1 Error Status Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 341
52.2 Answer Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 341
52.3 Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 342

53 Searching 347
53.1 Equality . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 347
53.2 Finding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 349
53.3 Matching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 358

54 Sequence Manipulation 365


54.1 Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 365
54.2 Basic routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 366
54.3 Building sequences . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 374
54.4 Adding to sequences . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 376
54.5 Extracting, removing, replacing from/into a sequence . . . . . . . . . . . . . . . . . . . . . . . . . . . . 382
54.6 Changing the shape of a sequence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393

55 Serialization of Euphoria Objects 407


55.1 Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 407

56 Sorting 412
56.1 Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 412
56.2 Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 413

57 Locale Routines 419


57.1 Message translation functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 419
57.2 Time/Number Translation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 423
57.3 Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 426
57.4 Locale Name Translation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 429

58 Regular Expressions 432


58.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 432
58.2 General Use . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 432
58.3 Option Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 432
58.4 Error Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 436
58.5 Create/Destroy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 440
58.6 Utility Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 442
58.7 Match . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 443
58.8 Splitting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 448
58.9 Replacement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 449

59 Text Manipulation 452


59.1 Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 452

60 Wildcard Matching 467


60.1 Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 467

61 Base 64 Encoding/Decoding 469


61.1 Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 469

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

63 Math Constants 505


63.1 Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 505

64 Random Numbers 509

65 Statistics 517
65.1 Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 517

66 Euphoria Database (EDS) 535


66.1 Error Status Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 535
66.2 Lock Type Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 536
66.3 Error Code Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 537
66.4 Indexes for connection option structure. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 538
66.5 Database connection options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 538
66.6 Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 539
66.7 Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 539
66.8 Managing databases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 541
66.9 Managing tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 546
66.10 Managing Records . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 550

67 Prime Numbers 560


67.1 Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 560

68 Flags 563
68.1 Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 563

69 Hashing Algorithms 566


69.1 Type Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 566
69.2 Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 567

70 Map (hash table) 569


70.1 Operation codes for put . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 569
70.2 Types of Maps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 571
70.3 Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 571
70.4 Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 571
71 Stack 593
71.1 Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 593
71.2 Stack types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 593
71.3 Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 593
71.4 Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 593

72 Core Sockets 606


72.1 Error Information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 606
72.2 Socket Backend Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 612
72.3 Socket Type Euphoria Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 613
72.4 Socket Type Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 615
72.5 Select Accessor Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 616
72.6 Shutdown Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 617
72.7 Socket Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 618
72.8 Send Flags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 625
72.9 Server and Client sides . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 628
72.10 Client side only . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 633
72.11 Server side only . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 634
72.12 UDP only . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 635
72.13 Information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 636

73 Common Internet Routines 638


73.1 IP Address Handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 638
73.2 URL Parsing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 639

74 DNS 642
74.1 Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 642
74.2 General Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 647

75 HTTP Client 649


75.1 Error Codes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 649
75.2 Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 650
75.3 Get/Post Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 651

76 URL handling 653


76.1 Parsing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 653
76.2 URL Parse Accessor Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 653
76.3 URL encoding and decoding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 656

77 Dynamic Linking to external code 658


77.1 C Type Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 658
77.2 External Euphoria Type Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 661
77.3 Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 662
77.4 Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 662

78 Errors and Warnings 670


78.1 Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 670

79 Pseudo Memory 675

80 Machine Level Access 678


80.1 Safe Mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 678
80.2 Data Execute Mode and Data Execute Protection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 681
80.3 Type Sorted Function List . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 681
80.4 Memory Allocation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 682
80.5 Reading from Memory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 685
80.6 Writing to Memory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 691
80.7 Memory Manipulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 695
80.8 Calling Into Memory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 696
80.9 Allocating and Writing to memory: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 697
80.10 Memory Disposal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 699
80.11 Automatic Resource Management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 701
80.12 Types and Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 701

81 Indirect Routine Calling 704


81.1 Accessing Euphoria coded routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 704
81.2 Accessing Euphoria internals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 707

82 Memory Constants 709


82.1 Microsoft Windows Memory Protection Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 709
82.2 Standard Library Memory Protection Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 710
82.3 Error Code Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 711
82.4 video config sequence accessors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 712
82.5 Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 716

83 Graphics - Cross Platform 719


83.1 Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 719
83.2 Graphics Modes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 723

84 Graphics - Image Routines 724


84.1 Bitmap handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 724

85 Euphoria Information 726


85.1 Build Type Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 726
85.2 Numeric Version Information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 726
85.3 Compiled Platform Information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 726
85.4 String Version Information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 728
85.5 Copyright Information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 730
85.6 Timing Information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 731
85.7 Configure Information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 731

86 Keyword Data 733


86.1 Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 733

87 Syntax Coloring 734


87.1 Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 734

88 Euphoria Source Tokenizer 736


88.1 tokenize return sequence key . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 736
88.2 Tokens . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 736
88.3 T NUMBER formats and T types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 742
88.4 ET error codes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 744
88.5 get/set options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 746
88.6 Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 746
88.7 Debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 747

89 Unit Testing Framework 748


89.1 Background . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 748
89.2 Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 749
89.3 Setup Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 749
89.4 Reporting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 751
89.5 Tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 751

90 Windows Message Box 755


90.1 Style Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 755
90.2 Return Value Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 759
90.3 Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 760

91 Windows Sound 761

92 Unsupported Features 763


92.1 UTF Encoded String Literals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 763

IX Release Notes 765


93 Version 4.0.5 October 19, 2012 766
93.1 Bug Fixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 766
93.2 Enhancements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 766

94 Version 4.0.4 April 4, 2012 767


94.1 Bug Fixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 767
94.2 Enhancements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 768

95 Version 4.0.3 June 23, 2011 769


95.1 Bug Fixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 769
95.2 Enhancements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 769

96 Version 4.0.2 April 5, 2011 770


96.1 Bug Fixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 770
96.2 New Functionality . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 770

97 Version 4.0.1 March 29, 2011 771


97.1 Bug Fixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 771
97.2 Enhancements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 772

98 Version 4.0.0 December 22, 2010 773


98.1 Deprecation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 773
98.2 Possible Breaking Changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 773
98.3 Removed . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 773
98.4 Bug Fixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 773
98.5 Enhancements/Changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 774

99 Version 4.0.0 Release Candidate 2 December 8, 2010 775


99.1 Deprecation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 775
99.2 Removed . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 775
99.3 Bug Fixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 775
99.4 Enhancements/Changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 778

100Version 4.0.0 Release Candidate 1 November 8, 2010 780


100.1 Contributors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 780
100.2 Bug Fixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 781
100.3 Changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 781
100.4 New Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 781
100.5 New Features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 781

xii
Part I

Euphoria Programming Language v4.0

1
Chapter 1
Quick Overview

Welcome to the Euphoria programming language!


Euphoria is a programming language with the following advantages over conventional languages:
Euphoric
A remarkably simple, flexible, powerful language definition that is easy to learn and use.
Dynamic
Variables grow or shrink without the programmer having to worry about allocating and freeing chunks of memory.
Objects of any size can be assigned to an element of a Euphoria sequence (array).
Fast
A high-performance, state-of-the-art interpreter thats significantly faster than conventional interpreters such as Perl
and Python.
Compiles
An optimizing Euphoria To C Translator, that can boost your speed even further, often by a factor of 2x to 5x versus
the already-fast interpreter.
Safe
Extensive run-time checking for: out-of-bounds subscripts, uninitialized variables, bad parameter values for library
routines, illegal value assigned to a variable and many more. There are no mysterious machine exceptions--you
will always get a full English description of any problem that occurs with your program at run-time, along with a
call-stack trace-back and a dump of all of your variable values. Programs can be debugged quickly, easily and more
thoroughly.
High level
Features of the underlying hardware are completely hidden. Programs are not aware of word-lengths, underlying
bit-level representation of values, byte-order etc.
Debugger
A full-screen source debugger and an execution profiler are included.
Editor
A full-screen, multi-file editor is also included. On a color monitor, the editor displays Euphoria programs in multiple
colors, to highlight comments, reserved words, built-in functions, strings, and level of nesting of brackets. It optionally
performs auto-completion of statements, saving you typing effort and reducing syntax errors. This editor is written
in Euphoria, and the source code is provided to you without restrictions. You are free to modify it, add features,
and redistribute it as you wish.
Multi-platform
Euphoria programs run under Windows, Linux, OS/X, FreeBSD, NetBSD, OpenBSD and can be easily ported to
any platform supporting GCC.

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.

1 include std / console . e


2 sequence original_list
3

4 function merge_sort ( sequence x )


5 -- put x into ascending order using a recursive merge sort
6 integer n , mid
7 sequence merged , a , b
8

9 n = length ( x )
10 if n = 0 or n = 1 then
11 return x -- trivial case
12 end if
13

14 mid = floor ( n /2)


15 a = merge_sort ( x [1.. mid ]) -- sort first half of x
16 b = merge_sort ( x [ mid +1.. n ]) -- sort second half of x
17

18 -- merge the two sorted halves into one


19 merged = {}
20 while length ( a ) > 0 and length ( b ) > 0 do
21 if compare ( a [1] , b [1]) < 0 then
22 merged = append ( merged , a [1])
23 a = a [2.. length ( a )]
24 else
25 merged = append ( merged , b [1])
26 b = b [2.. length ( b )]
27 end if
28 end while
29 return merged & a & b -- merged data plus leftovers
30 end function
31

32 procedure print_sorted_list ()
33 -- generate sorted_list from original_list
34 sequence sorted_list
35

36 original_list = {19 , 10 , 23 , 41 , 84 , 55 , 98 , 67 , 76 , 32}


37 sorted_list = merge_sort ( original_list )
38 for i = 1 to length ( sorted_list ) do
39 display ( " Number [] was at position [:2] , now at [:2] " ,
40 { sorted_list [ i ] , find ( sorted_list [ i ] , original_list ) , i }
41 )
42 end for
43 end procedure
44

45 prin t_sort ed_list () -- this command starts the program

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

2.1 Yet Another Programming Language?


Euphoria is a very high-level programming language. It is unique among a crowd of conventional languages.

2.2 Euphoria delivers the expected features of a modern language


Open source
Free for personal and commercial use
Produces royalty-free, stand-alone, programs
Multi-platform -- Windows, OS X, Linux, FreeBSD, OpenBSD, NetBSD, ...
Provides a choice of multi-platform GUI toolkits: IUP, GTK, wxWindows
Syntax colored profiling, debugging and tracing of code
Dynamic memory allocation and efficient garbage collection
Interfacing to existing C libraries and databases
Well-documented, lots of example source-code, and an enthusiastic forum
Edit and run convenience

2.3 Euphoria is unique


What makes Euphoria unique is a design that uses just two basic data-types -- atom and sequence, and two helper
data-types -- object and integer.
An atom is single numeric value (either an integer or floating point)
A sequence is a list of zero or more objects.
An object is a variant type in that it can hold an atom or a sequence.
An integer is just a special form of atom that can only hold integers. You can use the integer type for a performance
advantage in situations where floating point values are not required.
What follows from this design are some advantages over conventional languages:

4
CHAPTER 2. INTRODUCTION
2.4. EUPHORIA HAS QUALITIES THAT GO BEYOND THE ELEGANCE OF SEQUENCES

The language syntax is smaller -- and thus easier to learn

The language syntax is consistent -- and thus easier to program

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

It supports both static data typing and dynamic data typing.

2.4 Euphoria has qualities that go beyond the elegance of sequences


Euphoria programs are considerably faster than conventional interpreted languages -- Euphoria makes a better
website server

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

Euphoria has a coherent design -- Euphoria programmers enjoy programming in Euphoria

2.5 As a first programming language


Easy to learn, easy to program

No limits as to what you can program

Euphoria programming skills will enhance learning other languages

2.6 As an extension to languages you already know


A fast, flexible, and powerful language

Euphoria, the language you will prefer to program in

2.7 But, my favorite language is ...


You will find that Euphoria programmers are also knowledgeable in other languages. I find that the more tools you
have (saws and hammers, or programming languages) the richer you are. Picking the correct tool is part of the art of
programming. It will remain true that some people can program better in their favorite language rather than an arguably
superior language.
Give Euphoria a try, and discover why it has enthusiastic supporters.

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.

2.10 Conventions used in the manual


Euphoria has multiple interpreters, the main one being eui.

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

2.11 Discover Euphoria


For more information, visit OpenEuphoria.org, and be sure to join the active discussion forum.

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.

3.1 General Changes


New manual and documentation system

New logo

Switched to using our own ticket system

Switched to using our own self hosted Mercurial SCM system

3.2 Executable name changes


Old New Description
ex and exwc eui Euphoria Interpreter
ec and ecw euc Euphoria to C Translator
bind.bat and bind eubind Euphoria Binder
shroud.bat and shroud eushrouder Euphoria Shrouder

3.3 Language Enhancements


Conditional compilation using the ifdef statement.

Raw strings, which can include multilined text.

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" ... "

Function results can now be ignored.

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.

Enumerated values/types (enum, enum type)

Built-in eu: namespace

Declare variable anywhere, not just at the top of a method.

Scoped variables (declared inside an if for example)

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.

Additional loop constructs ...

loop/until
You can label a loop
while X with entry
exit, continue, retry. All with an optional "label"
goto

Additional conditional constructs

switch statement with or without fallthru


You can label an if or switch
break keyword allows exiting from if / switch blocks

Default/optional parameters for routines

Additional scope modifiers

export
public (public include)
override

Built in sockets

Built in Regular Expressions

Resource clean up that can be triggered manually, or when an objects reference count goes to zero

Automatic inlining of small routines, with / without inline

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

3.4 Tool Additions / Enhancements


General
User Defined Preprocessor
Configuration system (eu.cfg)
Version display for all tools

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

EuDist - Distributing Programs


EuDOC - Source Documentation Tool
EuTEST - Unit Testing

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.

Copyright ( c ) 2007 -2011 by OpenEuphoria Group


Copyright ( c ) 1993 -2006 Rapid Deployment Software ( RDS )

Permission is hereby granted , free of charge , to any person obtaining a copy


of this software and associated documentation files ( the " Software ") ,
to deal in the Software without restriction , including without limitation
the rights to use , copy , modify , merge , publish , distribute ,
sublicense , and / or sell copies of the Software , and to permit persons
to whom the Software is furnished to do so .

THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY


KIND , EXPRESS OR IMPLIED , INCLUDING BUT NOT LIMITED TO
THE WARRANTIES OF MERCHANTABILITY , FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE AUTHORS
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR
OTHER LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR
OTHERWISE , ARISING FROM , OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE .

The copyright holders request , but do not require , that you :

1. Acknowledge RDS and others who contributed to this software .


2. Provide a link to www . RapidEuphoria . com , if possible , from your Web site .

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.

5.1 Current Authors


Jim Brown

Tom Ciplijauskas

Jeremy Cowgar

C. K. Lester

Matthew Lewis

Derek Parnell

Shawn Pringle

5.2 Past Authors


Robert Craig

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

Dave Smith - Graphics


Kathy Smith
Randy Sugianto

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.

6.1.1 Possible problems ...


On Windows XP/2000, be careful that your PATH and EUDIR do not conflict with autoexec.nt, which can also be
used to set environment variables.

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

6.1.2 How to manually modify the environment in Windows


Your EUPHORIA installation directory by default will be C:\Euphoria. It is possible to install to %PROGRAMFILES%\Euphoria,
or anywhere you wish. Careful when using the %ProgramFiles% special location (C:\Program Files on most systems in
English). The %ProgramFiles% directory invariably contains spaces by default. It is a good idea to use the short 8.3
version of the name, or surround with double quotes. Ofcourse, youll just have to substitute your real installation directory
for the C:\EUPHORIA examples below.

How to manually modify the environment in Windows (Windows NT/2000/XP)


On Windows XP select: Start Menu -> Control Panel -> Performance &Maintenance -> System -> Advanced then
click the Environment Variables button. Click the top New... button then enter EUDIR as the Variable Name and
c:\euphoria (or whatever is correct) for the value, then click OK. Find PATH in the list of your variables, select it, then
click Edit.... Add ;c:\euphoria\bin at the end and click OK.
On Windows Vista, Youll find the environment variables available at Start Menu -> Control Panel -> System and
Maintenance -> System -> Advanced system settings -> Environment Variables (button)
Other versions of Windows will have the environment variables somewhere in the control panel.

How to manually modify the environment in Windows (ME/98/95/3.1)


1. In the file c:\autoexec.bat add C:\EUPHORIA\BIN to the list of directories in your PATH command. You might
use the MS-DOS Edit command, Windows Notepad or any other text editor to do this.

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.

2. In the same autoexec.bat file add a new line:


SET EUDIR=C:\EUPHORIA
The EUDIR environment variable indicates the full path to the main Euphoria directory.

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.

More on editing environment variables


set EUDIR to the location of your Euphoria installation directory.

In PATH you need to include %EUDIR%\BIN.

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.

6.1.3 Modifying the Registry


Updating the environment is not enough, your old installation will still be called when you open a Euphoria program in
explorer or invoke the Euphoria program on the command line without typing in the interpreter (eui euiw). Do not type
in the single quotes.
You can set these in regedit (replace C:\EUPHORIA with your Euphoria installation directory):

16
CHAPTER 6. INSTALLATION 6.2. LINUX AND FREEBSD

HKEY _CLASS ES_ROOT \. exw \( Default ) = > EUWinApp


HKEY _CLASS ES_ROOT \ EuWinApp \( Default ) = > Euphoria Windows App
HKEY _CLASS ES_ROOT \ EUWinApp \ shell \ open \ command \( Default ) = > C :\ EUPHORIA \ BIN \ euiw . exe "%1"
HKEY _CLASS ES_ROOT \ EUWinApp \ shell \ translate \ command \( Default ) = > C :\ EUPHORIA \ BIN \ euc . exe "%1"

HKEY _CLASS ES_ROOT \. ex \( Default ) = > EUConsoleApp


HKEY _CLASS ES_ROOT \ EUConsoleApp \( Default ) = > Euphoria Console App
HKEY _CLASS ES_ROOT \ EUConsoleApp \ shell \ open \ command \( Default ) = > C :\ EUPHORIA \ BIN \ eui . exe "%1"
HKEY _CLASS ES_ROOT \ EUConsoleApp \ shell \ translate \ command \( Default ) = > C :\ EUPHORIA \ BIN \ euc . exe - con

HKEY _CLASS ES_ROOT \. e \( Default ) = > EUInc


HKEY _CLASS ES_ROOT \ EUInc \( Default ) = > Euphoria Include File
HKEY _CLASS ES_ROOT \. ew \( Default ) = > EUInc

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

6.2 Linux and FreeBSD


Euphoria may be installed using either a Unix archive ( .tar.gz or .tar.bz2 ) or, a distribution specific package, if
available.
http://openeuphoria.org/wiki/view/DownloadEuphoria.wc
The Unix tarball Archive is laid out similarly to the Windows directory structure. This may be convenient if working
cross-platform between Windows and Unix. The files at SourceForge are also in this form, making it convenient if you
wish to use updates directly from the SVN depository.
To install this version you must manually unarchive the tarball. Then copy the files to a suitable directory.
Youll need to manually edit:
/etc/profile so the PATH contains
euphoria/bin, and either create
an eu.cfg file or
set up EUDIR and EUINC. See the include statement.
The Packaged version installs Euphoria in a more Unix-like way, putting the executables into
/usr/bin,
/usr/share/euphoria and
/usr/share/doc/euphoria.
Man pages for eui, euc, eub, shroud and bind are also installed.
It will also create /etc/euphoria/eu.cfg, which will point to the standard euphoria include directory in /usr/
share/euphoria/include.
Other Unix based installations can be compiled from Source Releases.

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.

8.1 Configuration file format


The configuration file is a text file. Each line in the file is either a command line switch, a section header, an include path
or a comment.
Comments are lines that begin with a double dash "--". Everything on the line is ignored.
A section header is a name enclosed in square brackets. eg. [interpret].
There are a number of predefined sections.
The lines in a section are only added to the command line switches if they apply to the mode that Euphoria is
running in.
windows Applies to Windows platform only.
unix Applies to any Unix platform only.
interpret Applies to the interpreter running in any platform.
translate Applies to the translator running in any platform.
bind Applies to the binder running in any platform.
interpret:windows Applies to the interpreter when running under Windows only.
interpret:unix Applies to the interpreter when running under Unix only.
translate:windows Applies to the translator when running under Windows only.
translate:unix Applies to the translator when running under Unix only.
bind:windows Applies to the binder when running under Windows only.
bind:unix Applies to the binder when running under Unix only.
all Applies to all running modes.
All configuration lines before the first section header are assumed to be the [all] section.
You can have any number of section headers, but only the predefined ones are used. All lines in other sections
are treated as comments.
A command line switch is a line that begins with a single dash. The entire line is added to the actual command line
as if it was originally there.
An include path is any other line that is not one of the above. The string -I is prepended to the line and then it is
added to the command line.

21
CHAPTER 8. SET UP THE EUPHORIA CONFIGURATION FILE (EU.CFG) 8.2. CONFIG FILE LOCATIONS

8.2 Config File Locations


When Euphoria starts up, it looks for configuration files in the following order:
For Windows systems
1. %ALLUSERSPROFILE%\euphoria\eu.cfg
2. %APPDATA%\euphoria\eu.cfg
3. %EUDIR%\eu.cfg
4. %HOMEDRIVE%\%HOMEPATH%\eu.cfg
5. From where ever the executable is run from <exepath>/eu.cfg
6. Current working directory - ./eu.cfg
7. Command line -C switches

For Unix systems


1. /etc/euphoria/eu.cfg
2. $EUDIR/eu.cfg
3. $HOME/.eu.cfg
4. From where ever the executable is run from <exepath>/eu.cfg
5. Current working directory - ./eu.cfg
6. Command line -C switches

8.3 Config File Notes


Euphoria processes every configuration file found, and in the order described above. This means that settings specified
in earlier configuration files may be overridden by subsequent configuration files. For example, a configuration file
in the current directory will override the same settings in a configuration file in the executables directory.
If a configuration file contains a -C switch, the new configuration file specified on that switch is processed before
subsequent lines in the old file.

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

9.1 Hello, World


The mandatory Hello World program is a one-liner in Euphoria.
puts (1 , " Hello , World \ n " )

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

4 function merge_sort ( sequence x )


5 -- put x into ascending order using a recursive merge sort
6 integer n , mid
7 sequence merged , a , b
8

9 n = length ( x )
10 if n = 0 or n = 1 then
11 return x -- trivial case
12 end if
13

14 mid = floor ( n /2)


15 a = merge_sort ( x [1.. mid ]) -- sort first half of x
16 b = merge_sort ( x [ mid +1.. n ]) -- sort second half of x
17

18 -- merge the two sorted halves into one


19 merged = {}
20 while length ( a ) > 0 and length ( b ) > 0 do
21 if compare ( a [1] , b [1]) < 0 then
22 merged = append ( merged , a [1])
23 a = a [2.. length ( a )]
24 else

24
CHAPTER 9. EXAMPLE PROGRAMS 9.2. SORTING

25 merged = append ( merged , b [1])


26 b = b [2.. length ( b )]
27 end if
28 end while
29 return merged & a & b -- merged data plus leftovers
30 end function
31

32 procedure print_sorted_list ()
33 -- generate sorted_list from original_list
34 sequence sorted_list
35

36 original_list = {19 , 10 , 23 , 41 , 84 , 55 , 98 , 67 , 76 , 32}


37 sorted_list = merge_sort ( original_list )
38 for i = 1 to length ( sorted_list ) do
39 display ( " Number [] was at position [:2] , now at [:2] " ,
40 { sorted_list [ i ] , find ( sorted_list [ i ] , original_list ) , i }
41 )
42 end for
43 end procedure
44

45 prin t_sort ed_list () -- this command starts the program

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.

sequence original list


This declares a variable that is not public but is accessible from anywhere in this file. The datatype for the variable
is a sequence, which is a variable-length array, and whose symbol name is original list.

function merge sort(sequence x) ... end function


This declares and defines a function routine. Functions return values when called. This function must be passed a
single parameter when called - a sequence.

procedure print sorted list() ... end procedure


This declares and defines a procedure routine. Procedures never return values when called. This procedure must
not be passed any parameters when called.

print sorted list()


This calls the routine called print sorted list.

The output from the program will be:


Number 10 was at position 2 , now at 1
Number 19 was at position 1 , now at 2
Number 23 was at position 3 , now at 3
Number 32 was at position 10 , now at 4
Number 41 was at position 4 , now at 5
Number 55 was at position 6 , now at 6
Number 67 was at position 8 , now at 7
Number 76 was at position 9 , now at 8
Number 84 was at position 5 , now at 9
Number 98 was at position 7 , now at 10

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.

9.3 What to Do?


Now that you have installed Euphoria, here are some things you can try:

9.3.1 Run the Demo Programs


Run each of the demo programs in the demo directory. You just type eui <program name>. An example of running the
demos in a console
eui buzz

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.2 Edit Sample Files


Use the Euphoria editor, ed, to edit a Euphoria file. Notice the use of colors. You can adjust these colors along with
the cursor size and many other user-modifiable parameters by editing constant declarations in ed.ex. Use Esc q to
quit the editor or Esc h for help. There are several, even better, Euphoria-oriented editors in The Archive. If you use a
more sophisticated text editor, many have a highlighter file for Euphoria. You will find it either on the Archive or on the
community page for that editor. Check the wiki for more information about Euphoria editors.

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.

9.3.4 Read the Manual


Read the manual in html\index.html by double-clicking it. If you have a specific question, type at the console:
guru word

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.

9.3.5 Visit the EuForum


Euphoria Discussion Forum

9.3.6 Trace a Demo


Try running a Euphoria program with tracing turned on. Add:
with trace
trace (1)

at the beginning of any Euphoria source file.

26
CHAPTER 9. EXAMPLE PROGRAMS 9.3. WHAT TO DO?

9.3.7 Run the Tutorial Programs


Run some of the tutorial programs in euphoria\tutorial.

9.3.8 Modify the Tutorial Programs


Try modifying some of the demo programs.
First some simple modifications (takes less than a minute):

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.

9.3.9 Write Your Own


Try writing your own program in Euphoria. A program can be as simple as:
? 2+2

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.

10.1 Running a Program


To run a Euphoria program you type the name of the interpreter followed by the filename of the program you want to run.
Such as:
eui exampleex

What you just typed is known as the command-line.


Depending on the platform you are using the interpreter could be called:
Executable Purpose
eui General interpreter on Windows and Unix variants
euiw Console-less Windows interpreter
The command-line may contain extra information. Following your program filename you may add extra words (known
as arguments) that can used in your program to customize its behavior. These arguments are read within your program
by the built-in function command line().
Optionally, you may also use command line switches that are typed between the interpreter name and the program
name. Command line switches customize how the interpreter itself behaves.
Unlike many other compilers and interpreters, there is no obligation for any special command-line options for eui or
euiw. Only the name of you Euphoria file is expected, and if you dont supply it, Euphoria will display all the command
line options available.
Euphoria doesnt care about your choice of file extensions. By convention, however, console-based applications have
an extension of .ex, GUI-based applications have an extension of .exw and include files have an extension of .e. Note
that a GUI application is not necessarily a Windows program. A GUI application can exist on Linux, OS X, FreeBSD,
etc...
You can redirect standard input and standard output when you run a Euphoria program, for example:
eui filesortex < rawtxt > sortedtxt

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 ()

Then if you make your file executable:


chmod + x fooex

You can just type:


fooex

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.

10.2 Running under Windows


You can run Euphoria programs directly from the Windows environment, or from a console shell that you have opened
from Windows. By associating .ex files with eui.exe and .exw files with euiw.exe. You will then be able to double
click a Euphoria source file to run it. The installer will perform this operation for you, if you wish.

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

Euphoria provides you with 4 distinct ways of distributing a program.


source-code, with the Euphoria interpreter

shroud into .il code, with Euphoria backend


bind into a Euphoria executable
translate into a C-compiled executable

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.

-COM dir (translator)

Specifies the include directory for the C compiler once EUPHORIA code is translated.

This should be set such that dir/include/euphoria.h exists.

-COPYRIGHT (all)
Displays the copyright banner for euphoria.

-C config file (all)


Specifies either a file name or the path for where the default file called eu.cfg exists. The configuration file which
holds a set of additional command line switches. See Also Configuration file format

-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

-DLL, -SO (translator)


Compiles and links the translated euphoria code into a DLL, SO or DYLIB (depending on the platform).

-EUDIR dir (all)


This overrides the environment variable EUDIR.

-H, (all)
Displays the list of available command line options.

-I include path (all)


Specifies an extra include path.

-LIB file (translator)


Specifies the run-time library to use when translating euphoria programs.

-PLAT word (translator)


Specify the target platform for translation. This allows euphoria code to be translated for any supported platform from
any other supported platform. Supported platforms: FREEBSD, LINUX, NETBSD, OPENBSD, OSX, WINDOWS

-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.

-W warning name (all)


Resets, or adds to, the current list of warnings that may be emitted. The list of known names is to be found in the
subsection with/without warning. A name should appear without quotes. If the warning name begins with a plus
symbol +, this warning is added to the current set of warnings checked for, otherwise the first usage resets the list
to the warning being introduced, and each subsequent -W warning name adds to the list.

-WF file name (all)


Sets the file where the warnings should go instead of the standard error. Warnings are written to that file regardless
of whether or not there are errors in the source. If there are no warnings, the -wf file is not created. If the -wf file
cannot be created, a suitable message is displayed on STDERR and written to ex.err.

-X;
Resets, or adds to, the list of warnings that will not be issued. This is opposite of the -W switch.

The case of the switches is ignored, so -I and -i are equivalent.

13.1 Further notes


Included files are searched for in all included paths, in the following order:
1. The current path
2. Paths specified in a -I command line switch, which can also come from any configuration files found.
3. Paths listed in the EUINC environment variable, in the order in which they appear
4. Paths listed in the EUDIR environment variable, in the order in which they appear
5. The interpreters path

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

0 d101 -- > decimal 101


0 x101 -- > decimal 257

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

3 atom salary = 56 _110 .66 -- Set salary to the value 56110.66


4

5 integer defflags = #0323 _F3CD


6

7 object phone = 61 _3_5536_7733


8

9 integer bits = 0 b11_00010_1

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 }

equal ( seq_1 , seq_2 ) -- TRUE

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.

14.1.2 Character Strings and Individual Characters


A character string is just a sequence of characters. It may be entered in a number of ways ...

Using double-quotes e.g.

" ABCDEFG "

Using raw string notation e.g.

-- Using back - quotes


ABCDEFG

or
-- Using three double - quotes
" " " ABCDEFG " " "

Using binary strings e.g.

b " 1001 00110110 0110 _0111 1 _0101_1010 " -- == > {#9 ,#36 ,#67 ,#15 A }

Using hexadecimal byte strings e.g.

x " 65 66 67 AE " -- == > {#65 ,#66 ,#67 ,# AE }

When you put too many hex characters together they are split up appropriately for you:
x " 656667 AE " -- 8 - bit == > {#65 ,#66 ,#67 ,# AE }

The rules for double-quote strings are:

1. They begin and end with a double-quote character

2. They cannot contain a double-quote

3. They must be only on a single line

4. They cannot contain the TAB character

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 "

Which, when displayed should look like ...


Bill said
" This is a back - slash \ character ".

The rules for raw strings are:


1. Enclose with three double-quotes """...""" or back-quote. ...
2. The resulting string will never have any carriage-return characters in it.
3. If the resulting string begins with a new-line, the initial new-line is removed and any trailing new-line is also removed.
4. A special form is used to automatically remove leading whitespace from the source code text. You might code this
form to align the source text for ease of reading. If the first line after the raw string start token begins with one
or more underscore characters, the number of consecutive underscores signifies the maximum number of whitespace
characters that will be removed from each line of the raw string text. The underscores represent an assumed left
margin width. Note, these leading underscores do not form part of the raw string text.
e.g.
1 -- No leading underscores and no leading whitespace
2

3 Bill said

Which, when displayed should look like ...


Bill said
" This is a back - slash \ character ".

1 -- No leading underscores and but leading whitespace


2

3 Bill said

Which, when displayed should look like ...


Bill said
" This is a back - slash \ character ".

1 -- Leading underscores and leading whitespace


2

3 _____Bill said

Which, when displayed should look like ...


Bill said
" This is a back - slash \ character ".

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 .

The rules for binary strings are...

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.

3. an underscore is simply ignored, as if it was never there. It is used to aid readability.

4. each set of contiguous binary digits represents a single sequence element

5. they can span multiple lines

6. The non-digits are treated as punctuation and used to delimit individual values.

b " 1 10 11 _0100 01010110 _01111000 " == {0 x01 , 0 x02 , 0 x34 , 0 x5678 }

The rules for hexadecimal strings are:

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.

3. An underscore is simply ignored, as if it was never there. It is used to aid readability.

4. Each pair of contiguous hex digits represents a single sequence element with a value from 0 to 255

5. They can span multiple lines

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.

B -- equivalent to the atom 66 - the ASCII code for B


"B" -- equivalent to the sequence {66}

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.1.3 Escaped Characters


Special characters may be entered using a back-slash:
Code Meaning
\n newline
\r carriage return
\t tab
\\ backslash
\ double quote
\ single quote
\0 null
\e escape
\E escape
\b/d..d/ A binary coded value, the \b is followed by 1 or more
binary digits.
Inside strings, use the space character to delimit or end a
binary value.
\x/hh/ A 2-hex-digit value, e.g. \x5F ==> 95
\u/hhhh/ A 4-hex-digit value, e.g. \u2A7C ==> 10876
\U/hhhhhhhh/ An 8-hex-digit value, e.g. \U8123FEDC ==>
2166619868
For example, "Hello, World!\n", or \\. The Euphoria editor displays character strings in green.
Note that you can use the underscore character inside the \b, \x, \u, and \U values to aid readability, e.g.
"\U8123 FEDC" ==> 2166619868

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

Examples of invalid identifiers:


0n -- must not start with a digit

Shell Sort -- Cannot have spaces in identifiers .


quick - sort -- must only consist of letters , digits or underscore .

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.

-- This is a comment which extends to the end of this line only .

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.

extends over a number


of text lines .
*/

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.

/ home / rob / euphoria / bin / eui

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.

14.4.1 Relational Operators


The relational operators < > <= >= = != each produce a 1 (true) or a 0 (false) result.

1 8.8 < 8.7 -- 8.8 less than 8.7 ( false )


2 -4.4 > -4.3 -- -4.4 greater than -4.3 ( false )
3 8 <= 7 -- 8 less than or equal to 7 ( false )
4 4 >= 4 -- 4 greater than or equal to 4 ( true )
5 1 = 10 -- 1 equal to 10 ( false )
6 8.7 != 8.8 -- 8.7 not equal to 8.8 ( true )

As we will soon see you can also apply these operators to sequences.

41
CHAPTER 14. DEFINITION 14.4. EXPRESSIONS

14.4.2 Logical Operators


The logical operators and, or, xor, and not are used to determine the truth of an expression. e.g.
1 1 and 1 -- 1 ( true )
2 1 and 0 -- 0 ( false )
3 0 and 1 -- 0 ( false )
4 0 and 0 -- 0 ( false )
5

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 )

These operators can also be applied to sequences. See below.


In some cases short circuit evaluation will be used for expressions containing and or or. Specifically, short circuiting
applies inside decision making expressions. These are found in the if statement, while statement and the loop until
statement. More on this later.

14.4.3 Arithmetic Operators


The usual arithmetic operators are available: add, subtract, multiply, divide, unary minus, unary plus.
1 3.5 + 3 -- 6.5
2 3 - 5 -- -2
3 6 * 2 -- 12
4 7 / 2 -- 3.5
5 -8.1 -- -8.1
6 +8 -- +8

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.

14.4.4 Operations on Sequences


All of the relational, logical and arithmetic operators described above, as well as the math routines described in Language
Reference, can be applied to sequences as well as to single numbers (atoms).

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

16 -- note that the first = is assignment , and the


17 -- second = is a relational operator that tests
18 -- equality

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

You can use compare() for other comparisons as well:


if compare ( " APPLE " , " ORANGE " ) < 0 then -- CORRECT
-- enter here if " APPLE " is less than " ORANGE " ( TRUE )

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

14.4.5 Subscripting of Sequences


A single element of a sequence may be selected by giving the element number in square brackets. Element numbers start
at 1. Non-integer subscripts are rounded down to an integer.
For example, if x contains 5, 7.2, 9, 0.5, 13 then x[2] is 7.2. Suppose we assign something different to x[2]:
x [2] = {11 ,22 ,33}

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 " }

-- s [3] is " Euphoria "


-- s [3][1] is E

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

10 -- employees [2][ SALARY ] would be 57000.

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 )]

A short-hand for this is:


s[$]

Similarly,
s [ length ( s ) -1]

can be simplified to:


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

Compare that with the equivalent:


longname [ length ( longname )][ length ( longname [ length ( longname )])]

Subscripting and function side-effects:


In an assignment statement, with left-hand-side subscripts:
lhs_var [ lhs_expr1 ][ lhs_expr2 ]... = rhs_expr

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

14.4.6 Slicing of Sequences


A sequence of consecutive elements may be selected by giving the starting and ending element numbers. For example if
x is 1, 1, 2, 2, 2, 1, 1, 1 then x[3..5] is the sequence 2, 2, 2. x[3..3] is the sequence 2. x[3..2] is also
allowed. It evaluates to the zero length sequence . If y has the value: "fred", "george", "mary" then y[1..2] is
"fred", "george".
We can also use slices for overwriting portions of variables. After x[3..5] = 9, 9, 9 x would be 1, 1, 9, 9,
9, 1, 1, 1. We could also have said x[3..5] = 9 with the same effect. Suppose y is 0, "Euphoria", 1, 1. Then
y[2][1..4] is "Euph". If we say y[2][1..4] = "ABCD" then y will become 0, "ABCDoria", 1, 1.
In general, a variable name can be followed by 0 or more subscripts, followed in turn by 0 or 1 slices. Only variables
may be subscripted or sliced, not expressions.
We need to be a bit more precise in defining the rules for empty slices. Consider a slice s[i..j] where s is of length
n. A slice from i to j, where j = i - 1 and i >= 1 produces the empty sequence, even if i = n + 1. Thus 1..0 and
n + 1..n and everything in between are legal (empty) slices. Empty slices are quite useful in many algorithms. A slice
from i to j where j < i - 1 is illegal , i.e. reverse slices such as s[5..3] are not allowed.
We can also use the $ shorthand with slices, e.g.
s [2.. $ ]
s [5.. $ -2]
s [$ -5.. $ ]
s [ $ ][1.. floor ( $ /2)] -- first half of the last element of s

14.4.7 Concatenation of Sequences and Atoms - The & Operator


Any two objects may be concatenated using the & operator. The result is a sequence with a length equal to the sum of
the lengths of the concatenated objects. e.g.
1 {1 , 2 , 3} & 4 -- {1 , 2 , 3 , 4}
2

3 4 & 5 -- {4 , 5}
4

5 {{1 , 1} , 2 , 3} & {4 , 5} -- {{1 , 1} , 2 , 3 , 4 , 5}


6

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 }

The sequence-formation operator is listed at the bottom of the a precedence chart.

46
CHAPTER 14. DEFINITION 14.4. EXPRESSIONS

14.4.9 Other Operations on Sequences


Some other important operations that you can perform on sequences have English names, rather than special characters.
These operations are built-in to eui.exe/euiw.exe, so theyll always be there, and so theyll be fast. They are described in
detail in the Language Reference, but are important enough to Euphoria programming that we should mention them here
before proceeding. You call these operations as if they were subroutines, although they are actually implemented much
more efficiently than that.

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

repeat(object o1, integer count)


Returns a sequence that consists of an item repeated count times. e.g.
repeat (0 , 100) -- {0 ,0 ,0 ,... ,0} i . e . 100 zeros
repeat ( " Hello " , 3) -- {" Hello " , " Hello " , " Hello "}
repeat (99 ,0) -- {}

The item to be repeated can be any atom or sequence.

append(sequence s1, object o1)


Returns a sequence by adding an object o1 to the end of a sequence s1.
append ({1 ,2 ,3} , 4) -- {1 ,2 ,3 ,4}
append ({1 ,2 ,3} , {5 ,5 ,5}) -- {1 ,2 ,3 ,{5 ,5 ,5}}
append ({} , 9) -- {9}

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.

prepend(sequence s1, object o1)


Returns a new sequence by adding an element to the beginning of a sequence s. e.g.
1 append ({1 ,2 ,3} , 4) -- {1 ,2 ,3 ,4}
2 prepend ({1 ,2 ,3} , 4) -- {4 ,1 ,2 ,3}
3

4 append ({1 ,2 ,3} , {5 ,5 ,5}) -- {1 ,2 ,3 ,{5 ,5 ,5}}


5 prepend ({} , 9) -- {9}
6 append ({} , 9) -- {9}

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

5 -- appending an atom is the same


6 append ({1 ,2 ,3} , 5) -- {1 ,2 ,3 ,5}
7 {1 ,2 ,3} & 5 -- {1 ,2 ,3 ,5}

insert(sequence in what, object what, atom position)


This function takes a target sequence, in what, shifts its tail one notch and plugs the object what in the hole just created.
The modified sequence is returned. For instance:
s = insert ( " Joe " , h ,3) -- s is " Johe " , another string
s = insert ( " Joe " ," h " ,3) -- s is { J , o ,{ h } , e } , not a string
s = insert ({1 ,2 ,3} ,4 , -0.5) -- s is {4 ,1 ,2 ,3} , like prepend ()
s = insert ({1 ,2 ,3} ,4 ,8.5) -- s is {1 ,2 ,3 ,4} , like append ()

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().

splice(sequence in what, object what, atom position)


If what is an atom, this is the same as insert(). But if what is a sequence, that sequence is inserted as successive
elements into in what at position. Example:
1 s = splice ( " Joe " , h ,3)
2 -- s is " Johe " , like insert ()
3 s = splice ( " Joe " ," hn Do " ,3)
4 -- s is " John Doe " , another string
5 s = splice ( " Joh " ," n Doe " ,9.3)
6 -- s is " John Doe " , like with the & operator
7 s = splice ({1 ,2 ,3} ,4 , -2)
8 -- s is {4 ,1 ,2 ,3} , like with the & operator in reversed order

The length of splice(in what, what, position) always is length(in what) + length(what), like for concate-
nation using &.

14.5 Precedence Chart


When two or more operators follow one another in an expression, there must be rules to tell in which order they should be
evaluated, as different orders usually lead to different results. It is common and convenient to use a precedence order on
operators. Operators with the highest degree of precedence are evaluated first, then those with highest precedence among
what remains, and so on.
The precedence of operators in expressions is as follows:
highest precedence
** highest precedence **

function / type calls


unary - unary + not
* /
+ -
&
< > <= >= = !=
and or xor

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

The Euphoria editor displays these words in blue


The following are Euphoria built-in routines. It is best if you do not use these for your own identifiers:
1 abort getenv peek4s system
2 and_bits gets peek4u system_exec
3 append hash peeks tail
4 arctan head platform tan
5 atom include_paths poke task_clock_start
6 c_func insert poke2 task_clock_stop
7 c_proc integer poke4 task_create
8 call length position task_list
9 call_func log power task_schedule
10 call_proc machine_func prepend task_self
11 clear_screen machine_proc print task_status
12 close match printf task_suspend
13 command_line match_from puts task_yield
14 compare mem_copy rand time

50
CHAPTER 15. DECLARATIONS 15.1. IDENTIFIERS

15 cos mem_set remainder trace


16 date not_bits remove xor_bits
17 delete object repeat ?
18 delete_routine open replace &
19 equal option_switches routine_id $
20 find or_bits sequence
21 find_from peek sin
22 floor peek_string splice
23 get_key peek2s sprintf
24 getc peek2u sqrt

Identifiers can be used in naming the following:


procedures
functions
types
variables
constants
enums

15.1.1 procedures
These perform some computation and may contain a list of parameters, e.g.
1 procedure empty ()
2 end procedure
3

4 procedure plot ( integer x , integer y )


5 position (x , y )
6 puts (1 , * )
7 end procedure

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

1 procedure foo ( sequence s , integer n =1)


2 ? n + length ( s )
3 end procedure
4

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

This is not limited to the last parameter(s):


1 procedure bar ( sequence s = " abc " , integer n , integer p =1)
2 ? length ( s )+ n + p
3 end procedure
4

5 bar ( , 2) -- prints out 6 = 3 + 2 + 1


6 bar (2) -- errors out , as 2 is not a sequence
7 bar ( , 2 ,) -- same as bar ( ,2)
8 bar ( , 2 , 3) -- prints out 8 = 3 + 22 + 3
9 bar ({} , 2 , ) -- prints out 3 = 0 + 2 + 1
10 bar () -- errors out , second parameter is omitted ,
11 -- but doesn t have a default value

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

5 baz ( " abcd " ) -- prints out 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

15.1.3 return statement


Any Euphoria object can be returned. You can, in effect, have multiple return values, by returning a sequence of objects.
e.g.
return { x_pos , y_pos }

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

5 -- a , b and c may be assigned * any * value


6 object a , b , c
7 a = {}
8 b = a
9 c = 0

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

11 foo () -- prints out 7

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

constant MAX = 100


constant Upper = MAX - 10 , Lower = 5
constant name_list = { " Fred " , " George " , " Larry " }

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

-- ONE is 1 , TWO is 2 , THREE is 3 , FOUR is 4

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

-- ONE is 1 , TWO is 2 , THREE is 3


-- ABC is 10 , DEF is 11 , XYZ is 12

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

3 -- Only allow values of RED , GREEN , BLUE , or ALPHA as parameters


4 function xyz ( RGBA x , RGBA y )
5 return
6 end function

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

3 ? color ( RED ) -- > 1


4 ? color ( GREEN ) -- > 2
5 ? color ( BLACK ) -- > 3

54
CHAPTER 15. DECLARATIONS 15.2. SPECIFYING THE TYPE OF A VARIABLE

6 ? color ( BLUE ) -- > 4


7 ? color ( PINK ) -- > 5
8

9 constant color_names = { " rouge " , " vert " , " noir " , " bleu " , " rose " }
10

11 puts (1 , color_names [ color ( BLUE )]) -- > bleu

But with the exception,


1 enum type color RED , GREEN =7 , BLACK =1 , BLUE =3 , PINK =10 end type
2 ? color ( RED ) -- > 1
3 ? color ( GREEN ) -- > 2
4 ? color ( BLACK ) -- > 1
5 ? color ( BLUE ) -- > 4
6 ? color ( PINK ) -- > 5

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

Also note that enum members do not have to be integers.


enum by / 2 A =5 ,B , C -- > values are 5 , 2.5 , 1.25

15.2 Specifying the type of a variable


So far youve already seen some examples of variable types but now we will define types more precisely.
Variable declarations have a type name followed by a list of the variables being declared. For example,
1 object a
2

3 global integer x , y , z
4

5 procedure fred ( sequence q , sequence r )

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.

15.2.1 User-defined types


To augment the predefined types, you can create user-defined types. All you have to do is define a single-parameter
function, but declare it with type ... end type instead of function ... end function. For example,
1 type hour ( integer x )
2 return x >= 0 and x <= 23
3 end type
4

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.

Note to Bench markers:


When comparing the speed of Euphoria programs against programs written in other languages, you should specify
without type check at the top of the file. This gives Euphoria permission to skip run-time type checks, thereby
saving some execution time. All other checks are still performed, e.g. subscript checking, uninitialized variable
checking etc. Even when you turn off type checking, Euphoria reserves the right to make checks at strategic places,
since this can actually allow it to run your program faster in many cases. So you may still get a type check failure
even when you have turned off type checking. Whether type checking is on or off, you will never get a machine-level
exception. You will always get a meaningful message from Euphoria when something goes wrong. (This
might not be the case when you S directly into memory, or call routines written in C or machine code.)

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.

For large numbers, usual operations may yield strange results:

1 integer n = power (2 , 27) -- ok


2 integer n_plus = n + 1 , n_minus = n - 1 -- ok
3 atom a = n * n -- ok
4 atom a1 = n_plus * n_minus -- still ok
5 ? a - a1 -- prints 0 , should be 1 mathematically

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.

15.3.2 Defining the scope of an identifier


The scope of an identifier is a description of what code can access it. Code in the same scope of an identifier can access
that identifier and code not in the same scope cannot access it.
The scope of a variable depends upon where and how it is declared.

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

11 bar () -- ok , declared in sublib . e


12

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.

15.3.3 Using namespaces


Identifiers marked as global, public or export are known as exposed variables because they can be used in files other
than the one they were declared in.
All other identifiers can only be used within their own file. This information is helpful when maintaining or enhancing
the file, or when learning how to use the file. You can make changes to the internal routines and variables, without having
to examine other files, or notify other users of the include file.
Sometimes, when using include files developed by others, you will encounter a naming conflict. One of the include file
authors has used the same name for a exposed identifier as one of the other authors. One of way of fixing this, if you have
the source, is to simply edit one of the include files to correct the problem, however then youd have repeat this process
whenever a new version of the include file was released.
Euphoria has a simpler way to solve this. Using an extension to the include statement, you can say for example:
1 include johns_file . e as john
2 include bills_file . e as bill
3

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

5 puts (1 , " Hello , world !\ n " )


6 eu : puts (1 , " Hello , world !\ n " )

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

-- foo . e : this file does some stuff


namespace foo

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

4 public include sublib . e


5

6 public procedure main ()


7 ...
8

9 -- sublib . e
10 public procedure sub ()
11 ...
12

13 -- app . ex
14 include lib . e
15

16 lib : main ()
17 lib : sub ()

Now, what happens if you do not use public include ?


1 -- lib2 . e
2 include sublib . e
3 ...
4

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

15.3.4 The visibility of public and export identifiers


When a file needs to see the public or exported identifiers in another file that includes the first file, the first file must
include that other (including) file.
For example,
-- Parent file : foo . e --
public integer Foo = 1
include bar . e -- bar . e needs to see Foo
showit () -- execute a routine in bar . e

61
CHAPTER 15. DECLARATIONS 15.3. SCOPE

1 -- Included file : bar . e --


2 include foo . e -- included so I can see Foo
3 constant xyz = Foo + 1
4

5 public procedure showit ()


6 ? xyz
7 end procedure

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

5 public procedure fooer ()


6 . . .
7 end procedure

-- Appl file : runner . ex --


include foo . e
showit () -- execute a public routine that foo . e can see in bar . e
fooer () -- execute a public routine in foo . e

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

6 export function foobarr1 ()


7 return 0
8 end function
9

10 export function foobarr2 ()


11 return 0
12 end function

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.

15.3.5 The complete set of resolution rules


Resolution is the process by which the interpreter determines which specific symbol will actually be used at any given
point in the code. This is usually quite easy as most symbol names in a given scope are unique and so Euphoria does not
have to choose between them. However, when the same symbol name is used in different but enclosing scopes, Euphoria
has to make a decision about which symbol the coder is referring to.
When Euphoria sees an identifier name being used, it looks for the names declaration starting from the current scope
and moving outwards through the enclosing scopes until the names declaration is found.
The hierarchy of scopes can be viewed like this ...
global / public / export
file
routine
block 1
block 2
...
block n

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

1 procedure foo ( integer a )


2 if x then
3 integer a -- redefinition not allowed .
4 end if
5 end procedure

But note that this below is valid ...


1 integer a = 1
2 procedure foo ()
3 integer a = 2
4 ? a

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.

15.3.6 The override qualifier


There are times when it is necessary to replace a global, public or export identifier. Typically, one would do this to extend
the capabilities of a routine. Or perhaps to supersede the user defined type of some public, export or global variable, since
the type itself may not be global.
This can be achieved by declaring the identifier as override:
override procedure puts ( integer channel , sequence text )
eu : puts ( log_file , text )

64
CHAPTER 15. DECLARATIONS 15.3. SCOPE

eu : puts ( channel , text )


end procedure

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

x = repeat (0 , 1000) -- a sequence of 1000 zeros

and then later we assigned an atom to x with:


x = 7

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).

16.1 Assignment with Operator


Euphoria also provides some additional forms of the assignment statement.
To save typing, and to make your code a bit neater, you can combine assignment with one of the operators:
+ - / * &

For example, instead of saying:


mylongvarname = mylongvarname + 1

You can say:


mylongvarname += 1

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

You can say:


galaxy [ q_row ][ q_col ][ q_size ] *= 10

and instead of saying:


accounts [ start .. finish ] = accounts [ start .. finish ] / 10

You can say:


accounts [ start .. finish ] /= 10

In general, whenever you have an assignment of the form:


left - hand - side = left - hand - side op expression

You can say:


left - hand - side op = expression

where op is one of:


+ - * / &

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

5 if a = 9 and find (0 , s ) then


6 x = 4
7 y = 5
8 else
9 z = 8
10 end if
11

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.

17.2 switch statement


The switch statement is used to run a specific set of statements, depending on the value of an expression. It often replaces
a set of if-elsif statements due to its ability to be highly optimized, thus much greater performance. There are some key
differences, however. A switch statement operates upon the value of a single expression, and the program flow continues
based upon defined cases. The syntax of a switch statement:
1 switch < expr > [ with fallthru ] [ label " < label name > " ] do
2 case <val >[ , < val2 > , ...] then
3 [ code block ]
4 [[ break [ label ]]
5 case <val >[ , < val2 > , ...] then
6 [ code block ]
7 [[ break [ label ]]
8 case <val >[ , < val2 > , ...] then
9 [ code block ]
10 [[ break [ label ]]
11 ...
12

13 [ case else ]
14 [ code block ]
15 [[ break [ label ]]
16 end switch

The above example could be written with if statements like this ..


1 object temp = expression
2 object breaking = false
3 if equal ( temp , val1 ) then
4 [ code block 1]
5 [ breaking = true ]
6 end if
7 if not breaking and equal ( temp , val2 ) then
8 [ code block 2]
9 [ breaking = true ]

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

1 switch opt label " LBLa " do


2 case 1 , 5 , 8 then
3 FuncA ()
4

6 case 4 , 2 , 7 then
7 FuncB ()
8 switch alt label " LBLb " do
9 case " X " then
10 FuncC ()
11 break " LBLa "
12

13 case " Y " then


14 FuncD ()
15

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 ()

In the above, if opt is 2 and alt is X then it runs...


FuncB() FuncC() FuncM()
But if opt is 2 and alt is Y then it runs ...
FuncB() FuncD() FuncF() FuncG() FuncM()
In other words, the break "LBLa" skips to the end of the switch called LBLa rather than the switch called LBLb.

17.3 ifdef statement


The ifdef statement has a similar syntax to the if statement.
1 ifdef SOME_WORD then
2 -- ... zero or more statements
3 elsifdef SOME_OTHER_WORD then
4 -- ... zero or more statements
5 elsedef
6 -- ... zero or more statements
7 end ifdef

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:

17.3.1 Euphoria Version Definitions


EU4 - Major Euphoria Version

EU4 0 - Major and Minor Euphoria Version

EU4 0 4 - Major, Minor and Release Euphoria Version

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.

17.3.2 Platform Definitions


CONSOLE - Euphoria is being executed with the Console version of the interpreter (on windows, eui.exe, others
are eui)

GUI - Platform is Windows and is being executed with the GUI version of the interpreter (euiw.exe)

WINDOWS - Platform is Windows (GUI or Console)

LINUX - Platform is Linux

OSX - Platform is Mac OS X

FREEBSD - Platform is FreeBSD

OPENBSD - Platform is OpenBSD

NETBSD - Platform is NetBSD

BSD - Platform is a BSD variant (FreeBSD, OpenBSD, NetBSD and OS X)

UNIX - Platform is any Unix

72
CHAPTER 17. BRANCHING STATEMENTS 17.3. IFDEF STATEMENT

17.3.3 Application Definitions


EUI - Application is being interpreted by eui.
EUC - Application is being translated by euc.
EUC DLL - Application is being translated by euc into a DLL file.
EUB - Application is being converted to a bound program by eub.
EUB SHROUD - Application is being converted to a shrouded program by eub.
CONSOLE - Application is being translated, or converted to a bound console program by euc or eub, respectively.
GUI - Application is being converted to a bound Windows GUI program by eub.

17.3.4 Library Definitions


DATA EXECUTE - Application will always get executable memory from allocate() even when the system has
Data Execute Protection enabled for the Euphoria Interpreter.
SAFE - Enables safe runtime checks for operations for routines found in machine.e and dll.e
UCSTYPE DEBUG - Found in include/std/ucstypes.e
CRASH - Found in include/std/unittest.e

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 " )

C :\ myproj > eui myproj . ex


Hello , I am an interpreted program .
C :\ myproj > euc - con myprog . ex
... translating ...
... compiling ...
C :\ myproj > myprog . exe
Hello , I am a translated program .
C :\ myproj > bind myprog . ex
...
C :\ myproj > myprog . exe
Hello , I am a bound program .
C :\ myproj > shroud myprog . ex
...
C :\ myproj > eub myprog . il
Hello , I am a bound , shrouded program .

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

17.3.5 Using ifdef


You can define your own words either in source:
with define MY_WORD -- defines
without define OTHER_WORD -- undefines

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

5 -- define exported and public constants and procedures for


6 -- OSX as well
7 ifdef WINDOWS or OSX then
8 -- OSX is not supported but we define public symbols for it anyhow .

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

16 ifdef SHAREWARE then


17 if record_count > 100 then
18 message ( " Shareware version can only contain 100 records . Please register " )
19 abort (1)
20 end if
21 end ifdef

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.

18.1 while statement


A while statement tests a condition to see if it is non-zero (true), and if so, a body of statements is executed. The
condition is re-tested after when the statements are run, and if still true the statements are run again, and so on.
Syntax Format: while expr [ with entry] [ label "name" ] do statements [ entry] statements end
while
Example 1
while x > 0 do
a = a * 2
x = x - 1
end while

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

17 res = funcE ( res , some_value )


18 end while

18.2 loop until statement


A loop statement tests a condition to see if it is non-zero (true), and until it is true a loop is executed.
Syntax Format: loop [ with entry] [ label "name" ] do statements
until expr end loop
1 loop do
2 a = a * 2
3 x = x - 1
4 until x <=0
5 end loop

1 loop with entry do


2 a = a * 2
3 entry
4 x = x - 1
5 until x <=0
6 end loop

1 loop label " GONEXT " do


2 a = a * 2
3 y += 1
4 if y = 7 then continue " GONEXT " end if
5 x = x - 1
6 until x <=0
7 end loop

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.

18.3 for statement


Syntax Format: for loopvar = startexpr to endexpr [ by delta] do statements end for
A for statement sets up a special loop that has its own loop variable. The loop variable starts with the specified
initial value and increments or decrements it to the specified final value. The for statement is used when you need to
repeat a set of statements a specific number of times.
Example:
1 -- Display the numbers 1 to 6 on the screen .
2 puts (1 , " 1\ n " )
3 puts (1 , " 2\ n " )
4 puts (1 , " 3\ n " )
5 puts (1 , " 4\ n " )
6 puts (1 , " 5\ n " )
7 puts (1 , " 6\ n " )

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

Or using another way ...


1 for i = 1 to 10 do
2 ? i -- ? is a short form for print ()
3 end for
4

5 -- fractional numbers allowed too


6 for i = 10.0 to 20.5 by 0.3 do
7 for j = 20 to 10 by -2 do -- counting down
8 ? {i , j }
9 end for
10 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.

The following flow control keywords are available.


break retry entry exit continue return goto end

19.1 exit statement


Exiting a loop is done with the keyword exit. This causes flow to immediately leave the current loop and recommence
with the first statement after the end of the loop.
1 for i = a to b do
2 c = i
3 if doSomething ( i ) = 0 then
4 exit -- Stop executing code inside the for block .
5 end if
6 end for
7

8 -- Flow restarts here .


9 if c = a then ...

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 output from this is ...


1 {1 , 1, 2}
2 {1 , 2, 5}
3 {1 , 3, 9}
4 {1 , 4, 14}
5 {1 , 5, 20}
6 {1 , 6, 27}
7 {1 , 7, 35}
8 {1 , 8, 44}
9 {1 , 9, 54}
10 0

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

It is also quite common to see something like this:


1 constant TRUE = 1
2

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.

19.2 break statement


Works exactly like the exit statement, but applies to if statements or switch statements rather than to loop statements
of any kind. Example:
1 if s [1] = E then
2 a = 3
3 if s [2] = u then
4 b = 1
5 if s [3] = p then
6 break 0 -- leave topmost if block
7 end if
8 a = 2
9 else
10 b = 4
11 end if
12 else
13 a = 0
14 b = 0
15 end if

This code results in:

Dur -> a=0 b=0

Exe -> a=3 b=4

Eux -> a=2 b=1

81
CHAPTER 19. FLOW CONTROL STATEMENTS 19.3. CONTINUE STATEMENT

Eup -> a=3 b=1


The same optional parameters can be used with the break statement as with the exit statement, but of course apply
to if and switch blocks only, instead of loops.

19.3 continue statement


Likewise, skipping the rest of an iteration in a single code block is done using a single keyword, continue. The continue
statement continues execution of the loop it applies to by going to the next iteration now. Going to the next iteration
means testing a condition (for while and loop constructs, or changing the for construct variable index and checking
whether it is still within bounds.
1 for i = 3 to 6 do
2 ? i
3 if i = 4 then
4 puts (1 , " (2)\ n " )
5 continue
6 end if
7 ? i * i
8 end for

This will print 3, 9, 4, (2), 5 25, 6 36.


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 if b > 50 then
7 printf (1 , " % d " , b )
8 b = 0
9 continue " main "
10 end if
11 end for
12 end for
13

14 ? b

The same optional parameters that can be used in an exit statement can apply to a continue statement.

19.4 retry statement


The retry statement retries executing the current iteration of the loop it applies to. The statement branches to the first
statement of the designated loop, without testing anything nor incrementing the for loop index.
Normally, a sub-block which contains a retry statement also contains another flow control keyword, since otherwise
the iteration would be endlessly executed.
1 errors = 0
2 for i = 1 to length ( files_to_open ) do
3 fh = open ( files_to_open [ i ] , " rb " )
4 if fh = -1 then
5 if errors > 5 then
6 exit
7 else
8 errors += 1
9 retry
10 end if
11 end if

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.

19.5 with entry statement


It is often the case that the first iteration of a loop is somehow special. Some things have to be done before the loop
starts--they are done before the statement starting the loop. Now, the problem is that, just as often, some things do not
need to, or should not, be done at this initialization stage. The entry keyword is an alternative to setting flags relentlessly
and forgetting to update them. Just add the entry keyword at the point you wish the first iteration starts.
1 public function find_all ( object x , sequence source , integer from )
2 sequence ret = {}
3

4 while from > 0 with entry do


5 ret &= from
6 from += 1
7 entry
8 from = find_from (x , source , from )
9 end while
10

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.

Note on infinite loops.


With eui.exe or eui, control-c will always stop your program immediately, but with the euiw.exe that has not
produced any console output, you will have to use the Windows process monitor to end the application.

19.6 goto statement


goto instructs the computer to resume code execution at a place which does not follow the statement. The place to
resume execution is called the target of the statement. It is restricted to lie in the current routine, or the current file if
outside any routine.
Syntax is:
goto " label string "

The target of a goto statement can be any accessible label statement:


label " label string "

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

the various structured constructs wouldnt do, or very awkwardly;

you contemplate a significant gain in speed/reliability from such a direct move;


the code flow remains understandable for an outsider nevertheless.
During early development, it may be nice to have while the code is not firmly structured. But most instances of goto
should melt into structured constructs as soon as possible as code matures. You may find out that modifying a program
that has goto statements is usually trickier than if it had not had them.
The following may be situations where goto can help:
A routine has several return statements, and some processing must be done before returning, no matter from where.
It may be clearer to goto a single return point and perform the processing only at this point.
An exit statement in a loop corresponds to an early exit, and the normal processing that immediately follows the
loop is not relevant. Replacing an exit statement followed by various flag testing by a single goto can help.
Explicit label names will tremendously help maintenance. Remember that there is no limit to their contents.
goto-ing into a scope (like an if block, a for loop,...) will just do that. Some variables may be defined only in that
scope, and they may or may not have sensible values. It is up to the programmer to take appropriate action in this respect.

19.7 Header Labels


As shown in the above section on control flow statements, most can have their own label. To label a flow control statement,
use a label clause immediately preceding the flow controls terminator keyword (then / do).
A label clause consists of the keyword label followed by a string literal. The string is the label name.
Examples:
1 if n =0 label " an_if_block " then
2 ...
3 end if
4

5 while TRUE label " a_while_block " do


6 ...
7 end while
8

9 loop label " a_loop_block " do


10 ...
11 until TRUE
12 end loop
13

14 switch x label " a_switch_block " do


15 ...
16 end switch

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

while 1 with entry label " top " do -- CORRECT

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

while 1 or {1 ,2 ,3 ,4 ,5} do -- illegal sequence result avoided

B could even contain uninitialized variables, out-of-bounds subscripts etc.


This may look like sloppy coding, but in fact it often allows you to write something in a simpler and more readable
way. For instance:
if length ( x ) > 1 and x [2] = y then

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

21.1 include statement


When you write a large program it is often helpful to break it up into logically separate files, by using include statements.
Sometimes you will want to reuse some code that you have previously written, or that someone else has written. Rather
than copy this code into your main program, you can use an include statement to refer to the file containing the code.
The first form of the include statement is:
include filename
This reads in (compiles) a Euphoria source file.
Some Examples:
include std / graphics . e
include / mylib / myroutines . e
public include library . e

Any top-level code in the included file will be executed at start up time.
Any global identifiers that are declared in the file doing the including will also be visible in the file being included.
However the situation is slightly different for an identifier declared as public or export. In these cases the file being
included will not see public/export symbols declared in the file doing the including, unless the file being included also
explicitly includes the file doing the including. Yes, you would better read that again because its not that obvious. 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

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

If the above code did not use namespaces, Euphoria would not have know which foo to use the one from bob.e or
the one in anne.e.
If public precedes the include statement, then all public identifiers from the included file will also be visible to the
including file, and visible to any file that includes the current file.
If an absolute filename is given, Euphoria will open it and start parsing it. When a relative filename is given, Euphoria
will try to open the file relative to the following directories, in the following order:
1. The directory containing the current source file. i.e. the source file that contains the include statement that is being
processed.
2. The directory containing the main file given on the interpreter, translator or binder see command line.
3. If 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:

include filename as namespace identifier :


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

See Also: Using namespaces.

21.2 with / without


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

21.2.1 On / Off options


Default Option
without profile
without profile time
without trace
without batch
with type check
with indirect includes
with inline
with turns on one of the options and without turns off one of the options.
For more information on the profile, profile time and trace options, see Debugging and Profiling. For more
information on the type check option, see Performance Tips.
There is also a rarely-used special with option where a code number appears after with. In previous releases this code
was used by RDS to make a file exempt from adding to the statement count in the old Public Domain Edition. This is
not used any longer, but does not cause an error.

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.

21.2.2 Complex with / without options


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

with warning
enables all warnings

without warning
disables all warnings

with warning warning name list with warning = warning name list
enables only these warnings, and disables all other

without warning warning name list without warning = warning name list
enables all warnings except the warnings listed

with warning &= warning name list with warning += warning name list
enables listed warnings in addition to whichever are enabled already

without warning &= warning name list without warning += warning name list
disables listed warnings and leaves any not listed in its current state.

with warning save


saves the current warning state, i.e. the list of all enabled warnings. This destroys any previously saved state.

with warning restore


causes the previously saved state to be restored.

without warning strict


overrides some of the warnings that the -STRICT command line option tests for, but only until the end of the next
function or procedure. The warnings overridden are * default arg type * not used * short circuit * not reached *
empty case * no case else

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

Initially, only the following warnings are enabled:


resolution
override
builtin chosen

91
CHAPTER 21. SPECIAL TOP-LEVEL STATEMENTS 21.2. WITH / WITHOUT

translator

cmdline
mixed profile
not reached
custom

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

with / without define


As mentioned about ifdef statement, this top level statement is used to define/undefine tags which the ifdef statement
may use.
The following tags have a predefined meaning in Euphoria:
WINDOWS: platform is any version of Windows (tm) from 95 on to Vista and beyond
WINDOWS: platform is any kind of Windows system
UNIX: platform is any kind of Unix style system

LINUX: platform is Linux


FREEBSD: platform is FreeBSD
OSX: platform is OS X for Macintosh

SAFE: turns on a slower debugging version of memory.e called safe.e when defined. Switching mode by renaming
files no longer works.
EU4: defined on all versions of the version 4 interpreter
EU4 0: defined on all versions of the interpreter from 4.0.0 to 4.0.X

EU4 0 0: defined only for version 4.0.0 of the interpreter


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

21.2.3 with / without inline


This directive allows coders some flexibility with inlined routines. The default is for inlining to be on. Any routine that is
defined when without inline is in effect will never be inlined.
with inline takes an optional integer parameter that defines the largest routine (by size of IL code) that will be
considered for inlining. The default is 30.

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

IDENTIFIER ==: ( ALPHA | USCORE ) [( AlPHA | DIGIT | USCORE ) ... ]

EXPRESSION ==: NUMEXPR | STREXPR | SEQEXPR | BOOLEXPR

NUMEXPR ==: ( an expression that evaluates to an atom )

STREXPR ==: ( an expression that evaluates to a string sequence )

SEQEXPR ==: ( an expression that evaluates to an sequence )

BOOLEXPR ==: ( an expression that evaluates to an atom in which zero represents


falsehood and non - zero represents truth )

BINARYEXPR ==: [ EXPRESSION BINOP EXPRESSION ]

BINOP ==: and | or | xor | + | - | * | /

UNARYEXPR ==: [ UNARYOP EXPRESSION ]

UNARYOP ==: not | -

STATEMENT ==:

STMTBLK ==: STATEMENT [ STATEMENT ...]

LABEL ==: label STRINGLIT

LISTDELIM ==: ,

STRINGLIT ==: SIMPLESTRINGLIT | RAWSTRINGLIT

SIMPLESTRINGLIT ==: SSLITSTART [ ( CHAR | ESCCHAR ) ... ] SSLITEND

94
CHAPTER 22. FORMAL SYNTAX 22.2. STATEMENTS

SSLITSTART ==: "


SSLITEND ==: "
CHAR ==: ( any byte value )
ESCCHAR ==: ESCLEAD ( t | n | r | \ | " \ )
ESCLEAD ==: \

RAWSTRINGLIT ==: DQRAWSTRING | BQRAWSTRING


DQRAWSTRING ==: """ [ MARGINSTR ] [ CHAR ...] """
BQRAWSTRING ==: [ MARGINSTR ] [ CHAR ...]
MARGINSTR ==: _ ...

SCOPETYPE ==: global | public | export | override

DATATYPE ==: atom | integer | sequence | object | IDENTIFER

22.2 Statements
22.2.1 Directives
INCLUDESTMT
WITHSTMT
NAMESPACE

22.2.2 Variables, Constants, Enums


VARDECLARE
CONSTDECLARE
ENUMDECLARE
SLICING

22.2.3 Flow Control


IFSTMT
SWITCHSTMT
BREAKSTMT
CONTINUESTMT
RETRYSTMT
EXITSTMT
FALLTHRUSTMT
FORSTMT
WHILESTMT
LOOPSTMT
GOTOSTMT
CALL
IFDEFSTMT

22.2.4 Routines
PROCDECLARE
FUNCDECLARE
TYPEDECLARE

95
CHAPTER 22. FORMAL SYNTAX 22.3. SEQUENCE SLICE

RETURN

22.2.5 include
INCLUDESTMT

INCLUDESTMT ==: include FILEREF [ as NAMESPACEID ] EOL


FILEREF ==: A file path that may be enclosed in double - quotes .
NAMESPACEID ==: IDENTIFIER

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.3 Sequence Slice


SLICING

SLICE ==: SLICESTART INTEXPRESSION SLICEDELIM INTEXPRESSION SLICEEND


SLICESTART ==: [
SLICEDELIM ==: ..
SLICEEND ==: ]

See Also: Slicing of Sequences

22.4 if
IFSTMT

IFSTMT ==: IFTEST [ ELSIF ...] [ ELSE ] ENDIF


IFTEST ==: if ATOMEXPR [ LABEL ] then [ STMTBLOCK ]
ELSIF ==: elsif ATOMEXPR then [ STMTBLOCK ]
ELSE ==: else [ STMTBLOCK ]
ENDIF ==: end if

See Also: if statement

22.5 ifdef
IFDEFSTMT

IFDEFSTMT ==: IFDEFTEST [ ELSDEFIF ...] [ ELSEDEF ] ENDDEFIF


IFDEFTEST ==: ifdef DEFEXPR then [ STMTBLOCK ]
ELSDEFIF ==: elsifdef DEFEXPR then [ STMTBLOCK ]
ELSEDEF ==: elsedef [ STMTBLOCK ]
ENDDEFIF ==: end ifdef
DEFEXPR ==: DEFTERM [ DEFOP DEFTERM ]
DEFTERM ==: [ not IDENTIFIER ]
DEFOP ==: and | or

See Also: ifdef statement

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

See Also: switch statement

22.6 break
BREAKSTMT
BREAKSTMT ==: break [ STRINGLIT ]

See Also: break statement

22.7 continue
CONTINUESTMT
CONTINUESTMT ==: continue [ STRINGLIT ]

See Also: continue statement

22.8 retry
RETRYSTMT
RETRYSTMT ==: retry [ STRINGLIT ]

See Also: retry statement

22.9 exit
EXITSTMT
EXITSTMT ==: exit [ STRINGLIT ]

See Also: exit statement

22.10 fallthru
FALLTHRUSTMT
FALLTHRUSTMT ==: fallthru

See Also: switch statement

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 ]

See Also: for statement

22.12 while
WHILESTMT
WHILESTMT ==:
while BOOLEXPR [ WITHENTRY ] [ LABEL ] do STMTBLK [ ENTRY ] end while
WITHENTRY ==: with entry
ENTRY ==: entry [ STMTBLK ]

See Also: while statement

22.13 loop
LOOPSTMT
LOOPSTMT ==:
loop [ WITHENTRY ] [ LABEL ] do STMTBLK [ ENTRY ] until BOOLEXPR end loop

See Also: loop until statement

22.14 goto
GOTOSTMT
GOTOSMT ==: goto LABEL

See Also: goto statement

22.15 declare a variable


VARDECLARE
VARDECLARE ==: [ SCOPETYPE ] DATATYPE IDENTLIST
IDENTLIST ==: IDENT [ , IDENTLIST ]
IDENT ==: IDENTIFIER [ = EXPRESSION ]

Notes:

The type of the EXPRESSION must be compatable with the DATATYPE.

22.16 declare a constant


CONSTDECLARE
CONSTDECLARE ==: [ SCOPETYPE ] constant IDENTLIST

98
CHAPTER 22. FORMAL SYNTAX 22.17. DECLARE AN ENUMERATED VALUE

22.17 declare an enumerated value


ENUMDECLARE
ENUMDECLARE ==: [ SCOPETYPE ] [ ENUMVAL | ENUMTYPE ]
ENUMVAL ==: enum [ by ENUMDELTA ] IDENTLIST
ENUMDELTA ==: [ + | - | * | / ] NUMEXPR
ENUMTYPE ==: enum type [ by ENUMDELTA ] IDENTLIST end type

22.18 call a procedure or function


CALL Used to call (invoke) either a procedure or a function.
CALL ==: IDENTIFIER ( [ ARGLIST ] )
ARGLIST ==: ARGUMENT [ , ARGLIST ]

See Also: procedures functions

22.19 declare a procedure


PROCDECLARE
PROCDECLARE ==: [ SCOPETYPE ] procedure IDENTIFIER ( [ PARMLIST ] ) [ STMTBLK ] end procedure
PARMLIST ==: PARAMETER [ , PARMLIST ]
PARAMETER ==: DATATYPE IDENTIFER

Notes:
The procedure statement block must not contain a return statememt.
See Also: procedures

22.20 declare a function


FUNCDECLARE
FUNCDECLARE ==: [ SCOPETYPE ] function IDENTIFIER ( [ PARMLIST ] ) [ STMTBLK ] end function
PARMLIST ==: PARAMETER [ , PARMLIST ]
PARAMETER ==: DATATYPE IDENTIFER

Notes:
The function statement block must contain a return statememt.
See Also: functions

22.21 declare a user defined type


TYPEDECLARE
TYPEDECLARE ==: [ SCOPETYPE ] type IDENTIFIER ( PARAMETER ) [ STMTBLK ] end type
PARAMETER ==: DATATYPE IDENTIFER

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

22.22 return the result of a function


RETURN
RETURN ==: return EXPRESSION

See Also: types

22.23 default namespace


NAMESPACE ==: namespace IDENTIFIER EOL

See Also: Using namespaces

22.24 with options


WITHSTMT
WITHSTMT ==: [ " with " | " without " ] WITHOPTION
WITHOPTION ==: [ " profile " | " profile_time " | " trace " | " batch " |
" type_check " | " indirect_includes " | " inline " | WITHWARNING ]
WITHWARNING ==: " warning " [ WARNOPT ]
WARNOPT ==: SETWARN | ADDWARN | SAVEWARN | RESTOREWARN | STRICTWARN
SETWARN ==: [ = ] { WARNLIST }
ADDWARN ==: [ += | &= ] { WARNLIST }
SAVEWARN ==: save
RESTOREWARN ==: restore
STRICTWARN ==: strict

See Also: with / without

100
Chapter 23
Euphoria Internals

The interpreter has four binary components:

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.

23.1 The Euphoria Data Structures


23.1.1 The Euphoria representation of a Euphoria Object
Every Euphoria object is stored as-is. A special unlikely floating point value is used for NOVALUE. NOVALUE signifies that
a variable has not been assigned a value or the end of a sequence.

23.1.2 The C Representation of a Euphoria Object


Every Euphoria object is either stored as is, or as an encoded pointer. A Euphoria integer is stored in a 32-bit signed
integer. If the number is too big for a Euphoria integer, it is assigned to a 64-bit double float in a structure and an
encoded pointer to that structure is stored in the said 32-bit memory space. Sequences are stored in a similar way.

32 bit number range :


0 X8 0 XA 0 XC 0 XE 0 X0 0 X2 0 X4 0 X6 0 X8
-4*2^29 -3*2^29 -2*2^29 -1 -2^29 0*2^29 1*2^29 2*2^29 3*2^29 4*2^29

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.

23.2 The C Representations of a Euphoria Sequence and a Euphoria Atom

// 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

Taken together these are what get represented in memory.


base length ref postfill cleanup pre fill base[1..$] NOVALUE post fill
space space
By their nature, sequences are variable length, dynamic entities and so the C structure needs to cater for this. When
a sequence is created, we allocate enough RAM for the combined header and the initial storage for the elements.

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.

cleanup If not null, it points to a routine that is called immediately


before the sequence is deleted.

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

23.3 The Euphoria Object Macros and Functions


23.3.1 Description
The macros are imperfect. For example, IS SEQUENCE(NOVALUE) returns TRUE and IS ATOM DBL() will return TRUE for
integer values as well as encoded pointers to struct ds. This is why there is an order that these tests are made: We test
IS ATOM INT and if that fails we can use IS ATOM DBL and then that will only be true if we pass an encoded pointer to a
double. We must be sure that something is not NOVALUE before we use IS SEQUENCE on it.
Often we know foo is not NOVALUE before getting into this:
// object foo
if ( IS_ATOM_INT ( foo )) {
// some code for a Euphoria integer
} else if ( IS_ATOM_DBL ( foo )) {
// some code for a double
} else {
// code for a sequence foo
}

A sequence is held in a struct s1 type and a double is contained in a struct d.

23.4 Type Value Functions and Macros


23.4.1 IS ATOM INT

< internal > int IS_ATOM_INT ( object o )

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.

23.4.2 IS ATOM DBL

< internal > int IS_ATOM_DBL ( object o )

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

< internal > int IS_ATOM ( object o )

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

< internal > int IS_SEQUENCE ( object o )

Returns
true if the object is an encoded pointer to a struct s1.

Assumption
o is not NOVALUE.

23.4.5 IS DBL OR SEQUENCE

< internal > int IS_DBL_OR_SEQUENCE ( object o )

Returns
true if the object is an encoded pointer of either kind of structure.

23.5 Type Conversion Functions and Macros


23.5.1 MAKE INT

< internal > object MAKE_INT ( signed int x )

Returns
an object with the same value as x. x must be with in the integer range of a legal Euphoria integer type.

23.5.2 MAKE UINT

< internal > object MAKE_UINT ( unsigned int x )

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

23.5.3 MAKE SEQ

< internal > object MAKE_SEQ ( struct s1 * sptr )

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

< internal > object NewString ( char * s )

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.

23.5.5 MAKE DBL

< internal > object MAKE_DBL ( struct d * dptr )

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

< internal > object NewDouble ( double dbl )

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.

23.5.7 DBL PTR

< internal > struct d * DBL_PTR ( object o )

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.

23.5.8 SEQ PTR

< internal > struct s1 * SEQ_PTR ( object o )

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.

get pos int

< internal > uintptr_t get_pos_int ( char * where , object x )

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.

23.6 Creating Objects


23.6.1 NewS1

< internal > object NewS1 ( long size )

Returns
A sequence object with size members which are not yet set to a value.

23.7 Object Constants


Use MAXINT and MININT to check for overflow and underflow, NOVALUE to check if a variable has not been assigned,
and use NOVALUE to terminate a sequence.

23.7.1 NOVALUE

< internal > object NOVALUE

Indicates that a variable has not been assigned and also terminates a sequence.

23.7.2 MININT

< internal > signed int MININT

The minimal Euphoria integer. This is -(230 ).

107
CHAPTER 23. EUPHORIA INTERNALS 23.7. OBJECT CONSTANTS

23.7.3 MAXINT

< internal > signed int MAXINT

The maximal Euphoria integer. This is 230 -1.

23.7.4 HIGH BITS

< internal > signed int HIGH_BITS

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.

Proof that HIGH BITS is #C000 0000 on 32-bit version of EUPHORIA.


In the following expressions powers have higher precedence than unuary minus.* if c is a non-ATOM-INT value, then

c belongs to the set [-231 ,-230 -1(=NOVALUE)] U [230 ,231 ].


c+-230 belongs to the set [-231 -230 ,-230 -1-230 ] U [230 -230 ,230 ] which is [-3*230 ,-231 -1] U [0,230 ]. However the lower
values wrap around to non-negative numbers:
-231 -1 wraps to 231 -1. -3*230 wraps around to 230 .
c+-230 belongs to the set [230 ,231 -1] U [0,230 ] = [0,231 -1]
This is the set of all non-negative numbers that can fit into 32-bit signed longs. -230 is the unsigned version of
#C000 0000. QED.
A visual way of looking at it is, adding #C000 0000 to the set of non-ATOM INTS rotates the set to the negative
side by -MININT (230). The already negative ones wrap around to the positive; the positive numbers stay positive and
hug the zero. Since adding #C000 0000 on registers is 1-1 and onto, we also know that ATOM INTs will all be mapped
to negative signed longs.

Testing for Overflow:


There are two ways to test for overflow:

1. (c > MAXINT) (c < MININT)

2. (c + HIGH BITS) >= 0

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.

23.7.6 Backend Instructions


After the Parser processes the instructions. It creates Backend instructions that are easily translated or interpreted. The
system uses opcodes and some parameters which are put on a stack. This backend language is similar to assembler. You
have opcodes (instructions) and parameters. These parameters must be integers themselves but some may serve as pointers
to arbitrary EUPHORIA objects. As a developer of EUPHORIA itself, rather than a developer that uses EUPHORIA, it is

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.

24.1.1 The with / without trace directive


The interpreter provides you with additional powerful tools for debugging. Using trace(1) you can trace the execution of
your program on one screen while you witness the output of your program on another. trace(2) is the same as trace(1)
but the trace screen will be in monochrome. Finally, using trace(3), you can log all executed statements to a file called
ctrace.out.
The with/without trace special statements select the parts of your program that are available for tracing. Often you
will simply insert a with trace statement at the very beginning of your source code to make it all traceable. Sometimes it
is better to place the first with trace after all of your user-defined types, so you dont trace into these routines after each
assignment to a variable. At other times, you may know exactly which routine or routines you are interested in tracing, and
you will want to select only these ones. Of course, once you are in the trace window, you can skip viewing the execution
of any routine by pressing down-arrow on the keyboard rather than Enter. However, once inside a routine, you must step
through till it returns, even if stepping in was an mistake.
Only traceable lines can appear in ctrace.out or in ex.err as Traced lines leading up to the failure, should a
run-time error occur. If you want this information and didnt get it, you should insert a with trace and then rerun your
program. Execution will be slower when lines compiled with trace are executed, especially when trace(3) is used.
After you have predetermined the lines that are traceable, your program must then dynamically cause the trace facility
to be activated by executing a trace() statement. You could simply say:
with trace
trace (1)

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.

1 type positive_int ( integer x )


2 if x = 99 then
3 trace (1) -- how can this be ???
4 return 1 -- keep going
5 else
6 return x > 0
7 end if
8 end type

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.

24.2 The Trace Screen

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

F1 display main output screen


take a look at your programs output so far
F2 redisplay trace screen. Press this key while viewing the
main output screen
to return to the trace display.
Enter execute the currently-highlighted statement only
down-arrow continue execution and break when any statement coming
after
this one in the source listing is about to be executed.
This lets you skip over subroutine calls. It also lets you
stop on the first statement following the end of a loop
without having to witness all iterations of the loop.
? display the value of a variable. After hitting ? you will be
prompted for the name of the variable.
Many variables are displayed for you automatically as they
are assigned a value. If a variable is not currently being
displayed, or is only partially displayed, you can ask for it.
Large sequences are limited to one line on the trace screen,
but when you ask for the value of
a variable that contains a large sequence, the screen will
clear, and you can scroll through
a pretty-printed display of the sequence. You will then be
returned to the trace screen,
where only one line of the variable is displayed. Variables
that are not defined at this point
in the program cannot be shown. Variables that have not
yet been initialized will have
< NO VALUE > beside their name. Only variables, not
general expressions, can be displayed.
As you step through execution of the program, the system
will update any values showing
on the screen. Occasionally it will remove variables that
are no longer in scope, or
that havent been updated in a long time compared with
newer, recently-updated variables.
q quit tracing and resume normal execution. Tracing will
start again when the next trace(1) is executed.
Q quit tracing and let the program run freely to its normal
completion. trace() statements will be ignored.
! this will abort execution of your program. A traceback and
dump of variable values will go to ex.err.
As you trace your program, variable names and values appear automatically in the bottom portion of the screen.
Whenever a variable is assigned to, you will see its name and new value appear at the bottom. This value is always kept
up-to-date. Private variables are automatically cleared from the screen when their routine returns. When the variable
display area is full, least-recently referenced variables will be discarded to make room for new variables. The value of a
long sequence will be cut off after 80 characters.
For your convenience, numbers that are in the range of printable ASCII characters (32-127) are displayed along with
the ASCII character itself. The ASCII character will be in a different color (or in quotes in a mono display). This is done
for all variables, since Euphoria does not know in general whether you are thinking of a number as an ASCII character or
not. You will also see ASCII characters (in quotes) in ex.err. This can make for a rather busy display, but the ASCII
information is often very useful.
The trace screen adopts the same graphics mode as the main output screen. This makes flipping between them quicker

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.3 The Trace File


When your program calls trace(3), tracing to a file is activated. The file, ctrace.out will be created in the current
directory. It contains the last 500 Euphoria statements that your program executed. It is set up as a circular buffer that
holds a maximum of 500 statements. Whenever the end of ctrace.out is reached, the next statement is written back at
the beginning. The very last statement executed is always followed by === THE END ===. Because its circular, the
last statement executed could appear anywhere in ctrace.out. The statement coming after === THE END === is
the 500th-last.
This form of tracing is supported by both the interpreter and the the Euphoria to C translator. It is particularly useful
when a machine-level error occurs that prevents Euphoria from writing out an ex.err diagnostic file. By looking at the
last statement executed, you may be able to guess why the program crashed. Perhaps the last statement was a poke()
into an illegal area of memory. Perhaps it was a call to a C routine. In some cases it might be a bug in the interpreter or
the translator.
The source code for a statement is written to ctrace.out, and flushed, just before the statement is performed, so
the crash will likely have happened during execution of the final statement that you see in ctrace.out.

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.

24.5 Some Further Notes on Time Profiling


With each click of the system clock, an interrupt is generated. When you specify with profile time Euphoria will
sample your program to see which statement is being executed at the exact moment that each interrupt occurs.
Each sample requires four bytes of memory and buffer space is normally reserved for 25000 samples. If you need more
than 25000 samples you can request it:
with profile_time 100000

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

25.1 The Shroud Command


25.1.1 Synopsis

eushroud [ - full_debug ] [ - list ] [ - quiet ] [ - out shrouded_file ] filename . ex [ w / u ]

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.

-quiet: Suppress normal messages and statistics. Only report errors.

-out shrouded file: Write the output to shrouded file.

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.

25.2 The Bind Command


25.2.1 Synopsis:

eubind [ - c config - file ] [ - con ] [ - copyright ] [ - eub path - to - backend ]


[ - full_debug ] [ - i dir ] [ - icon file ] [ - list ] [ - quiet ]
[ - out executable_file ] [ - shroud_only [ filename . ex ]

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.

-list: Same as shroud above.

-quiet: Same as shroud above.

-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 C Compilers Supported


The Translator currently works with GNU C on Unix-like OSes, GNU C on Windows from MinGW or Cygwin using the
-gcc option and with Watcom C (the default) on Windows. These are all free compilers.
GNU C will exist already on your Unix system. The others can be downloaded from their respective Web sites.

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.

Currently, only 32-bit compilers are supported on 64-bit platforms.

26.3 How to Run the Translator


Running the Translator is similar to running the Interpreter:
euc - con allsorts . ex

Note: that on Unix, the demos might be installed to /usr/share/euphoria/demo


Instead of running the allsorts.ex program, the Translator will create several C source files in a temporary build
directory, compile them and result in a native executable file. For this to work, you have to have a supporting compiler
installed (mentioned above). The optional parameter used in this example, -con, will be explained in full detail below.

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 Command-Line Options


26.4.1 -gcc, -wat
If you happen to have more than one C compiler for a given platform, you can select the one you want to use with a
command-line option:
- wat -- Watcom compiler
- gcc -- GCC compiler ( MinGW on Windows )

For example, to compile with GCC (or MinGW on Windows):


euc - gcc pretend . exw

Note: Watcom is the default on Windows and -wat is assumed.

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

26.4.3 -dll / -so - Shared Library


To make a shared dynamically loading library, just add -dll to the command line. e.g.
euc - dll mylib . ew

Note: On *nix systems, you can also use -so. Both will produce a *nix shared library.
Please see Dynamic Link Libraries

26.4.4 -con - Console based program


To make a Windows console program instead of a Windows GUI program, add -con to the command line. e.g.
euc - con myprog . exw

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.

26.4.5 -rc-file - Resource File


On Windows, euc can automatically compile and link in an application specific resource file. This resource file can contain
product and version information, an application icon or any other valid resource data.
euc -rc - file myapp . rc myapp . ex

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

26.4.6 -stack - Stack size


To increase or decrease the total amount of stack space reserved for your program, add -stack nnnn to the command
line. e.g.

euc - stack 100000 myprog . ex

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.

26.4.7 -debug - Debug mode


To compile your program with debugging information, usable with a debugger compatible with your compiler, use the
-debug option:

euc - debug myapp . ex

26.4.8 -lib - User defined library


It is sometimes useful to link your translated code to a Euphoria runtime library other than the default supplied library.
This ability is probably mostly useful for testing and debugging the runtime library itself, or to give additional debugging
information when debugging translated Euphoria code. Note that only the default library is supplied. Use the -lib
library option:

euc - lib decu . a myapp . ex

26.4.9 -plat - Set platform


The translator has the capability of translating Euphoria code to C code for a platform other than the host platform. This
can be done with the -plat option. It takes one parameter, the platform code:

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

26.4.10 -makefile / -makefile-partial - Using makefiles


You can optionally have the translator create a makefile that you can use to build your program instead of building directly.
Using a makefile like this can be convenient if you want or need to alter the translated C code, or change compiling or
linking options before building your program. To do so:
$ euc - makefile myapp . ex
Translating code , pass : 1 2 3 4 generating

3. c files were created .


To build your project , type make -f myapp . mak

Then, as the message indicates, simply type:


$ make -f myapp . mak

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.

26.5 Dynamic Link Libraries


Simply by adding -dll (or -so) to the command line, the Translator will build a shared dynamically loading library
instead of an executable program.
You can translate and compile a set of useful Euphoria routines, and share them with other people, without giving them
your source. Furthermore, your routines will likely run much faster when translated and compiled. Both translated/compiled
and interpreted programs will be able to use your library.
Only the global Euphoria procedures and functions, i.e. those declared with the global, public or export
keyword, will be exported from the shared dynamically loaded library.
Any Euphoria program, whether translated or compiled or interpreted, can link with a Euphoria shared dynamically
loading library using the same mechanism that lets you link with a shared dynamically loading library written in C. The
program first calls open dll() to open the file, then it calls define c func() or define c proc() for any routines that it wants
to call. It calls these routines using c func() and c proc().
The routine names exported from a Euphoria shared dynamically loading library will vary depending on which C compiler
you use.
GNU C on Unix exports the names exactly as they appear in the C code produced by the Translator, e.g. a Euphoria
routine
global procedure foo ( integer x , integer y )

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.

26.6 Using Resource Files


When creating an executable file to deliver to your users on Windows, its best to link in a resource file that at minimum
sets your application icon but better if it sets product and version information.
When the resource compiler is launched by euc, a single macro is defined named SRCDIR. This can be used in your
resource files to reference your application source path for including other resource files, icon files, etc...
A simple resource file to attach an icon to your executable file is as simple as:
myapp ICON SRCDIR \ myapp . ico

Remember that SRCDIR will be expanded to your application source path.


A more complex resource file containing an icon and product/version information may look like:
1 VERSIONINFO

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

VALUE " InternalName " , " coolapp . exe \0"


VALUE " LegalCopyright " , " Copyright ( c ) 2022 by John Doe Computing \0"
VALUE " LegalTrademarks1 " , " Trademark Pending \0"
VALUE " LegalTrademarks2 " , "\0"
VALUE " OriginalFilename " , " coolapp . exe \0"
VALUE " ProductName " , " Cool Application \0"
VALUE " ProductVersion " , "4.0.0\0"
END
END
BLOCK " VarFileInfo "
BEGIN
VALUE " Translation " , 0 x409 , 1200
END
END

coolapp ICON SRCDIR \ coolapp . ico

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 "

to the end of your resource file. The coolapp.manifest file is:


<? xml version ="1.0" encoding =" UTF -8" standalone =" yes "? >
< assembly xmlns =" urn : schemas - microsoft - com : asm . v1 " manifestVersion ="1.0" >
< assemblyIdentity
version ="0.64.1.0"
p r o c e s s orArc hite cture =" x86 "
name =" euphoria "
type =" win32 "
/>
< dependency >
< dependentAssembly >
< assemblyIdentity
type =" win32 "
name =" Microsoft . Windows . Common - Controls "
version ="6.0.0.0"
pro cess orArc hite cture =" X86 "
publicKeyToken ="6595 b64144ccf1df "
language ="*"
/>
</ dependentAssembly >
</ dependency >
</ assembly >

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.

26.7 Executable Size and Compression


The translator does not compress your executable file. If you want to do this we suggest you try the free UPX compressor.
Large Win32Lib-based .exes produced by the Translator can be compressed by UPX to about 15% of their original
size, and you wont notice any difference in start-up time.
The Translator deletes routines that are not used, including those from the standard Euphoria include files. After
deleting unused routines, it checks again for more routines that have now become unused, and so on. This can make a
big difference, especially with Win32Lib-based programs where a large file is included, but many of the included routines
are not used in a given program.

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 Interpreter vs. Translator


All Euphoria programs can be translated to C, and with just a few exceptions noted below, will run the same as with the
Interpreter (but hopefully faster).
The Interpreter and Translator share the same parser, so you will get the same syntax errors, variable not declared
errors etc. with either one.
The Interpreter automatically expands the call stack (until memory is exhausted), so you can have a huge number
of levels of nested calls. Most C compilers, on most systems, have a pre-set limit on the size of the stack. Consult your
compiler or linker manual if you want to increase the limit, for example if you have a recursive routine that might need
thousands of levels of recursion. Modify the link command in your makefile, or use the -lflags option when calling the
translator. For Watcom C, use OPTION STACK=nnnn, where nnnn is the number of bytes of stack space.

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.9 Legal Restrictions


As far as RDS is concerned, any executable programs or shared dynamically loading libraries that you create with this
Translator without modifying an RDS translator library file, may be distributed royalty-free. You are free to incorporate
any Euphoria files provided by RDS into your application.
In general, if you wish to use Euphoria code written by 3rd parties, please honor any restrictions that apply. If in doubt,
you should ask for permission.
On Linux, FreeBSD, the GNU Library licence will normally not affect programs created with this Translator. Simply
compiling with GNU C does not give the Free Software Foundation any jurisdiction over your program. If you statically
link their libraries you will be subject to their Library licence, but the standard compile/link procedure does not statically
link any FSF libraries, so there should be no problem.

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 Frequently Asked Questions


26.11.1 How much of a speed-up should I expect?
It all depends on what your program spends its time doing. Programs that use mainly integer calculations, dont call
run-time routines very often, and dont do much I/O will see the greatest improvement, currently up to about 5x faster.
Other programs may see only a few percent improvement.
The various C compilers are not equal in optimization ability.

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.11.3 How can I make my program run even faster?


Its important to declare variables as integer where possible. In general, it helps if you choose the most restrictive type
possible when declaring a variable.
Typical user-defined types will not slow you down. Since your program is supposed to be free of type check errors,
types are ignored by the Translator, unless you call them directly with normal function calls. The one exception is when
a user-defined type routine has side-effects (i.e. it sets a global variable, performs pokes into memory, I/O etc.). In that
case, if with type check is in effect, the Translator will issue code to call the type routine and report any type check
failure that results.
On Windows we have left out the /ol loop optimization for Watcoms wcc386. We found in a couple of rare cases
that this option led to incorrect machine code being emitted by the Watcom C compiler. If you add it back in to your
own makefile you might get a slight improvement in speed, with a slight risk of buggy code.
On Linux or FreeBSD you could try the -O3 option of gcc instead of -O2. It will in-line small routines, improving
speed slightly, but creating a larger executable. You could also try the Intel C++ Compiler for Linux. Its compatible with
GNU C, but some adjustments to your makefile might be required.

26.12 Common Problems


Many large programs have been successfully translated and compiled using each of the supported C compilers, and the
Translator is now quite stable.

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.

27.1 Indirect calling a routine coded in Euphoria


The following applies to any routine coded in Euphoria that your program uses, whether it is defined in the standard library,
any third party library or your own code. It does not apply to routines implemented in the backend.

27.1.1 Getting a routine identifier


Whenever a routine is in scope, you can supply its name to the builtin routine id() function, which returns a small
integer:
include get . e
constant value_id = routine_id ( " value " )

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.

27.1.2 Calling Euphoria routines by id


This is very similar to using c func() or c proc() to interface with external code.

Calling a function

This is done as follows:


result = call_func ( id_of_the_routine , argument_sequence )

where

id of the routine is an id you obtained from routine id().

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

3 constant value_id = routine_id ( " value " )


4 result = call_func ( value_id , { " Model 36 A " , 6 , GET_LONG_ANSWER })
5 -- result is { GET_SUCCESS , 36 , 4 , 1}

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

3 constant pretty_id = routine_id ( " pretty_print " )


4

5 call_proc ( pretty_id ,{1 , some_object , some_options })

This does the same as a straightforward


include std / pretty . e

pretty_print (1 , some_object , some_options )

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.

27.1.3 Why call indirectly?


Calling functions and procedures indirectly can seem more complicated and slower than just calling the routine directly,
but indirect calls can be used when the name of the routine you want to call might not be known until run-time.
1 integer foo_id
2

3 function bar ( integer x )


4 return call_func ( foo_id ,{ x })
5 end function
6

7 function foo_dev1 ( integer y )


8 return y + 1
9 end function
10

11 function foo_dev2 ( integer y )


12 return y - 1
13 end function
14

15 function foo_dev3 ( integer y )


16 return y * y - 3
17 end function
18

19 function user_opt ( object x )


20 ...
21 end function
22

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.

27.2 Calling Euphorias internals


A number of Euphoria routines are defined in different ways depending on the platform they will run on. It would be
cumbersome, and at times downright impossible, to put such code in include files or to make the routine fully builtin.
A solution to this is provided by machine func() and machine proc(). User code normally never needs to use these.
Various examples are to be found in the standard library.
These primitives are called like this:
machine_proc ( id , argument )
result = machine_func ( id , argument )

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.

28.2 Why Multitask?


Most programs do not need to use multitasking and would not benefit from it. However it is very useful in some cases:
Action games where numerous characters, projectiles etc. need to be displayed in a realistic way, as if they are all
independent of one another. Language War is a good example.
Situations where your program must sometimes wait for input from a human or other computer. While one task in
your program is waiting, another separate task could be doing some computation, disk search, etc.
All operating systems today have special API routines that let you initiate some I/O, and then proceed without
waiting for it to finish. A task could check periodically to see if the I/O is finished, while another task is performing
some useful computation, or is perhaps starting another I/O operation.
Situations where your program might be called upon to serve many users simultaneously. With multiple tasks, its
easy to keep track of the state of your interaction with all these separate users.
Perhaps you can divide your program into two logical processes, and have a task for each. One produces data and
stores it, while the other reads the data and processes it. Maybe the first process is time-critical, since it interacts
with the user, while the second process can be executed during lulls in the action, where the user is thinking or doing
something that doesnt require quick response.

28.3 Types of Tasks


Euphoria supports two types of tasks: real-time tasks, and time-share tasks.
Real-time tasks are scheduled at intervals, specified by a number of seconds or fractions of a second. You might
schedule one real-time task to be activated every 3 seconds, while another is activated every 0.1 seconds. In Language
War, when the Euphoria ship moves at warp 4, or a torpedo flies across the screen, its important that they move at a
steady, timed pace.
Time-share tasks need a share of the CPU but they neednt be rigidly scheduled according to any clock.
Its possible to reschedule a task at any time, changing its timing or its slice of the CPU. You can even convert a task
from one type to the other dynamically.

130
CHAPTER 28. MULTITASKING IN EUPHORIA 28.4. A SMALL EXAMPLE

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.

1 constant TRUE = 1 , FALSE = 0


2

3 type boolean ( integer x )


4 return x = 0 or x = 1
5 end type
6

7 boolean t1_running , t2_running


8

9 procedure task1 ( sequence message )


10 for i = 1 to 10 do
11 printf (1 , " task1 (% d ) % s \ n " , {i , message })
12 task_yield ()
13 end for
14 t1_running = FALSE
15 end procedure
16

17 procedure task2 ( sequence message )


18 for i = 1 to 10 do
19 printf (1 , " task2 (% d ) % s \ n " , {i , message })
20 task_yield ()
21 end for
22 t2_running = FALSE
23 end procedure
24

25 puts (1 , " main task : start \ n " )


26

27 atom t1 , t2
28

29 t1 = task_create ( routine_id ( " task1 " ) , { " Hello " })


30 t2 = task_create ( routine_id ( " task2 " ) , { " Goodbye " })
31

32 task_schedule ( t1 , {2.5 , 3})


33 task_schedule ( t2 , {5 , 5.1})
34

35 t1_running = TRUE
36 t2_running = TRUE
37

38 while t1_running or t2_running do


39 if get_key () = q then
40 exit
41 end if
42 task_yield ()
43 end while
44

45 puts (1 , " main task : stop \ n " )


46 -- program ends when main task is finished

131
CHAPTER 28. MULTITASKING IN EUPHORIA 28.5. COMPARISON WITH EARLIER MULTITASKING SCHEMES

28.5 Comparison with earlier multitasking schemes


In earlier releases of Euphoria, Language War already had a mechanism for multitasking, and some people submitted to
User Contributions their own multitasking schemes. These were all implemented using plain Euphoria code, whereas this
new multitasking feature is built into the interpreter. Under the old Language War tasking scheme a scheduler would
*call* a task, which would eventually have to *return* to the scheduler, so it could then dispatch the next task.
In the new system, a task can call the built-in procedure task yield() at any point, perhaps many levels deep in
subroutine calls, and the scheduler, which is now part of the interpreter, will be able to transfer control to any other task.
When control comes back to the original task, it will resume execution at the statement after task yield(), with its call
stack and all private variables intact. Each task has its own call stack, program counter (i.e. current statement being
executed), and private variables. You might have several tasks all executing a routine at the same time, and each task will
have its own set of private variable values for that routine. Global and local variables are shared between tasks.
Its fairly easy to take any piece of code and run it as a task. Just insert a few task yield() statements so it wont hog
the CPU.

28.6 Comparison with multithreading


When people talk about threads, they are usually referring to a mechanism provided by the operating system. Thats
why we prefer to use the term multitasking. Threads are generally preemptive, whereas Euphoria multitasking is
cooperative. With preemptive threads, the operating system can force a switch from one thread to another at virtually
any time. With cooperative multitasking, each task decides when to give up the CPU and let another task get control. If
a task were greedy it could keep the CPU for itself for long intervals. However since a program is written by one person
or group that wants the program to behave well, it would be silly for them to favor one task like that. They will try to
balance things in a way that works well for the user. An operating system might be running many threads, and many
programs, that were written by different people, and it would be useful to enforce a reasonable degree of sharing on these
programs. Preemption makes sense across the whole operating system. It makes far less sense within one program.
Furthermore, threading is notorious for causing subtle bugs. Nasty things can happen when a task loses control at
just the wrong moment. It may have been updating a global variable when it loses control and leaves that variable in an
inconsistent state. Something as trivial as incrementing a variable can go awry if a thread-switch happens at the wrong
moment. e.g. consider two threads. One has:
x = x + 1

and the other also has:


x = x + 1

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.

29.2 Structure of an EDS database


In EDS, a database is a single file with a .edb file extension. An EDS database contains zero or more tables. Each table
has a name, and contains zero or more records. Each record consists of a key part, and a data part. The key can be
any Euphoria objectan atom, a sequence, a deeply-nested sequence, whatever. Similarly the data can be any Euphoria
object. There are no constraints on the size or structure of the key or data. Within a given table, the keys are all unique.
That is, no two records in the same table can have the same key part.
The records of a table are stored in ascending order of key value. An efficient binary search is used when you refer to
a record by key. You can also access a record directly, with no search, if you know its current record number within the
table. Record numbers are integers from one to the length (current number of records) of the table. By incrementing the
record number, you can efficiently step through all the records, in order of key. Note however that a records number can
change whenever a new record is inserted, or an existing record is deleted.
The keys and data parts are stored in a compact form, but no accuracy is lost when saving or restoring floating-point
numbers or any other Euphoria data.
std/eds.e will work as is, on all platforms. EDS database files can be copied and shared between programs running
on all platforms as well. When sharing EDS database files, be sure to make an exact byte-for-byte copy using binary
mode copying, rather than text or ASCII mode, which could change the line terminators.
Example:
database : " mydata . edb "
first table : " passwords "
record #1: key : " jones " data : " euphor123 "
record #2: key : " smith " data : " billgates "

second table : " parts "


record #1: key : 134525 data : {" hammer " , 15.95 , 500}
record #2: key : 134526 data : {" saw " , 25.95 , 100}
record #3: key : 134530 data : {" screw driver " , 5.50 , 1500}

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.3 How to access the data


To reduce the number of parameters that you have to pass, there is a notion of the current database, and current table.

29.3.1 The current database.


Any data operation or table operation assumes there is a current database being defined. You set the current database by
opening, creating or selecting a database. Deleting the current database leaves the current database undefined.

29.3.2 The current table.


All data operations assume there is a current table being defined. You must create, select or rename a table in order to
make it current. Deleting the current table leaves the current table undefined.

29.3.3 Accessing data


Most routines use these current values automatically. You normally start by opening (or creating) a database file, then
selecting the table that you want to work with.
You can map a key to a record number using db find key. It uses an efficient binary search. Most of the other
record-level routines expect the record number as a parameter. You can very quickly access any record, given its number.
You can access all the records by starting at record number one and looping through to the record number returned by
db table size.

29.4 How does storage get recycled?


When you delete something, such as a record, the space for that item gets put on a free list, for future use. Adjacent free
areas are combined into larger free areas. When more space is needed, and no suitable space is found on the free list, the
file will grow in size. Currently there is no automatic way that a file will shrink in size, but you can use a db compress to
completely rewrite a database, removing the unused spaces.

29.5 Security / Multi-user Access


This release provides a simple way to lock an entire database to prevent unsafe access by other processes.

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.7 EDS API


More details on using EDS, including complete coverage of the EDS API, can be found at Euphoria Database (EDS).

29.8 Disclaimer
Do not store valuable data without a backup. RDS will not be responsible for any damage or data loss.

29.9 Warning: Use the right file mode


.edb files are binary files, not text files. You must use BINARY mode when transferring a .edb file via FTP from one
machine to another. You must also avoid loading a .edb file into an editor and saving it. If you open a .edb file directly
using Euphorias open(), which is not recommended, you must use binary mode, not text mode. Failure to follow these
rules could result in 10 (line-feed) and 13 (carriage-return) bytes being changed, leading to subtle and not-so-subtle forms
of corruption in your database.

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.

30.1 A Quick Example


The problem in this case is that you want the copyright statement and the about screen to show what date the program
was compiled on but you do not want to manually maintain this date. So, we are going to create a simple pre-processor
that will read a source file, replace all instances of @DATE@ with the current date and then write the output back out.
Before we get started, let me say that we will expand on this example later on. Up front, we are going to do almost no
error checking for the purpose of showing off the pre-processor not for the sake of making a production quality application.
We are going to name this file datesub.ex.
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

6 sequence cmds = command_line ()


7 sequence inFileName , outFileName
8

9 for i = 3 to length ( cmds ) do


10 switch cmds [ i ] do
11 case " -i " then
12 inFileName = cmds [ i +1]
13 case " -o " then

136
CHAPTER 30. THE USER DEFINED PRE-PROCESSOR 30.2. PRE-PROCESS DETAILS

14 outFileName = cmds [ i +1]


15 end switch
16 end for
17

18 sequence content = read_file ( inFileName )


19

20 content = match_replace ( " @DATE@ " , content , format ( now ()))


21

22 write_file ( outFileName , content )


23

24 -- programs automatically exit with ZERO error code , if you want


25 -- non - zero , you exit with abort (1) , for example .

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

puts (1 , " The date this was run is @DATE@ \ n " )

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!

30.2 Pre-process Details


Euphoria manages when the pre-processor should be called and with what arguments. The pre-processor does not need
to concern itself as to if it should run, what filename it is reading or what filename it will be writing to. It should simply
do as Euphoria tells it to do. This is because Euphoria monitors what the modification time is on the source file and
what time the last pre-process call was made on the file. If nothing has changed in the source file then the pre-processor
is not called again. Pre-processing does have a slight penalty in speed as the file is processed twice. For example, the
datesub.ex pre-processor read the entire file, searched for @DATE@, wrote the file and then Euphoria picked up from there
reading the output file, parsing it and finally executing it. To minimize the time taken, Euphoria caches the output of the
pre-processor so that the interim process is not normally needed after it has been run once.

137
CHAPTER 30. THE USER DEFINED PRE-PROCESSOR 30.3. COMMAND LINE OPTIONS

30.3 Command Line Options


30.3.1 -p - Define a pre-processor
The primary command line option that you will use is the -p option which defines the pre-processor. It is a two or three
section option. The first section is a comma delimited list of file extensions to associate with the pre-processor, the second
is the actual pre-processor script/command and the optional third is parameters to send to the pre-processor in addition
to the -i and -o parameters.
Lets go over some examples:

-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.

Multiple pre-processors can be defined at the same time. For instance,


C :\ MyProjects \ datesub > eui -p e , ex : datesub . ex -p de , dex : dot4 . dll \
-p le , lex : literate . ex hello . ex

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

30.3.2 -pf - Force pre-processing


When writing a pre-processor you may run into the problem that your source file did not change, therefore, Euphoria is not
calling your pre-processor. However, your pre-processor has changed and you want Euphoria to re-process your unchanged
source file. This is where -pf comes into play. -pf causes Euphoria to force the pre-processing, regardless of the cached
state of any file. When used, Euphoria will always call the pre-processor for all files with a matching pre-processor definition.

30.3.3 Use of a configuration file


Ok, so who wants to type these pre-processor definitions in all the time? I dont either. Thats where the standard Euphoria
configuration file comes into play. You can simply create a file named eu.cfg and place something like this into it.
-p le , lex : literate . ex
-p e , ex : datesub . ex
... etc ...

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.

30.4 DLL/Shared Library Interface


A pre-processor may be a Euphoria file, ending with an extension of .ex, a compiled Euphoria program, .exe or even a
compiled Euphoria DLL file, .dll. The only requirements are that it must accept the two command line options, -i and
-o described above and exit with a ZERO status code on success or non-ZERO on failure.
The DLL file (or shared library on Unixes) has a real benefit in that with each file that needs to be pre-processed does
not require a new process to be spawned as with an executable or a Euphoria script. Once you have the pre-processor
written and functioning, its easy to convert your script to use the more advanced, better performing shared library method.
Lets do that now with our datesub.ex pre-processor. Take a moment to review the code above for the datesub.ex
program before continuing. This will allow you to more easily see the changes that we make here.

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

6 public function preprocess ( sequence inFileName , sequence outFileName ,


7 sequence options ={})
8

9 sequence content = read_file ( inFileName )


10

11 content = match_replace ( " @DATE@ " , content , format ( now ()))


12

13 write_file ( outFileName , content )


14

15 return 0
16 end function
17

18 ifdef not EUC_DLL then


19 sequence cmds = command_line ()
20 sequence inFileName , outFileName
21

22 for i = 3 to length ( cmds ) do


23 switch cmds [ i ] do
24 case " -i " then
25 inFileName = cmds [ i +1]
26 case " -o " then
27 outFileName = cmds [ i +1]
28 end switch
29 end for
30

31 preprocess ( inFileName , outFileName )


32 end ifdef

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:

1. inFileName - filename to read from

2. outFileName - filename to write to

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,

C :\ MyProjects \ datesub > euc - dll datesub . ex

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,

C :\ MyProjects \ datesub > eui -p e , ex : datesub . dll thedate . ex

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

30.5 Advanced Examples


30.5.1 Finish datesub.ex
Before we move totally away from our datesub.ex example, lets finish it off by adding some finishing touches and
making use of optional parameters. Again, please go back and look at the Shared Library version of datesub.ex before
continuning so that you can see how we have changed things.

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

12 public function preprocess ( sequence inFileName , sequence outFileName ,


13 sequence options ={})
14 map opts = cmd_parse ( cmdopts , options )
15 sequence content = read_file ( inFileName )
16

17 content = match_replace ( " @DATE@ " , content , format ( now () , map : get ( opts ,
18 " f " )))
19

20 write_file ( outFileName , content )


21

22 return 0
23 end function
24

25 ifdef not EUC_DLL then


26 cmdopts = {
27 { " i " , 0 , " Input filename " , { NO_CASE , MANDATORY , HAS_PARAMETER ,
28 " filename " } } ,
29 { " o " , 0 , " Output filename " , { NO_CASE , MANDATORY , HAS_PARAMETER ,
30 " filename " } }
31 } & cmdopts
32

33 map opts = cmd_parse ( cmdopts )


34 preprocess ( map : get ( opts , " i " ) , map : get ( opts , " o " ) ,
35 " -f " & map : get ( opts , " f " , " %Y -% m -% d " ))
36 end ifdef

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

Other examples of pre-processors include


eSQL - Allows you to include a .sql file directly. It parses CREATE TABLE and CREATE INDEX statements building
common methods to create, destroy, get by id, find by any index, add, remove and save entities.

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

2. Check the list of common problems (Common Problems and Solutions).

3. Read the relevant parts of the documentation, i.e. Euphoria Programming Language v4.0 or API Reference.

4. Try running your program with trace:

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.

2. Post a message on the forum.

3. Visit the Euphoria IRC channel, irc://irc.freenode.net/#euphoria.

31.1 Common Problems and Solutions


Here are some commonly reported problems and their solutions.

31.1.1 Console window disappeared


I ran my program with euiw. exe and the console window disappeared before I could read the output.
The console window will only appear if required, and will disappear immediately when your program finishes execution.
Perhaps you should code something like:
puts (1 , " \ nPress Enter \ n " )
if getc (0) then
end if

at the end of your program.


You may also run your console program with eui.exe.

142
CHAPTER 31. EUPHORIA TROUBLE-SHOOTING GUIDE 31.1. COMMON PROBLEMS AND SOLUTIONS

31.1.2 Press Enter


At the end of execution of my program, I see Press Enter and I have to hit the Enter key. How do I get rid of that?
Call free console just before your program terminates.
include dll . e

free_console ()

31.1.3 CGI Program Hangs / No Output


My Euphoria CGI program hangs or has no output

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.

31.1.4 Read / Write Ports?


How do I read/write ports?
There are collections of machine-level routines from the Euphoria Web Page.

31.1.5 Program has no errors, no output


When I run my program there are no errors but nothing happens.
You probably forgot to call your main procedure. You need a top-level statement that comes after your main procedure
to call the main procedure and start execution.

31.1.6 Routine not declared


Im trying to call a routine documented in library. doc , but it keeps saying the routine has not been declared.
Did you remember to include the necessary .e file from the euphoria\include directory? If the syntax of the routine
says for example, include\std\graphics.e, then your program must have include\std\graphics.e (without
the quotes) before the place where you first call the routine.

31.1.7 Routine not declared, my file


I have an include file with a routine in it that I want to call, but when I try to call the routine it says the routine has not
been declared. But it has been declared.
Did you remember to define the routine as public, export or possibly global? If not, the routine is not visible
outside of its own file.

143
CHAPTER 31. EUPHORIA TROUBLE-SHOOTING GUIDE 31.1. COMMON PROBLEMS AND SOLUTIONS

31.1.8 After user input, left margin problem


After inputting a string from the user with gets (), the next line that comes out on the screen does not start at the left
margin.
Your program should output a new-line character e.g.
input = gets ()
puts ( SCREEN , \ n )

31.1.9 Floating-point calculations not exact


Why arent my floating-point calculations coming out exact?
Intel CPUs, and most other CPUs, use binary numbers to represent fractions. Decimal fractions such as 0.1, 0.01 and
similar numbers cant be represented precisely. For example, 0.1 might be stored internally as 0.0999999999999999. That
means that 10 * 0.1 might come out as 0.999999999999999, and floor(10 * 0.1) might be 0, not 1 as youd expect. This
can be a nuisance when you are dealing with money calculations, but its not a Euphoria problem. Its a general problem
that you must face in most programming languages. Always remember: floating-point numbers are just an approximation
to the real numbers in mathematics. Assume that any floating-point calculation might have a tiny bit of error in the
result. Sometimes you can solve the problem by rounding, e.g. x = round( x, 100 ) would round x off to the nearest
hundredth. Storing money values as an integer number of pennies, rather than a fractional number of dollars (or similar
currency) will help, but some calculations could still cause problems.

31.1.10 Number to a string?


How do I convert a number to a string?
Use sprintf:
string = eu : sprintf ( " % d " , 10) -- string is "10"

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).

31.1.11 String to a number?


How do I convert a string to a number?
Use value.

31.1.12 Redefine my for-loop variable?


It says Im attempting to redefine my for-loop variable.
For-loop variables are declared automatically. Apparently you already have a declaration with the same name earlier in
your routine or your program. Remove that earlier declaration or change the name of your loop variable.

31.1.13 Unknown Escape Character


I get the message unknown escape character on a line where I am trying to specify a file name.
Do not say "C:\TMP\MYFILE". You need to say "C:\\TMP\\MYFILE" or use back-quotes C:\TMP\MYFILE.
Backslash is used for escape characters such as \n or \t. To specify a single backslash in a string you need to type
\\. Therefore, say "C:\\TMP\\MYFILE" instead of "C:\TMP\MYFILE"

144
CHAPTER 31. EUPHORIA TROUBLE-SHOOTING GUIDE 31.1. COMMON PROBLEMS AND SOLUTIONS

31.1.14 Only first character in printf


Im trying to print a string using but only the first character comes out.
You need to put braces around the parameters sequence to printf. You probably wrote:
printf (1 , " Hello , % s !\ n " , mystring )

but you need:


printf (1 , " Hello , % s !\ n " , { mystring })

31.1.15 Only 10 significant digits during printing


When I print numbers using or only 10 significant digits are displayed.
Euphoria normally only shows about 10 digits. Internally, all calculations are performed using at least 15 significant
digits. To see more digits you have to use printf. For example,
printf (1 , " %.15 f " , 1/3)

This will display 15 digits.

31.1.16 A type is expected here


It complains about my routine declaration, saying, a type is expected here.
When declaring subroutine parameters, Euphoria requires you to provide an explicit type for each individual parameter.
e.g.
procedure foo ( integer x , y ) -- WRONG
procedure foo ( integer x , integer y ) -- RIGHT

In all other contexts it is ok to make a list:


atom a , b , c , d , e

31.1.17 Expected to see...


It says: Syntax Error - expected to see possibly xxx, not yyy
At this point in your program you have typed a variable, keyword, number or punctuation symbol, yyy, that does not
fit syntactically with what has come before it. The compiler is offering you one example, xxx, of something that would
be accepted at this point in place of yyy. Note that there may be many other legal (and much better) possibilities at this
point than xxx, but xxx might at least give you a clue as to what the compiler is thinking.

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

Another way is to use parse-time evaluation using ifdefs.


1 ifdef WINDOWS then
2 -- Windows code
3 elsifdef LINUX then
4 -- LINUX code
5 elsifdef FREEBSD or NETBSD then
6 -- BSD code
7 elsedef
8 crash ( " Unsupported platform " )
9 end ifdef

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

15 elsifdef WINDOWS then


16

17 public constant SLASH = \\


18 public constant SLASHES = " \\/: "
19 public constant EOLSEP = " \ r \ n "
20 public constant PATHSEP = ;
21 public constant NULLDEVICE = " NUL : "
22 public constant SHARED_LIB_EXT = " dll "
23

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.

32.2 The Discontinued DOS32 Platform


This platform is no longer supported.
Those interested in writing DOS programs in Euphoria may use version 3.1 downloadable from the original RapidE-
uphoria website: http://www.rapideuphoria.com/v20.htm.
The DOS32 platform was for computers without Windows OS, and though people could still use the Euphoria binaries
built for this platform on Windows, it was slower than and lacked features available on binaries built for the WINDOWS
platform.
The binaries for this platform had support for low-level graphics and though DOS was 16-bit, the Euphoria binaries for
DOS32 used techniques that allowed you to use 32-bit addresses transparently, hence the name of the platform: DOS32.
However, in this platform you could not use dynamically loaded libraries and filenames had to be in a format of: eight
letters, a dot, and three letters when creating a file. You could not use the Windowing system even if your computer had
Windows. You were limited to full-sreen mode graphics and the text console.

32.3 The WINDOWS Platform


With the WINDOWS platform, your programs can still use the text console . Because most library routines work the same
way on each platform most text mode programs can be run using the console interpreter of any platform without any
change.
Since the Euphoria interpreter can work directly with your OS you can also create GUI programs. You can use a
user submitted library from the archive or handle calls directly into the DLLs. There are high-level graphics libraries for
Direct3D and OpenGL available from the Euphoria Web site.
A console window will be created automatically when a WINDOWS Euphoria program first outputs something to the
screen or reads from the keyboard. If your program is displaying a screen, you will also see a console window when you
read standard input or write to standard output, even when these have been redirected to files. The console will disappear
when your program finishes execution, or via a call to free console.
If you dont want a console to appear, it might help to put the following statements at the top of your Euphoria
program:
-- Now , when there is input or output to the console we will get an error
-- and see in which line number this happens .
close ( STDOUT )
close ( STDIN )

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

any_key ( " Press any key to close this Window " )

which will wait for the user enters something.


If you want to run an interpreted Euphoria program to use the current console use eui.exe but if you want it to create
a new console window use euiw.exe.
Programs translated by the translator for this platform will also pop up a new console whenever input is asked for our
output is sent to the screen unless you specify the -CON option.
When running an interpreter or translator for the WINDOWS platform, platform returns WINDOWS and a parsetime
branch (with ifdef/end ifdef) with WINDOWS will be followed.
In order to use sockets you must have Windows 2000 Professional or later. In order for the the routines has console
and maybe any key to have useful behavior you must have Windows XP or later.

32.3.1 High-Level WINDOWS Programming


Thanks to David Cuny, Derek Parnell, Judith Evans and many others, theres a package called Win32Lib that you
can use to develop Windows GUI applications in Euphoria. Its remarkably easy to learn and use, and comes with good
documentation and many small example programs.
If you have a SVN client, you can get a Euphoria version 4.0-compatible Win32lib at: https://win32libex.svn.sourceforge.net/svnroot/
Get version 68.
There is also an IDE, by Judith Evans for use with Win32lib. https://euvide.svn.sourceforge.net/svnroot/euvide.
Matt Lewis has developed a wrapper for the wxWidgets library for Euphoria: wxEuphoria. It is cross-platform.
You can download WxEuphoria, Win32Lib and Judiths IDE from the Euphoria Web site.

32.3.2 Low-Level WINDOWS Programming


To allow access to WINDOWS at a lower level, Euphoria provides a mechanism for calling any C function in any WINDOWS
API .dll file, or indeed in any 32-bit Windows .dll file that you create or someone else creates. There is also a call-back
mechanism that lets Windows call your Euphoria routines. Call-backs are necessary when you create a graphical user
interface.
To make full use of the WINDOWS platform, you need documentation on 32-bit Windows programming, in particular
the WINDOWS Application Program Interface (API), including the C structures defined by the API. There is a large
WINDOWS.HLP file (c) Microsoft that is available with many programming tools for Windows. There are numerous
books available on the subject of WINDOWS programming for C/C++. You can adapt most of what you find in those
books to the world of Euphoria programming for WINDOWS. A good book is Programming Windows by Charles Petzold.
A WINDOWS API Windows help file (8 Mb) can be downloaded from ftp://ftp.borland.com/pub/delphi/techpubs/delphi2/win32.zip
Borlands Web site.

32.4 The Unix Platforms


As with WINDOWS, you can write text on a console, or xterm window, in multiple colors and at any line or column
position.
Just as in WINDOWS, you can call C routines in shared libraries and C code can call back to your Euphoria routines.
You can get a Euphoria interface to high level graphics library OpenGL from the Euphoria Web site. OpenGL also
works with Windows.
Easy X-windows GUI programming is available using either Irv Mullins EuGTK interface to the GTK GUI library, or
wxEuphoria developed by Matt Lewis. wxEuphoria also runs on Windows.

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.

32.5 Interfacing with C Code


On WINDOWS and Unix its possible to interface Euphoria code with C code. Your Euphoria program can call C routines
and read and write C variables. C routines can even call (callback) your Euphoria routines. The C code must reside
in a dynamic link or shared library. By interfacing with dynamic link libraries and shared libraries, you can access the full
programming interface on these systems.
Using the Euphoria to C Translator, you can translate Euphoria routines to C, and compile them into a shared library
file. You can pass Euphoria atoms and sequences to these compiled Euphoria routines, and receive Euphoria data as a
result. Translated/compiled routines typically run much faster than interpreted routines. For more information, see the
Translator.

32.5.1 Calling C Functions


To call a C function in a shared library file you must perform the following steps:
1. Open the shared library file that contains the C function by calling open dll.
2. Define the C function, by calling define c func or define c proc. This tells Euphoria the number and type of the
arguments as well as the type of value returned.
Euphoria currently supports all C integer and pointer types as arguments and return values. It also supports floating-
point arguments and return values (C double type). It is currently not possible to pass C structures by value or
receive a structure as a function result, although you can certainly pass a pointer to a structure and get a pointer
to a structure as a return value. Passing C structures by value is rarely required for operating system calls.
Euphoria also supports all forms of Euphoria data - atoms and arbitrarily-complex sequences, as arguments to
translated/compiled Euphoria routines.
3. Call the C function by calling c func or c proc

1 include dll . e
2

3 atom user32
4 integer LoadIcon , icon

150
CHAPTER 32. PLATFORM SPECIFIC ISSUES 32.5. INTERFACING WITH C CODE

6 user32 = open_dll ( " user32 . dll " )


7

8 -- The name of the routine in user32 . dll is " LoadIconA ".


9 -- It takes a pointer and an 32 - bit integers as arguments ,
10 -- and it returns a 32 - bit integer .
11 LoadIcon = define_c_func ( user32 , " LoadIconA " , { C_POINTER , C_INT } , C_INT )
12

13 icon = c_func ( LoadIcon , { NULL , IDI_APPLICATION })

See c func, c proc, define c func, define c proc, open dll


See demo\win32 or demo/linux for example programs.
On Windows there is more than one C calling convention. The Windows API routines all use the stdcall convention.
Most C compilers however have cdecl as their default. cdecl allows for variable numbers of arguments to be passed.
Euphoria assumes stdcall, but if you need to call a C routine that uses cdecl, you can put a + sign at the start of
the routine name in define c proc() and define c func(). In the example above, you would have +LoadIconA, instead
of LoadIconA.
You can examine a dll file by right-clicking on it, and choosing QuickView (if its on your system). You will see a
list of all the C routines that the dll exports.
To find out which .dll file contains a particular WINDOWS C function, run Euphoria\demo\win32\dsearch.exw

32.5.2 Accessing C Variables


You can get the address of a C variable using define c var. You can then use poke and peek to access the value of the
variable.

32.5.3 Accessing C Structures


Many C routines require that you pass pointers to structures. You can simulate C structures using allocated blocks of
memory. The address returned by allocate can be passed as if it were a C pointer.
You can read and write members of C structures using peek and poke, or peek4u, peek4s, and poke4. You can allocate
space for structures using allocate.
You must calculate the offset of a member of a C structure. This is usually easy, because anything in C that needs 4 bytes
will be assigned 4 bytes in the structure. Thus C ints, chars, unsigned ints, pointers to anything, etc. will all take 4
bytes. If the C declaration looks like:
// Warning C code ahead !

struct example {
int a ; // offset 0
char * b ; // offset 4
char c ; // offset 8
long d ; // offset 12
};

To allocate space for struct example you would need:


atom p = allocate (16) -- size of " struct example "

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 )

You can read a field with something like:


d = peek4 ( p +12)

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

7 atom rect = allocate ( RECT_SIZEOF )


8

9 poke4 ( rect + RECT_LEFT , 10)


10 poke4 ( rect + RECT_TOP , 20)
11 poke4 ( rect + RECT_RIGHT , 90)
12 poke4 ( rect + RECT_BOTTOM , 100)
13

14 -- pass rect as a pointer to a C structure


15 -- hWnd is a " handle " to the window
16 if not c_func ( InvalidateRect , { hWnd , rect , 1}) then
17 puts (2 , " InvalidateRect failed \ n " )
18 end if

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.

32.5.4 Call-backs to your Euphoria routines


When you create a window, the Windows operating system will need to call your Euphoria routine. To set this up, you must
get a 32-bit call-back address for your routine and give it to Windows. For example (taken from demo\win32\window.exw):
1 integer id
2 atom WndProcAddress
3

4 id = routine_id ( " WndProc " )


5

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

33.1 General Tips


If your program is fast enough, forget about speeding it up. Just make it simple and readable.

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:

if x > 20 and y = 0 then


...
end if

The y = 0 test will only be made when x > 20 is true.


For maximum speed, you can order your tests. Do x > 20 first if it is more likely to be false than y = 0.
In general, with a condition A and B, Euphoria will not evaluate the expression B, when A is false (zero). Similarly, with
a condition like A or B, B will not be evaluated when A is true (non-zero).
Simple if-statements are highly optimized. With the current version of the interpreter, nested simple ifs that compare
integers are usually a bit faster than a single short-circuit if-statement e.g.:
1 if x > 20 then
2 if y = 0 then
3 ...
4 end if
5 end if

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

is exactly the same as:


y = x * 1000

where youve previously defined:


constant MAX = 1000

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.

33.2 Measuring Performance


In any programming language, and especially in Euphoria, you really have to make measurements before drawing
conclusions about performance.
Euphoria provides both execution-count profiling, as well as time profiling. You will often be surprised by the results
of these profiles. Concentrate your efforts on the places in your program that are using a high percentage of the total time
(or at least are executed a large number of times.) Theres no point to rewriting a section of code that uses 0.01% of the
total time. Usually there will be one place, or just a few places where code tweaking will make a significant difference.
You can also measure the speed of code by using the time() function. e.g.
1 atom t = time ()
2 for i = 1 to 10000 do
3 -- small chunk of code here
4 end for
5 ? time () - t

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

33.3 How to Speed-Up Loops


Profiling will show you the hot spots in your program. These are usually inside loops. Look at each calculation inside the
loop and ask yourself if it really needs to happen every time through the loop, or could it be done just once, prior to the
loop.

33.4 Converting Multiplies to Adds in a Loop


Addition is faster than multiplication. Sometimes you can replace a multiplication by the loop variable, with an addition.
Something like:
for i = 0 to 199 do
poke ( screen_memory + i *320 , 0)
end for

becomes:
1 x = screen_memory
2 for i = 0 to 199 do
3 poke (x , 0)
4 x = x + 320
5 end for

33.5 Saving Results in Variables


Its faster to save the result of a calculation in a variable, than it is to recalculate it later. Even something as simple
as a subscript operation, or adding 1 to a variable is worth saving.

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.

33.6 In-lining of Routine Calls


If you have a routine that is rather small, the interpreter and translator will in-line it for you. Your code will remain as
readable as before.

156
CHAPTER 33. PERFORMANCE TIPS 33.7. OPERATIONS ON SEQUENCES

33.7 Operations on Sequences


Euphoria lets you operate on a large sequence of data using a single statement. This saves you from writing a loop where
you process one element at-a-time. e.g.
x = {1 ,3 ,5 ,7 ,9}
y = {2 ,4 ,6 ,8 ,10}
z = x + y

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.

33.8 Some Special Case Optimizations


Euphoria automatically optimizes certain special cases. x and y below could be variables or arbitrary expressions.
1 x + 1 -- faster than general x + y
2 1 + x -- faster than general y + x
3 x * 2 -- faster than general x * y
4 2 * x -- faster than general y * x
5 x / 2 -- faster than general x / y
6 floor ( x / y ) -- where x and y are integers , is faster than x / y
7 floor ( x /2) -- faster than floor ( x / y )

x below is a simple variable, y is any variable or expression:


1 x = append (x , y ) -- faster than general z = append (x , y )
2 x = prepend (x , y ) -- faster than general z = prepend (x , y )
3

4 x = x & y -- where x is much larger than y ,


5 -- is faster than general z = x & y

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.)

33.9 Assignment with Operators


For greater speed, convert:
** left - hand - side = left - hand - side op expression **

to:

157
CHAPTER 33. PERFORMANCE TIPS 33.10. LIBRARY / BUILT-IN ROUTINES

** left - hand - side op = expression **

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).

33.10 Library / Built-In Routines


Some common routines are extremely fast. You probably couldnt do the job faster any other way, even if you used C or
assembly language. Some of these are:

33.10.1 Low Level Memory Manipulation


mem copy
mem set

33.10.2 Sequence Manipulation


append
head
insert
remove
repeat
replace
splice
tail
Other routines are reasonably fast, but you might be able to do the job faster in some cases if speed was crucial.
x = repeat (0 ,100) -- Pre - allocate all the elements first .
for i = 1 to 100 do
x[i] = i
end for

is somewhat faster than:


x = {}
for i = 1 to 100 do
x = append (x , i )
end for

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

33.10.3 Bitwise operations vs Arithmetic


You can replace:
remainder (x , p )

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.

33.13 Taking Advantage of Cache Memory


As CPU speeds increase, the gap between the speed of the on-chip cache memory and the speed of the main memory or
DRAM (dynamic random access memory) becomes ever greater. You might have 256 Mb of DRAM on your computer, but
the on-chip cache is likely to be only 8K (data) plus 8K (instructions) on a Pentium, or 16K (data) plus 16K (instructions)
on a Pentium with MMX or a Pentium II/III. Most machines will also have a level-2 cache of 256K or 512K.
An algorithm that steps through a long sequence of a couple of thousand elements or more, many times, from beginning
to end, performing one small operation on each element, will not make good use of the on-chip data cache. It might be
better to go through once, applying several operations to each element, before moving on to the next element. The same
argument holds when your program starts swapping, and the least-recently-used data is moved out to disk.
These cache effects arent as noticeable in Euphoria as they are in lower-level compiled languages, but they are
measurable.

33.14 Using Machine Code and C


Euphoria lets you call routines written in machine code. You can call C routines in dynamically loaded library files, and
these C routines can call your Euphoria routines. You might need to call C or machine code because of something that
can not be done directly in Euphoria, or you might do it for improved speed.
To boost speed, the machine code or C routine needs to do a significant amount of work on each call, otherwise the
overhead of setting up the arguments and making the call will dominate the time, and it might not gain you much.
Many programs have some inner core operation that consumes most of the CPU time. If you can code this in C or
machine code, while leaving the bulk of the program in Euphoria, you might achieve a speed comparable to C, without
sacrificing Euphorias safety and flexibility.

159
CHAPTER 33. PERFORMANCE TIPS 33.15. USING THE EUPHORIA TO C TRANSLATOR

33.15 Using The Euphoria To C Translator


The Euphoria To C Translator is included in the installation package. It will translate any Euphoria program into a set of
C source files that you can compile using a C compiler.
The executable file that you get using the Translator should run the same, but faster than when you use the interpreter.
The speed-up can be anywhere from a few percent to a factor of 5 or more.

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.

34.2 The eutest Program


34.2.1 Synopsis for running the tests

eutest [ - D NO_INET ] [ - D NO_INET_TESTS ]


[ - verbose ] [ - log ] [ - i include path ] [ - cc wat | gcc ] [ - exe interpreter ]
[ - ec translator ] [ - lib binary library path ]
[ optional list of unit test files ]

34.2.2 Synopsis for creating report from the log

eutest - process - log [ - html ]

34.2.3 General behavior


If you want to test translation of your tests as well as interpreted tests, you can specify it with -ec.
If you dont specify unit tests on the command line eutest will scan the directory for unit test files using the pattern
t *.e. If you specify a pattern it will interpret the pattern, as some shells do not do this for programs.

34.2.4 Options detail


-D REC: Is for creating control files, use only when on tests that work already on an interpreter that correctly works
or correctly *fails* with them. This option must come before the eutest.ex program itself in the command line
and is the option with that requirement.

-log: Is for creating a log file for later processing

-verbose: Is for eutest.ex to give you detail of what it is doing

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.

-html: Is for making the report creation to be in 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.

-D NO INET TESTS: See NO INET

34.3 The Unit Test Files


Unit test files must match a pattern t *.e. If the unit test file matches t c *.e the test program will expect the program
to fail, if there is an error control file in a directory with its same name and d extension it will also expect it to fail
according to the control files contents found in the said directory. Such a failure is marked as a successful test run.
However, if there is no such directory or file the counter test will be marked as a failed test run.

34.3.1 A trivial example


The following is a minimal unit test file:
include std / unittest . e

test_report ()

Please see the Unit Testing Framework, for information on how to construct these files.

34.4 The Error Control Files


There are times when we expect something to fail. We want good EUPHORIA code to do the correct thing and there is a
correct thing to do also for *bad* code. The interpreter must return with an error message of why it failed and the error
must be correct and it must get written to ex.err. We must thus check the ex.err file to see if it has the correct error
message.
If the unit test is t foo.e then the location for its control file can be in the following locations:

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.

34.5 Test Coverage


When writing and evaluating the results of unit tests, it is important to understand which parts of your code are and are
not being tested. The Euphoria interpreter has a built in capability to instrument your code to analyze how many times
each line of your code is executed during your suite of tests. The data is output into an EDS database. Euphoria also
comes with a coverage data post-processor that generates html reports to make analysis of your coverage easy.
The coverage capabilities can be used manually, with arguments supplied on the command line, or passed to eutest.
Indeed, eutest simply passes these along to the interpreter. The Euphoria suite of unit tests can be run via the makefiles,
and there is a special target to run a coverage analysis of the standard library:
Windows :
> wmake coverage

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.

34.5.1 Coverage Command Line Switches


-coverage [file|dir] This specifies what files to gather stats for. If you supply a directory, it recurses on child
directories. Only files that are obviously Euphoria are included ( .e, .ew, .eu, .ex, .exw, .exu).

-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.

34.5.2 Coverage Post-Processing


Once you have run tests to generate a coverage database, the data is not easily viewed. Euphoria comes with a post-
processor called eucoverage.ex, which is installed in the bin directory. On a Unix packaged install, you should be able
to simply use eucoverage, which is configured to run eucoverage.ex.
The post-processor generates an index page, with coverage stats for each file, and individual html files, linked from
the index page, for each file analyzed for test coverage. At the file level, statistics are presented for total and executed
routines and lines of code. The files are sorted in descending order of lines that were never executed, in order to highlight
the parts of your code that are less tested. The page for each file shows this information, as well as a similar breakdown
by routine, displaying the number of lines in each routine that was executed. The routines are also sorted in descending
order by the most unexecuted lines.
Additionally, the source of the file is displayed below the statistics. The routines are linked to their place in the code.
Each line is colored either green red or white. White lines are those that are not executed. These are typically blank,

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.

Command Line Switches


-o <dir> Specify the output directory. The default is to create a subdirectory, from the same directory as the
coverage database, with the name of the base filename (without extension) of the coverage database.

-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.

35.1 Documentation tags


Documentation is embedded in source-code using the Euphoria line ( ) comments. Two special tags, --**** and --**
distinguish documentation from comments that will not be extracted.

35.2 Generic documentation


Generic documentation starts with the ( --**** ) tag, continues with lines starting with -- in the first column, and
ends with the next blank line. The tags and -- will not appear in the documentation.
1 -- ****
2 -- generic text , thus tagged , will be extracted by eudoc
3 -- write your documentation here ...
4 --
5

6 -- blank line is a terminator , this line is not included

Produces...
generic text , thus tagged , will be extracted by eudoc
write your documentation here ...

35.3 Source documentation


Source documentation starts with the ( --** ) tag. Locate them before a routine or identifier that you wish to be
described in your documentation. The eudoc program will extract the signature of a routine and combines it with the

166
CHAPTER 35. EUDOC - SOURCE DOCUMENTATION TOOL 35.4. ASSEMBLY FILE

comments that you write after this tag.


Starting with the source-code file favorite.ex:
1 -- **
2 -- this is my favorite routine
3

4 public procedure hello ( sequence name )


5 printf (1 , " Hello % s ! " , { name } )
6 end procedure

Executing eui eudoc -o foo.txt favorite.ex produces:


%% disallow ={ camelcase }

!! CONTEXT : favorite . ex

@ [ hello |]
==== hello
< eucode >
include favorite . ex
public procedure hello ( sequence name )
</ eucode >

This is my favorite routine .

Process with eui creole foo.txt:


include favorite . ex
public procedure hello ( sequence name )

This is my favorite routine.


If you examine the source-code included with Euphoria you will realize how these steps were used to create the
documentation you are reading now.

35.4 Assembly file


Large projects are managed using an assembly file, which is a list of files (source-code, and external) that will be
incorporated into one output file. Look at euphoria/docs/manual.af for the file used to produce this documentation.

35.5 Creole markup


Creole is a text markup language used in wikis, such as the Euphoria Wiki, and for documenting source-code.
Common Creole tags are:

= Title

== Section

// italic // ** bold ** ## fixed ##

* 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

< eucode >


-- euphoria code is colorized
for i =1 to 5 do
? i
end for
</ eucode >

The previous tags will produce html that looks like...

Title **

Section **

italic bold fixed


bullet
lists are

easy to produce
tables are
easy to produce with bold headers
-- euphoria code is colorized
for i =1 to 5 do
? i
end for

More details can be found at the Euphoria Wiki under CreoleHelp.

35.6 Documentation software


The programs required for creating documentation are hosted on our Mercurial SCM server at http://scm.openeuphoria.org.
eudoc: http://scm.openeuphoria.org/hg/eudoc
creole: http://scm.openeuphoria.org/hg/creole
More on using eudoc
More on using Creole markup
The program htmldoc is found at... http://www.htmldoc.org/ and http://htmldoc-binaries.org/.
For LaTeX on Windows, we suggest MiKTeX found at... http://miktex.org/ For those on Linux, you should be able
to install via your package manager.

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.

36.3 Special Keys


Some PC keys do not work in a Linux or FreeBSD or Windows text console, or in Telnet, and some keys do not work in
an xterm under X windows. Alternate keys have been provided. In some cases you might have to edit ed.ex to map the
desired key to the desired function. e.g. youll have to use C-t and C-b instead of C-Home and C-End.

169
CHAPTER 36. ED - EUPHORIA EDITOR 36.4. ESCAPE COMMANDS

Delete Delete the current character above the cursor


Backspace Move the cursor to the left and delete a character
C-Delete Delete the current line (not available on all platforms)
C-d Delete the current line (same as C-Delete)
Insert re-insert the preceding series of Deletes before the current
line/character
C-Left Move to the start of the previous word. On Unix, use C-l
C-Right Move to the start of the next word. On Unix, use C-r
Home Move to the beginning of the current line
End Move to the end of the current line
C-Home Move to the beginning of the file (euid.exe only, others use
C-t
C-End Move to the end of the file (euid.exe only, others use C-b
PgUp Move up one screen. On Unix use C-u
PgDn Move down one screen. On Unix use C-p
F1..F10 Select a new window. The windows are numbered from
top to bottom with the top window on the screen being
F1
F12 User definable key (see CUSTOM KEYSTROKES near top of
ed.ex. Default action is to insert -- for a Euphoria com-
ment

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

h Get help text for the editor, or Euphoria. The screen is


split so you can view your program and the help text at
the same time.
c Clone the current window, i.e. make a new edit window
that is initially viewing the same file at the same position as
the current window. The sizes of all windows are adjusted
to make room for the new window. You might want to
use Esc l to get more lines on the screen. Each window
that you create can be scrolled independently and each has
its own menu bar. The changes that you make to a file
will initially appear only in the current window. When you
press an F-key to select a new window, any changes will
appear there as well. You can use Esc n to read a new file
into any window.
q Quit (delete) the current window and leave the editor if
there are no more windows. Youll be warned if this is the
last window used for editing a modified file. Any remaining
windows are given more space.
s Save the file being edited in the current window, then quit
the current window as Esc q above.
w Save the file but do not quit the window.
e Save the file, and then execute it with euid, euiw or eui.
When the program finishes execution youll hear a beep.
Hit Enter to return to the editor. This operation may not
work if you are very low on extended memory. You cant
supply any command-line arguments to the program.
d Run an operating system command. After the beep, hit
Enter to return to the editor. You could also use this
command to edit another file and then return, but Esc c
is probably more convenient.
n Start editing a new file in the current window. Deleted
lines/chars and search strings are available for use in the
new file. You must type in the path to the new file. Al-
ternatively, you can drag a file name from a Windows file
manager window into the console window for ed. This will
type the full path for you.
f Find the next occurrence of a string in the current win-
dow. When you type in a new string there is an option to
match case or not. Press y if you require upper/lower
case to match. Keep hitting Enter to find subsequent
occurrences. Any other key stops the search. To search
from the beginning, press C-Home before Esc f. The de-
fault string to search for, if you dont type anything, is
shown in double quotes.
r Globally replace one string by another. Operates like Esc f
command. Keep hitting Enter to continue replacing. Be
careful - there is no way to skip over a possible replace-
ment.
l Change the number of lines displayed on the screen. Only
certain values are allowed, depending on your video card.
Many cards will allow 25, 28, 43 and 50 lines. In a Lin-
ux/FreeBSD text console youre stuck with the number
of lines available (usually 25). In a Linux/FreeBSD xterm
window, ed will use the number of lines initially available
when ed is started up. Changing the size of the window
will have no effect after ed is started.
171
m Show the modifications that youve made so far. The cur-
rent edit buffer is saved as editbuff.tmp, and is com-
pared with the file on disk using the Windows fc com-
CHAPTER 36. ED - EUPHORIA EDITOR 36.5. RECALLING PREVIOUS STRINGS

36.5 Recalling Previous Strings


The Esc n, Esc d, Esc r and Esc f commands prompt you to enter a string. You can recall and edit these strings just as
you would at the command line. Type up-arrow or down-arrow to cycle through strings that you previously entered for a
given command, then use left-arrow, right-arrow and the delete key to edit the strings. Press Enter to submit the string.

36.6 Cutting and Pasting


When you C-Delete (or C-d) a series of consecutive lines, or Delete a series of consecutive characters, you create a
kill-buffer containing what you just deleted. This kill-buffer can be re-inserted by moving the cursor and then pressing
Insert.
A new kill-buffer is started, and the old buffer is lost, each time you move away and start deleting somewhere else.
For example, cut a series of lines with C-Delete. Then move the cursor to where you want to paste the lines and press
Insert. If you want to copy the lines, without destroying the original text, first C-Delete them, then immediately press
Insert to re-insert them. Then move somewhere else and press Insert to insert them again, as many times as you like. You
can also Delete a series of individual characters, move the cursor, and then paste the deleted characters somewhere else.
Immediately press Insert after deleting if you want to copy without removing the original characters.
Once you have a kill-buffer, you can type Esc n to read in a new file, or you can press an F-key to select a new edit
window. You can then insert your kill-buffer.

36.7 Use of Tabs


The standard tab width is 8 spaces. The editor assumes tab=8 for most files. However, it is more convenient when editing
a program for a tab to equal the amount of space that you like to indent. Therefore you will find that tabs are set to
4 when you edit Euphoria files (or .c, or .h or .bas files). The editor converts from tab=8 to tab=4 when reading your
program file, and converts back to tab=8 when you save the file. Thus your file remains compatible with the tab=8 world.
If you would like to choose a different number of spaces to indent, change the line at the top of ed.ex that says
constant PROG INDENT = 4.

36.8 Long Lines


Lines that extend beyond the right edge of the screen are marked with an inverse video character in the 80th column.
This warns you that there is more text out there that you cant see. You can move the cursor beyond the 80th column.
The screen will scroll left or right so the cursor position is always visible.

36.9 Maximum File Size


Like any Euphoria program, ed can access all the memory on your machine. It can edit huge files, and unless disk swapping
occurs, most operations will be very fast.

36.10 Non-text Files


ed is designed for editing pure text files, although you can use it to view other files. As ed reads in a file, it replaces
certain non-printable characters (less than ASCII 14) with ASCII 254 - small square. If you try to save a non-text file you
will be warned about this. Since ed opens all files as text files, a control-z character (26) embedded in a file will appear
to ed to be the end of the file.

172
CHAPTER 36. ED - EUPHORIA EDITOR 36.11. LINE TERMINATOR

36.11 Line Terminator


The end-of-line terminator on Linux/FreeBSD/OSX/OPENBSD/NETBSD is simply \n. On Windows, text files have lines
ending with \r\n. If you copy a Windows file to Linux/FreeBSD and try to modify it, ed will give you a choice of either
keeping the \r\n terminators, or saving the file with \n terminators.

36.12 Source Code


The complete source code to this editor is in bin\ed.ex and bin\syncolor.e. You are welcome to make improvements.
There is a section at the top of ed.ex containing user-modifiable configuration parameters that you can adjust. The
colors and the cursor size may need adjusting for some operating environments.

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.

.hash Details about symbol hashing.

.line Line table information. Unless tracing is enabled, this will be blank.

37.2 HTML Output


eudis can output html documentation of your program somewhat similar to the output from Doxygen. This documentation
is different than eudoc. It is meant to document the structure of your program, and to help developers understand code
dependencies. It can generate graphs showing how files include each other, as well as which routines call which others.
Note that generating graphs requires that you have Graphviz installed. Note that generating call graphs can be quite time
consuming for a large program.
By default, eudis will create a subdirectory in the current directory called eudox. This may be changed using the
--dir option.

37.2.1 Command Line Switches


You can use the standard -i and -c switches with eudis. There are additional options:

-b parse the code as though it were being bound

174
CHAPTER 37. EUDIS - DISASSEMBLING EUPHORIA CODE 37.2. HTML OUTPUT

--dir <dir> Specify the output directory for the html files

-f include a particular file in the html output


output the list of files included in the .dis file at the top of the listing
-g suppress call graphs in html output
--html generate html documentation of your program

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.

38.2 Command Line Switches


You can use the standard -i and -c switches with eudist. There are additional options:

--clear Clear the output directory before copying files


-d <dir> Specify the output directory for the files
-e <file> --exclude-file <file> Exclude a file from being copied

-ed <dir> --exclude-directory <file> Exclude a directory from being copied


-edr <dir> --exclude-directory-recursively <file> Exclude a directory and all subdirectories from being
copied

176
Part VIII

API Reference

177
Chapter 39
Built-in Methods

These methods are built into Euphoria and require no includes.


? abort and bits append
arctan atom c func c proc
call call func call proc clear screen
close command line compare cos
date delete delete routine equal
find floor get key getc
getenv gets hash head
include paths insert integer length
log machine func machine proc match
mem copy mem set not bits object
open option switches or bits peek
peek2s peek2u peek4s peek4u
peek string peeks pixel platform
poke poke2 poke4 position
power prepend print printf
puts rand remainder remove
repeat replace routine id sequence
sin splice sprintf sqrt
system system exec tail tan
task clock start task clock stop task create task list
task schedule task self task status task suspend
task yield time trace xor bits

178
Chapter 40
Command Line Handling

40.1 Constants
40.1.1 NO PARAMETER

include std / cmdline . e


namespace cmdline
public constant NO_PARAMETER

This option switch does not have a parameter. See cmd parse

40.1.2 HAS PARAMETER

include std / cmdline . e


namespace cmdline
public constant HAS_PARAMETER

This option switch does have a parameter. See cmd parse

40.1.3 NO CASE

include std / cmdline . e


namespace cmdline
public constant NO_CASE

This option switch is not case sensitive. See cmd parse

40.1.4 HAS CASE

include std / cmdline . e


namespace cmdline
public constant HAS_CASE

This option switch is case sensitive. See cmd parse

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.

40.1.11 HELP RID


include std / cmdline . e
namespace cmdline
public enum HELP_RID

Additional help routine id. See cmd parse

180
CHAPTER 40. COMMAND LINE HANDLING 40.1. CONSTANTS

40.1.12 VALIDATE ALL

include std / cmdline . e


namespace cmdline
public enum VALIDATE_ALL

Validate all parameters (default). See cmd parse

40.1.13 NO VALIDATION

include std / cmdline . e


namespace cmdline
public enum NO_VALIDATION

Do not cause an error for an invalid parameter. See cmd parse

40.1.14 NO VALIDATION AFTER FIRST EXTRA

include std / cmdline . e


namespace cmdline
public enum N O _ V A L I D A T I O N _ A F T E R _ F I R S T _ E X T R A

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.

40.1.15 SHOW ONLY OPTIONS

include std / cmdline . e


namespace cmdline
public enum SHOW_ONLY_OPTIONS

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

include std / cmdline . e


namespace cmdline
public enum 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.

40.1.18 PAUSE MSG


include std / cmdline . e
namespace cmdline
public enum PAUSE_MSG

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

Disable the automatic inclusion of -h, -? and help as help switches.

40.1.20 NO HELP ON ERROR


include std / cmdline . e
namespace cmdline
public enum NO_HELP_ON_ERROR

Disable the automatic display of all of the possible options on error.

40.1.21 OPT IDX


include std / cmdline . e
namespace cmdline
public enum OPT_IDX

An index into the opts list. See cmd parse

40.1.22 OPT CNT


include std / cmdline . e
namespace cmdline
public enum OPT_CNT

The number of times that the routine has been called by cmd parse for this option. See cmd parse

40.1.23 OPT VAL


include std / cmdline . e
namespace cmdline
public enum OPT_VAL

The options value as found on the command line. See cmd parse

182
CHAPTER 40. COMMAND LINE HANDLING 40.2. ROUTINES

40.1.24 OPT REV

include std / cmdline . e


namespace cmdline
public enum OPT_REV

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

include std / cmdline . e


namespace cmdline
public constant 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

< built - in > function 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

10 " myfile . dat " ,


11 " 12345 " ,
12 " the end "
13 }
14

15 -- Note that all arguments remain the same as example 1


16 -- except for the first two . The second argument is always
17 -- the same as the first and is inserted to keep the numbering
18 -- of the subsequent arguments the same , whether your program
19 -- is bound or translated as a . exe , or not .

See Also:

build commandline, option switches, getenv, cmd parse, show help

40.2.2 option switches

< built - in > function option_switches ()

Retrieves the list of switches passed to the interpreter on the command line.

Returns:

A sequence, of strings, each containing a word related to switches.

Comments:

All switches are recorded in upper case.

Example 1:

euiw -d helLo
-- will result in
-- option_switches () being {" - D " ," helLo "}

See Also:

Command line switches

184
CHAPTER 40. COMMAND LINE HANDLING 40.2. ROUTINES

40.2.3 show help

include std / cmdline . e


namespace cmdline
public procedure show_help ( sequence opts , object add_help_rid = - 1 ,
sequence cmds = command_line () , object parse_options = {})

Show help message for the given opts.

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

Creates a file containing an analysis of the weather .


The analysis includes temperature and rainfall data
for the past week .

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

>> Creates a file containing an analysis of the weather . <<


>> The analysis includes temperature and rainfall data <<
>> for the past week . <<

40.2.4 cmd parse


include std / cmdline . e
namespace cmdline
public function cmd_parse ( sequence opts , object parse_options = {} ,
sequence cmds = command_line ())

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