home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-04-14 | 77.2 KB | 2,015 lines |
-
- Euphoria Programming Language
- version 1.2
- Reference Manual
-
-
- (c) 1994 Rapid Deployment Software
-
- Permission is freely granted to anyone
- to copy this manual.
-
-
-
-
- TABLE OF CONTENTS
- =================
-
- 1. Introduction
-
- 1.1 Example Program
- 1.2 Installation
- 1.3 Running a Program
- 1.4 Editing a Program
- 1.5 Distributing a Program
-
- 2. Core Language
-
- 2.1 Objects
- 2.2 Expressions
- 2.3 Declarations
- 2.4 Statements
- 2.5 Top-Level Commands
-
- 3. Debugging
-
- 4. Built-in Routines
-
- 4.1 Predefined Types
- 4.2 Sequence Manipulation
- 4.3 Searching and Sorting
- 4.4 Math
- 4.5 File and Device I/O
- 4.6 Mouse Support
- 4.7 Operating System
- 4.8 Debugging
- 4.9 Graphics & Sound
- 4.10 Machine Level Interface
-
-
-
-
- 1. Introduction
- ===============
-
- Euphoria is a new programming language with the following advantages over
- conventional languages:
-
- o a remarkably simple, flexible, powerful language
- definition that is extremely easy to learn and use.
-
- o dynamic storage allocation. 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).
-
- o a high-performance, state-of-the-art interpreter that is
- 10 to 20 times faster than conventional interpreters such as
- Microsoft QBasic.
-
- o lightning-fast pre-compilation. Your program is checked
- for syntax and converted into an efficient internal form at
- over 12,000 lines per second on a 486-50.
-
- o extensive run-time checking for: out-of-bounds subscripts,
- uninitialized variables, bad parameter values for built-in
- functions, 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.
-
- o features of the underlying hardware are completely hidden.
- Programs are not aware of word-lengths, underlying bit-level
- representation of values, byte-order etc. Euphoria programs are
- therefore highly portable from one machine to another.
-
- o a full-screen source debugger and an execution profiler
- are included, along with a full-screen editor. 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.
-
- o Euphoria programs run under MS-DOS (or Windows), but are not
- subject to any 64K or 640K memory limitations. You can
- create programs that use the full multi-megabyte memory
- of your computer. You can even set up a swap file for
- programs that need more memory than exists on your machine.
- A least-recently-used paging algorithm will automatically
- shuffle pages of virtual memory in and out as your program
- executes.
-
- o 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 in the
- usual sense, yet it achieves many of the benefits of these
- languages in a much simpler way.
-
-
- 1.1 Example Program
- -------------------
-
- The following is an example of a complete Euphoria program.
-
-
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
- sequence list, sorted_list
-
- function merge_sort(sequence x)
- -- put x into ascending order using a recursive merge sort
- integer n, mid
- sequence merged, x1, x2
-
- n = length(x)
- if n = 0 or n = 1 then
- return x -- trivial case
- end if
-
- mid = floor(n/2)
- x1 = merge_sort(x[1..mid]) -- sort first half of x
- x2 = merge_sort(x[mid+1..n]) -- sort second half of x
-
- -- merge the two sorted halves into one
- merged = {}
- while length(x1) > 0 and length(x2) > 0 do
- if compare(x1[1], x2[1]) < 0 then
- merged = append(merged, x1[1])
- x1 = x1[2..length(x1)]
- else
- merged = append(merged, x2[1])
- x2 = x2[2..length(x2)]
- end if
- end while
- return merged & x1 & x2 -- merged data plus leftovers
- end function
-
- procedure print_sorted_list()
- -- generate sorted_list from list
- list = {9, 10, 3, 1, 4, 5, 8, 7, 6, 2}
- sorted_list = merge_sort(list)
- ? sorted_list
- end procedure
-
- print_sorted_list() -- this command starts the program
-
-
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-
- The above example contains 4 separate commands that are processed in order.
- The first declares two variables: list and sorted_list to be sequences.
- The second defines a function merge_sort(). The third defines a procedure
- print_sorted_list(). The final command calls procedure print_sorted_list().
-
- The output from the program will be:
- {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}.
-
- merge_sort() will just as easily sort {1.5, -9, 1e6, 100} or
- {"oranges", "apples", "bananas"} .
-
- This example is stored as euphoria\demo\example.ex. This is not the fastest
- way to sort in Euphoria. Go into the euphoria\demo directory and type
- "ex allsorts" to see timings on several different sorting algorithms for
- increasing numbers of objects. For a quick tutorial on Euphoria programming
- see euphoria\demo\bench\filesort.ex.
-
-
- 1.2 Installation
- ----------------
-
- To install Euphoria on your machine, first read the file install.doc.
- Installation simply involves copying the euphoria files to your hard disk
- under a directory named "EUPHORIA", and then modifying your autoexec.bat file
- so that EUPHORIA\BIN is on your search path, and the environment variable
- EUDIR is set to the EUPHORIA directory. An automatic install program,
- "install.bat" is provided for this purpose. For the latest details, please
- read the instructions in install.doc before you run install.bat.
-
- When installed, the euphoria directory will look something like this:
-
- euphoria
- readme.doc
- \bin
- ex.exe, dos4gw.exe, ed.bat, other utilities
- \include
- standard include files, e.g. graphics.e
- \doc
- ed.doc, refman.doc etc.
- \demo
- demo programs, e.g. ttt.ex, mset.ex, plot3d.ex
- \learn
- test your knowledge of Euphoria
- \langwar
- language war game, lw.ex
- \bench
- benchmark programs
-
-
- 1.3 Running a Program
- ------------------------
-
- Euphoria programs are executed by typing "ex", followed by the name of the
- main (or only) file. By convention, main Euphoria files have an extension of
- ".ex". Other Euphoria files, that are meant to be included in a larger
- program, end in ".e". To save typing, you can leave off the ".ex", and
- the ex command will supply it for you automatically. If the file can't be
- found in the current directory, your PATH will be searched. There are no
- command-line options for ex itself, but your program can call the built-in
- function command_line() to read the ex command-line. You can redirect
- standard input and standard output when you run a Euphoria program,
- for example:
-
- ex filesort.ex < raw > sorted
-
- or simply,
-
- ex filesort < raw > sorted
-
- For frequently-used programs you might want to make a small .bat file
- containing something like:
-
- @echo off
- ex myprog.ex %1 %2
-
- where myprog.ex expects two command-line arguments. This will save you
- from typing ex all the time.
-
- ex.exe is in the euphoria\bin directory which must be on your search path.
- The file dos4gw.exe must also be present in the bin directory (or somewhere
- on the search path). Some Euphoria programs expect the environment variable
- EUDIR to be set to the main Euphoria directory.
-
- Running Under Windows
- ---------------------
- You can run Euphoria programs directly from the Windows environment, or from
- a DOS shell that you have opened from Windows. By "associating" .ex files
- with ex.exe, you can simply double-click on a .ex file to run it. It
- is possible to have several Euphoria programs active in different windows.
- You can resize these windows, move them around, change to a different font,
- run things in the background, copy and paste between windows etc. See your
- Windows manual. The Euphoria editor is available. You might want to
- associate .e, .pro and other text files with ed.bat. Also, the File-menu/
- Run-command will let you type in ex or ed command lines.
-
- Use of a swap file
- ------------------
- If your program requires more memory than is physically present on your
- machine, you can easily set up a swap file to provide extra "virtual"
- memory under DOS. All you have to do is define the environment variable
- DOS4GVM. The MS-DOS command: set DOS4GVM=1 will allow a 16 megabyte swap
- file to be created, which will be used as virtual memory. Portions of your
- program and data that have not been recently used will be copied out to this
- file to create room in physical memory for actively-used information. If you
- can't afford the default 16 megabytes of disk space, you could:
- set DOS4GVM=virtualsize#8192 to get an 8 megabyte swap file, or specify a
- smaller number if this is still too much. To turn off virtual memory,
- you can: set DOS4GVM= after your program has finished executing. The swap
- file can be deleted after execution, but leaving it in place will let your
- next program start up faster.
-
- When you run under Windows, virtual memory swapping will be performed
- by Windows itself, and you may actually get more memory than DOS (without
- swap file) would provide.
-
-
- 1.4 Editing a Program
- ---------------------
-
- You can use any text editor to edit a Euphoria program. However, Euphoria
- comes with its own special editor which is written entirely in Euphoria.
- Type ed followed by the complete name of the file you wish to edit (the
- .ex extension is not assumed). You can use this editor to edit any kind of
- text file. When you edit a .e or .ex 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.
-
- 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. See
- the file euphoria\doc\ed.doc for a complete description of the editing
- commands. Esc h (help) will let you view ed.doc from your editing session.
-
- If you need to understand or modify any detail of the editor's operation,
- you can edit the file ed.ex in euphoria\bin (be sure to make a backup
- copy so you don't 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.
-
-
- 1.5 Distributing a Program
- --------------------------
-
- Your customer needs to have the 2 files: ex.exe and dos4gw.exe somewhere
- on the search path. You are free to supply anyone with the Public Domain
- Edition of ex.exe, as well as dos4gw.exe to support it.
-
- Your program can be distributed in source form or in shrouded form. In source
- form you supply your Euphoria files plus any standard include files that are
- required. To deliver a program in shrouded form, you run the Euphoria source
- code shrouder, bin\shroud.ex, against your main Euphoria file. The shrouder
- pulls together all included files into a single compact file that is
- virtually unreadable. You then ship this one file plus a copy of ex.exe and
- dos4gw.exe. One copy of ex.exe and dos4gw.exe on a machine is sufficient to
- run any number of Euphoria programs. Comments in bin\shroud.ex tell you how
- to run it, and what it does to obscure or "shroud" your source.
-
-
-
- 2. The Core Language
- ====================
-
- 2.1 Objects
- -----------
-
- All data objects in Euphoria are either atoms or sequences. An atom is a
- single numeric value. A sequence is an ordered list of data objects.
- The objects contained in a sequence can be an arbitrary mix of atoms or
- sequences. A sequence is represented by a list of objects in brace brackets,
- separated by commas. Atoms can have any double-precision floating point value.
- This is approximately -1e300 to +1e300 with 15 decimal digits of accuracy.
- Here are some Euphoria objects:
-
- -- examples of atoms:
- 0
- 1000
- 98.6
- -1e6
-
- -- examples of sequences:
- {2, 3, 5, 7, 11, 13, 17, 19} -- 8-element sequence
- {1, 2, {3, 3, 3}, 4, {5, {6}}} -- 5-element sequence
- {{"jon", "smith"}, 52389, 97.25} -- 3-element sequence
- {} -- 0-element sequence
-
- Numbers can also be entered in hexadecimal. For example:
- #FE -- 254
- #A000 -- 40960
- #FFFF00008 -- 68718428168
- -#10 -- -16
-
- Sequences can be nested to any depth. Brace brackets are used to construct
- sequences out of a list of expressions. These expressions are evaluated at
- run-time. e.g.
-
- {x+6, 9, y*w+2, sin(0.5)}
-
- 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.
-
- Performance Note: Although atoms can have any double-precision value,
- integer-valued atoms are generally stored and manipulated as machine integers
- to save time and space.
-
-
- Character Strings
- -----------------
- Character strings may be entered using quotes e.g.
-
- "ABCDEFG"
-
- Strings are just sequences of characters, and may be manipulated and
- operated upon just like any other sequences. For example the above
- string is equivalent to the sequence
-
- {65, 66, 67, 68, 69, 70, 71}
-
- which contains the corresponding ASCII codes. Individual characters may be
- entered using single quotes if it is desired that they be treated as
- individual numbers (atoms) and not length-1 sequences. e.g.
-
- 'B' -- equivalent to the atom 66
- "B" -- equivalent to the sequence {66}
-
- Note 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.
-
- Special characters may be entered using a back-slash:
-
- \n newline
- \r carriage return
- \t tab
- \\ backslash
- \" double quote
- \' single quote
-
- For example, "Hello, World!\n", or '\\'. The Euphoria editor displays
- character strings in brown.
-
- Comments
- --------
- Comments are started by two dashes and extend to the end of the current line.
- e.g.
-
- -- this is a comment
-
- Comments are ignored by the compiler and have no effect on execution speed.
- The editor displays comments in red. In this manual we use italics.
-
-
- 2.2 Expressions
- ---------------
-
- Objects can be combined into expressions using binary and unary operators as
- well as built-in and user-defined functions. 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}. Besides + there are many other operators. The
- precedence of operators is as follows:
-
- highest precedence: function/type calls
-
- unary - not
-
- * /
-
- + -
-
- &
-
- < > <= >= = !=
-
- lowest precedence: and, or
-
- Thus 2+6*3 means 2+(6*3), not (2+6)*3. Operators on the same line above have
- equal precedence and are evaluated left to right.
-
-
- Relational & Logical Operators
- ------------------------------
- The relational operators, <, >, <=, >=, = , != each produce a 1 (true) or a
- 0 (false) result. These results can be used by the logical operators 'and',
- 'or', and 'not' to determine an overall truth value. e.g.
-
- b > 0 and b != 100 or not (c <= 5)
-
- where b and c are the names of variables.
-
-
- 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, 9, 11, 13} then x[2] is 7. Suppose we
- assign something different to x[2]:
-
- x[2] = {11,22,33}
-
- Then x becomes: {5, {11,22,33}, 9, 11, 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 simulated
- with a sequence of sequences:
-
- { {5, 6, 7, 8, 9},
- {1, 2, 3, 4, 5},
- {0, 1, 0, 1, 0} }
-
- 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 there is no simple expression to select an entire column.
- Other logical structures, such as n-dimensional arrays, arrays of strings,
- arrays of structures etc. can also be handled easily and flexibly.
-
- Note that expressions in general may not be subscripted, just variables. For
- example: {5,6,7,8}[3] is not supported.
-
-
- 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 length-0 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}.
-
- 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.
-
-
- Concatenation of Sequences and Atoms
- ------------------------------------
- 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 (where atoms are considered here to have length 1). e.g.
-
- {1, 2, 3} & 4 -- result is {1, 2, 3, 4}
-
- 4 & 5 -- result is {4, 5}
-
- {{1, 1}, 2, 3} & {4, 5} -- result is {{1, 1}, 2, 3, 4, 5}
-
- x = {}
- y = {1, 2}
- y = y & x -- y is still {1, 2}
-
-
- Arithmetic Operations on Sequences
- ----------------------------------
- Any binary or unary arithmetic operation, including any of the built-in
- math routines, may be applied to entire sequences as well as to single
- numbers.
-
- When applied to a sequence, a unary 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
- recursively. e.g.
-
- x = -{1, 2, 3, {4, 5}} -- x is {-1, -2, -3, {-4, -5}}
-
- If a binary 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.
-
- x = {5, 6, 7 {1, 1}} + {10, 10, 20, 100}
- -- x is {15, 16, 27, {101, 101}}
-
- 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:
-
- y = {4, 5, 6}
-
- w = 5 * y -- w is {20, 25, 30}
-
- x = {1, 2, 3}
-
- z = x + y -- z is {5, 7, 9}
-
- z = x < y -- z is {1, 1, 1}
-
- w = {{1, 2}, {3, 4}, {5}}
-
- w = w * y -- w is {{4, 8}, {15, 20}, {30}}
-
-
- Comparison of Euphoria Objects with Other Languages
- ---------------------------------------------------
- By basing Euphoria on this one, simple, general, recursive data structure,
- a tremendous amount of the complexity normally found in programming languages
- has been avoided. The arrays, record structures, unions, arrays of records,
- multidimensional arrays, etc. of other languages can all be easily
- simulated in Euphoria with sequences. So can higher-level structures such
- as lists, stacks, queues, trees etc.
-
- Furthermore, in Euphoria you can have sequences of mixed type; you can
- assign any object to an element of a sequence; and sequences easily grow or
- shrink in length without your having to worry about storage allocation issues.
- The exact layout of a data structure does not have to be declared in advance,
- and can change dynamically as required. It is easy to write generic code,
- where, for instance, you push or pop a mix of various kinds of data
- objects using a single stack.
-
- Data structure manipulations are very efficient since Euphoria will point to
- large data objects rather than copy them.
-
- Programming in Euphoria is based entirely on creating and manipulating
- flexible, dynamic sequences of data. Sequences are it - there are no
- other data structures to learn. You operate in a simple, safe, elastic world
- of *values*, that is far removed from the rigid, tedious, dangerous world
- of bits, bytes, pointers and machine crashes.
-
- Unlike other languages such as LISP and Smalltalk, Euphoria's
- "garbage collection" of unused storage is a continuous process that never
- causes random delays in execution of a program, and does not pre-allocate
- huge regions of memory.
-
- The language definitions of conventional languages such as C, C++, Ada, etc.
- are very complex. Most programmers become fluent in only a subset of the
- language. The ANSI standards for these languages read like complex legal
- documents.
-
- You are forced to write different code for different data types simply to
- copy the data, ask for its current length, concatenate it, compare it etc.
- The manuals for those languages are packed with routines such as "strcpy",
- "strncpy", "memcpy", "strcat", "strlen", "strcmp", "memcmp", etc. that
- each only work on one of the many types of data.
-
- Much of the complexity surrounds issues of data type. How do you define
- new types? Which types of data can be mixed? How do you convert one type
- into another in a way that will keep the compiler happy? When you need to
- do something requiring flexibility at runtime, you frequently find yourself
- trying to fake out the compiler.
-
- In these languages the numeric value 4 (for example) can have a different
- meaning depending on whether it is an int, a char, a short, a double, an
- int * etc.. In Euphoria, 4 is the atom 4, period. Euphoria has something
- called types as we shall see later, but it is a much simpler concept.
-
- Issues of dynamic storage allocation and deallocation consume a great deal
- of programmer coding time and debugging time in these other languages, and
- make the resulting programs much harder to understand.
-
- Pointer variables are extensively used. The pointer has been called the
- "go to" of data structures. It forces programmers to think of data as
- being bound to a fixed memory location where it can be manipulated in all
- sorts of low-level non-portable, tricky ways. A picture of the actual
- hardware that your program will run on is never far from your mind. Euphoria
- does not have pointers and does not need them.
-
-
- 2.3 Declarations
- ----------------
-
- Identifiers
- -----------
- Variable names and other user-defined symbols (identifiers) may be of any
- length. Upper and lower case are distinct. Identifiers must start with a
- letter and then be followed by letters, digits or underscores. The
- following reserved words have special meaning in Euphoria and may not be
- used as identifiers:
-
- and end include then
- by exit not to
- constant for or type
- do function procedure while
- else global profile with
- elsif if return without
-
- The Euphoria editor displays these words in blue. In this manual we use
- boldface.
-
- The following kinds of user-defined symbols may be declared in a program:
-
- o procedures
- These perform some computation and may have a list of parameters,
- e.g.
-
- procedure empty()
- end procedure
-
- procedure plot(integer x, integer y)
- position(x, y)
- puts(1, '*')
- 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.
-
- Performance Note: The interpreter does not copy sequences unless it
- becomes necessary. For example,
- y = {1,2,3,4,5,6,7}
- x = y
- The statement x = y does not cause the value of y to be copied.
- Both x and y will simply "point" to the same data. If we later perform
- x[3] = 9, then x will be given its own separate copy. The same thing
- applies to "copies" of arguments passed in to subroutines.
-
- o functions
- These are just like procedures, but they return a value, and can be
- used in an expression, e.g.
-
- function max(atom a, atom b)
- if a >= b then
- return a
- else
- return b
- end if
- end function
-
- Any Euphoria object can be returned. You can, in effect, have
- multiple return values, by returning a sequence of objects. e.g.
-
- return {quotient, remainder}
-
- We will use the general term "subroutine", or simply "routine" when a
- remark is applicable to both procedures and functions.
-
- o 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. They are discussed
- in more detail below.
-
- o variables
- These may be assigned values during execution e.g.
-
- integer x
- x = 25
-
- object a, b, c
- a = {}
- b = a
- c = 0
-
- o constants
- These are variables that are assigned an initial value that can
- never change e.g.
-
- constant MAX = 100
- constant upper = MAX - 10, lower = 5
-
- 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".
-
-
- Scope
- -----
- Every symbol must be declared before it is used. This is restrictive, but it
- has benefits. It means you always know in which direction to look for the
- definition of a subroutine or variable that is used at some point in the
- program. When looking at a subroutine definition, you know that there could
- not be a call to this routine from any routine defined earlier. In general,
- it forces you to organize your program into a hierarchy where there are
- distinct, "layers" of low-level , followed by higher-level routines. You
- can replace a layer without disrupting any lower layers.
-
- A symbol is defined from the point where it is declared to the end of its
- scope. The scope of a variable declared inside a procedure or function (a
- private variable) ends at the end of the procedure or function. The scope
- of all other constants, procedures, functions and variables ends at the end
- of the source file in which they are declared and they are referred to as
- local, unless the word global precedes their declaration, in which case their
- scope extends indefinitely. Procedures and functions can call themselves
- recursively.
-
- Constant declarations must be outside of any function or procedure.
-
- A special case is that of the controlling variable used in a for-loop. It is
- automatically declared at the beginning of the loop, and its scope ends at
- the end of the for loop. If the loop is inside a function or procedure, the
- loop variable is a private variable and may not have the same name as any
- other private variable. When the loop is at the top level, outside of any
- function or procedure, the loop variable is a local variable and may not have
- the same name as any other global or local variable in that file. You do not
- declare loop variables as you would other variables. The range of values
- specified in the for statement defines the legal values of the loop variable
- - specifying a type would be redundant and is not allowed.
-
-
- Specifying the type of a variable
- ---------------------------------
-
- Variable declarations have a type name followed by a list of
- the variables being declared. For example,
-
- object a
-
- global integer x, y, z
-
- procedure fred(sequence q, sequence r)
-
- In a parameter list like the one above, the type name may only be followed by
- a single variable name.
-
- The types: object, sequence, atom and integer are predefined. Variables of
- type object may take on any value. Those declared with type sequence must be
- always be sequences. Those declared with type atom must always be atoms. Those
- declared with type integer must be atoms with integer values from -1073709056
- to +1073709055 inclusive. You can perform exact calculations on larger integer
- values, up to about 15 decimal digits, but declare them as atom, rather than
- integer.
-
- Performance Note: Calculations using integer variables will usually be
- somewhat faster than calculations involving atom variables. If your
- machine has floating-point hardware, Euphoria will use it to manipulate
- atoms that aren't representable as integers, otherwise floating-point
- emulation routines contained in ex.exe are used.
-
- To augment the predefined types, you can create new 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,
-
-
- type hour(integer x)
- return x >= 0 and x <= 23
- end type
-
- hour h1, h2
-
- This guarantees that variables h1 and h2 can only be assigned integer values
- in the range 0 to 23 inclusive. After an assignment to h1 or h2 the
- interpreter will call "hour()", passing the new value. The parameter x will
- first be checked to see if it is an integer. 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.
-
- procedure set_time(hour h)
-
- set_time() above can only be called with a reasonable value for parameter h.
-
- A variable's 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 when 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. 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.
-
- Type checking can be turned off or on in between subroutines using the
- with type_check or without type_check commands. It is initially on by default.
-
- Note to Benchmarkers: 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, unless the other language provides a comparable
- amount of run-time checking. This gives Euphoria permission to skip runtime
- type checks, thereby saving some execution time. When type_check is off, 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.
- With or without type_check, you will never get a machine-level exception.
- You will always get a meaningful message from Euphoria when something goes
- wrong.
-
- Euphoria's method of defining types is much 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.
-
- Strict type definitions can greatly 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 much 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 weren't 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 isn't 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.
-
-
- 2.4 Statements
- --------------
-
- The following kinds of executable statements are available:
-
- o assignment statement
-
- o procedure call
-
- o if statement
-
- o while statement
-
- o for statement
-
- o return statement
-
- o exit statement
-
- Semicolons are not used in Euphoria, but you are free to put as many
- statements as you like on one line, or to split a single statement across
- many lines. You may not split a statement in the middle of a variable name,
- string, number or keyword.
-
- 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) -- repeat 0, 1000 times
-
- 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 Euphoria's dynamic storage allocation.
-
- A procedure call starts execution of a procedure, passing it an optional list
- of argument values. e.g.
-
- plot(x, 23)
-
- An if statement tests an expression to see if it is 0 (false) or non-zero
- (true) and then executes the appropriate series of statements. There may
- be optional elsif and else clauses. e.g.
-
- if a < b then
- x = 1
- end if
-
-
- if a = 9 then
- x = 4
- y = 5
- else
- z = 8
- end if
-
-
- if char = 'a' then
- x = 1
- elsif char = 'b' then
- x = 2
- elsif char = 'c' then
- x = 3
- else
- x = -1
- end if
-
- A while statement tests an expression to see if it is non-zero (true),
- and while it is true a loop is executed. e.g.
-
- while x > 0 do
- a = a * 2
- x = x - 1
- end while
-
- A for statement sets up a special loop with a controlling loop variable
- that runs from an initial value up or down to some final value. e.g.
-
- for i = 1 to 10 do
- print(1, i)
- end for
-
- for i = 10 to 20 by 2 do
- for j = 20 to 10 by -2 do
- print(1, {i, j})
- end for
- end for
-
- 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 when the loop is entered, and are not affected by anything that
- happens during the execution of the loop.
-
- A return statement returns from a subroutine. If the subroutine is a function
- or type then a value must also be returned. e.g.
-
- return
-
- return {50, "FRED", {}}
-
- An exit statement may appear inside a while loop or a for loop. It causes
- immediate termination of the loop, with control passing to the first statement
- after the loop. e.g.
-
- for i = 1 to 100 do
- if a[i] = x then
- location = i
- exit
- end if
- end for
-
- It is also quite common to see something like this:
-
- while TRUE do
- ...
- if some_condition then
- exit
- end if
- ...
- 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.
-
-
- 2.5 Top-Level Commands
- ----------------------
-
- Euphoria processes your .ex file in one pass, starting at the first line and
- proceeding through to the last line. When a procedure or function definition
- is encountered, the routine is checked for syntax and converted into an
- internal form, but no execution takes place. When a statement that is outside
- of any routine is encountered, it is checked for syntax, converted into an
- internal form and then immediately executed. If your .ex file contains only
- routine definitions, but no immediate execution statements, then nothing will
- happen when you try to run it (other than syntax checking). You need to have
- an immediate statement to call your main routine (see the example program in
- section 1.1). It is quite possible to have a .ex file with nothing but
- immediate statements, for example you might want to use Euphoria as a
- desk calculator, typing in just one print (or ? see below) statement into a
- file, and then executing it. The langwar demo program
- (euphoria\demo\langwar\lw.ex) quickly reads in and displays a file on the
- screen, before the rest of the program is compiled (on a 486 this makes
- little difference as the compiler takes less than a second to finish
- compiling the whole program). Another common practice is to immediately
- initialize a global variable, just after its declaration.
-
- The following special commands may only appear at the top level i.e.
- outside of any function or procedure. As we have seen, it is also
- possible to use any Euphoria statement, including for loops, while loops,
- if statements etc. (but not return), at the top level.
-
- include filename - reads in (compiles) a Euphoria source file in the presence
- of any global symbols that have already been defined.
- Global symbols defined in the included file remain visible
- in the remainder of the program. If an absolute pathname
- is given, Euphoria will use it. When a relative pathname
- is given, Euphoria will first look for filename in the
- same directory as the main file given on the ex command
- line. If it's not there, it will look in %EUDIR%\include,
- where EUDIR is the environment variable that must be set
- when using Euphoria. This directory contains the standard
- Euphoria include files.
-
- profile - outputs an execution profile showing the number of times
- each statement was executed. Only statements compiled
- with profile will be shown. The output is placed in the
- file ex.pro. View this file with the Euphoria editor to
- see a color display.
-
- with - turns on one of the compile options: profile, trace,
- warning or type_check. Options warning and type_check are
- initially on, while profile and trace are initially off.
- These are global options. For example if you have:
-
- without type_check
- include graphics.e
-
- then type checking will be turned off inside graphics.e as
- well as in the current file.
-
- without - turns off one of the above options. Note that each of
- these options may be turned on or off between subroutines
- but not inside of a subroutine.
-
-
- Redirecting Standard Input and Standard Output
- ----------------------------------------------
- Routines such as gets() and puts() can use standard input (file #0),
- standard output (file #1), and standard error output (file #2). Standard
- input and output can then be redirected as in:
-
- ex myprog < myinput > myoutput
-
- See section 4.5 for more details.
-
-
-
- 3. Debugging
- ============
-
-
- Debugging in Euphoria is much easier than in most other programming languages.
- The extensive runtime checking provided at all times by Euphoria automatically
- catches many bugs that in other languages might take hours of your time to
- track down. When Euphoria 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 always 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.
-
- 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 your variables is assigned an illegal
- value.
-
- Sometimes a program will misbehave without failing any runtime 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 recompile/relink.
-
- Euphoria provides you with additional powerful tools for debugging. You
- can trace the execution of your program source code on one screen while
- you witness the output of your program on another. with trace / without trace
- commands select the subroutines in your program that are available for tracing.
- Often you will simply insert a with trace command 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 don't
- 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 interactively skip over the execution of any routine by
- pressing down-arrow on the keyboard rather than Enter.
-
- Only traceable lines can appear in ex.err as "most-recently-executed lines"
- should a runtime error occur. If you want this information and didn't get it,
- you should insert a with trace and then rerun your program. Execution will
- be a bit slower when lines compiled with trace are executed.
-
- 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(1) statement. Again, you could simply say:
-
- with trace
- trace(1)
-
- 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(1) and
- trace(0) 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.
- type positive_int(integer x)
- if x = 99 then
- trace(1) -- how can this be???
- return 1 -- keep going
- else
- return x > 0
- end if
- end type
-
- You will then be able to 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 been happening up to this precise moment. If you make your
- special type return 0 for the strange value instead of 1, you can force a
- dump into ex.err.
-
- The Trace Screen
- ----------------
- When a trace(1) statement is executed, 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. 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:
-
- F1 - display main output screen - take a look at your program's 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 executed. This lets you skip
- over subroutine calls. It also lets you force your way out of
- repetitive loops.
-
- ? - display the value of a variable. Many variables are displayed
- automatically as they are assigned a value, but sometimes you will have
- to explicitly ask for one that is not on display. After hitting ?
- you will be prompted for the name of the variable. Variables that are
- not defined at this point cannot be shown. Variables that have not yet
- been initialized will have <NO VALUE> beside their name.
-
- q - quit tracing and resume normal execution. Tracing will start again when
- the next trace(1) is executed.
-
- ! - 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 trace screen adopts the same graphics mode as the main output screen.
- This makes flipping between them quicker 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
- gets() input. When get_key() (quickly samples the keyboard) is called you
- will be given 10 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().
-
-
-
-
- 4. Built-in Routines
- ====================
-
-
- Many built-in procedures and functions are provided. The names of these
- routines are not reserved. If a user-defined symbol has the same name, it
- will override the built-in routine until the end of scope of the
- user-defined symbol (you will get a suppressible warning about this). Some
- routines are written in Euphoria and you must include one of the .e files in
- euphoria\include to use them. Where this is the case, the appropriate include
- file is noted. The editor displays in magenta those routines that are part
- of the interpreter, ex.exe, and require no include file.
-
- To indicate what kind of object may be passed in and returned, the following
- prefixes are used:
-
- fn - an integer used as a file number
- a - an atom
- i - an integer
- s - a sequence
- st - a string sequence, or single-character atom
- x - a general object (atom or sequence)
-
- An error will result if an illegal argument value is passed to any of these
- routines.
-
-
- 4.1 Predefined Types
- --------------------
-
- As well as declaring variables with these types, you can also call them
- just like ordinary functions, in order to test if a value is a certain type.
-
-
- i = integer(x)
- Return 1 if x is an integer in the range -1073709056 to +1073709055.
- Otherwise return 0.
-
-
- i = atom(x)
- Return 1 if x is an atom else return 0.
-
-
- i = sequence(x)
- Return 1 if x is a sequence else return 0.
-
-
- 4.2 Sequence Manipulating Routines
- ----------------------------------
-
- i = length(s)
- Return the length of s. s must be a sequence. e.g.
-
- length({{1,2}, {3,4}, {5,6}}) -- 3
- length("") -- 0
- length({}) -- 0
-
- Notice that {} and "" both represent the empty sequence.
- As a matter of style, use "" when you are thinking of it as an
- empty string of characters. Use {} when it is an empty sequence
- in general.
-
-
- s = repeat(x, a)
- Create a sequence of length a where each element is x.
- e.g.
- repeat(0, 10) -- {0,0,0,0,0,0,0,0,0,0}
- repeat("JOHN", 4) -- {"JOHN", "JOHN", "JOHN", "JOHN"}
-
-
- s2 = append(s1, x)
- Append x to the end of sequence s1. The length of s2 will be
- length(s1) + 1. If x is an atom this is the same as
- s2 = s1 & x. If x is a sequence it is definitely not the same.
- You can use append to dynamically grow a sequence e.g.
-
- x = {}
- for i = 1 to 10 do
- x = append(x, i)
- end for
- -- x is now {1,2,3,4,5,6,7,8,9,10}
-
- The necessary storage is allocated automatically (and quite
- efficiently) with Euphoria's dynamic storage allocation. See also
- the gets() example in section 4.5.
-
-
- s2 = prepend(s1, x)
- Prepend x to the start of sequence s1. The length of s2 will be
- length(s1) + 1. If x is an atom this is the same as s2 = x & s1.
- If x is a sequence it is definitely not the same. e.g.
-
- prepend({1,2,3}, {0,0}) -- {{0,0}, 1, 2, 3}
- {0,0} & {1,2,3} -- {0, 0, 1, 2, 3}
-
-
- 4.3 Searching and Sorting
- -------------------------
-
- i = compare(x1, x2)
- Return 0 if objects x1 and x2 are identical, 1 if x1 is greater
- than x2, -1 if x1 is less than x2. Atoms are considered to be less
- than sequences. Sequences are compared "alphabetically" starting
- with the first element until a difference is found. e.g.
-
- compare("ABC", "ABCD") -- -1
-
-
- i = find(x, s)
- Find x as an element of s. If successful, return the first element
- number of s where there is a match. If unsuccessful return 0.
- Example:
-
- location = find(11, {5, 8, 11, 2, 3})
- -- location is set to 3
-
- names = {"fred", "rob", "george", "mary", ""}
- location = find("mary", names)
- -- location is set to 4
-
-
- i = match(s1, s2)
- Try to match s1 against some slice of s2. If successful, return
- the element number of s2 where the (first) matching slice begins,
- else return 0. Example:
-
- location = match("pho", "Euphoria")
- -- location is set to 3
-
-
- include sort.e
- x2 = sort(x1)
- Sort x into ascending order using a fast sorting algorithm. By
- defining your own compare function to override the built-in
- compare(), you can change the ordering of values from sort(), and
- perhaps choose a field or element number on which to base the sort.
- Define your compare() as a global function before including sort.e.
- Example:
- x = 0 & sort({7,5,3,8}) & 0
- -- x is set to {0, 3, 5, 7, 8, 0}
-
-
- 4.4 Math
- --------
-
- These routines can be applied to individual atoms or to sequences of values.
- See "Arithmetic Operations on Sequences" in chapter 2.
-
- x2 = sqrt(x1)
- Calculate the square root of x1.
-
- x2 = rand(x1)
- Return a random integer from 1 to x1 where x1 is from 1 to 32767.
-
- x2 = sin(x1)
- Return the sin of x1, where x1 is in radians.
-
- x2 = cos(x1)
- Return the cos of x1, where x1 is in radians.
-
- x2 = tan(x1)
- Return the tan of x1, where x1 is in radians.
-
- x2 = log(x1)
- Return the natural log of x1
-
- x2 = floor(x1)
- Return the greatest integer less than or equal to x1.
-
- x3 = remainder(x1, x2)
- Compute the remainder after dividing x1 by x2. The result will have
- the same sign as x1, and the magnitude of the result will be less
- than the magnitude of x2.
-
- x3 = power(x1, x2)
- Raise x1 to the power x2
-
- Examples:
- sin_x = sin({.5, .9, .11}) -- {.479, .783, .110}
-
- ? power({5, 4, 3.5}, {2, 1, -0.5}) -- {25, 4, 0.534522}
-
- ? remainder({81, -3.5, -9, 5.5}, {8, -1.7, 2, -4})
- -- {1, -0.1, -1, 1.5}
-
-
- 4.5 File and Device I/O
- -----------------------
-
- To do input or output on a file or device you must first open the file or
- device, then use the routines below to read or write to it, then close
- the file or device. open() will give you a file number to use as the first
- argument of the other I/O routines. Certain files/devices are opened for you
- automatically:
-
- 0 - standard input
- 1 - standard output
- 2 - standard error
-
- Unless you redirect them on the command line, standard input comes from
- the keyboard, standard output and standard error go to the screen. When
- you write something to the screen it is written immediately without
- buffering. If you write to a file, your characters are put into a buffer
- until there are enough of them to write out efficiently. When you close
- the file or device, any remaining characters are written out. When your
- program terminates, any files that are still open will be closed for you
- automatically.
-
- fn = open(s1, s2)
- Open a file or device, to get the file number. -1 is returned if the
- open fails. s1 is the path name of the file or device. s2 is the
- mode in which the file is to be opened. Possible modes are:
- "r" - open text file for reading
- "rb" - open binary file for reading
- "w" - create text file for writing
- "wb" - create binary file for writing
- "u" - open text file for update (reading and writing)
- "ub" - open binary file for update
- "a" - open text file for appending
- "ab" - open binary file for appending
-
- Files opened for read or update must already exist. Files opened
- for write or append will be created if necessary. A file opened
- for write will be set to 0 bytes. Output to a file opened for
- append will start at the end of file.
-
- Output to text files will have carriage-return characters
- automatically added before linefeed characters. On input, these
- carriage-return characters are removed. Null characters (0) are
- removed from output. I/O to binary files is not modified in any way.
-
- Some typical devices that you can open are:
- "CON" the console (screen)
- "AUX" the serial auxiliary port
- "COM1" serial port 1
- "COM2" serial port 2
- "PRN" the printer on the parallel port
- "NUL" a non-existent device that accepts and discards output
-
-
- close(fn)
- Close a file or device and flush out any still-buffered characters.
-
-
- print(fn, x)
- Print an object x with braces { , , , } to show the structure.
- If you want to see a string of characters, rather than just the
- ASCII codes, you need to use puts or printf below. e.g.
-
- print(1, "ABC") -- output is: {65, 66, 67}
- puts(1, "ABC") -- output is: ABC
-
- ? x This is just a shorthand way of saying print(1, x), i.e. printing
- the value of an expression to the standard output. For example
- ? {1, 2} + {3, 4} would display {4, 6}. ? adds new-lines to
- make the output more readable on your screen (or standard output).
-
-
- printf(fn, st, x)
- Print x using format string st. If x is an atom then a single
- value will be printed. If x is a sequence, then formats from st
- are applied to successive elements of x. Thus printf always takes
- exactly 3 arguments. Only the length of the last argument,
- containing the values to be printed, will vary. The basic formats
- are:
- %d - print an atom as a decimal integer
- %x - print an atom as a hexadecimal integer
- %o - print an atom as an octal integer
- %s - print a sequence as a string of characters
- %e - print an atom as a floating point number with exponential
- notation
- %f - print an atom as a floating-point number with a decimal point
- but no exponent
- %g - print an atom as a floating point number using either
- the %f or %e format, whichever seems more appropriate
- %% - print '%' character
-
- Field widths can be added to the basic formats, e.g. %5d, or %8.2f.
- The number before the decimal point is the minimum field width to be
- used. The number after the decimal point is the precision to be used.
-
- If the field width is negative, e.g. %-5d then the value will be
- left-justified within the field. Normally it will be right-justified.
- If the field width starts with a leading 0 e.g. %08d then leading
- zeros will be supplied to fill up the field. If the field width
- starts with a '+' e.g. %+7d then a plus sign will be printed for
- positive values.
-
- Examples:
- rate = 7.75
- printf(myfile, "The interest rate is: %8.2f\n", rate)
-
- name="John Smith"
- score=97
- printf(1, "%15s, %5d\n", {name, score})
-
- Watch out for the following common mistake:
-
- printf(1, "%15s", name)
-
- This will print only the first character of name, as each element
- of name is taken to be a separate value to be formatted. You must
- say this instead:
-
- printf(1, "%15s", {name})
-
-
- puts(fn, x)
- Print a single character (atom) or sequence of characters as bytes
- of text. e.g.
-
- puts(screen, "Enter your first name: ")
-
- puts(output, 'A') -- the single byte 65 will be sent to output
-
-
- i = getc(fn)
- Get the next character (byte) from file fn. -1 is returned at end
- of file
-
-
- x = gets(fn)
- Get a sequence (one line, including \n) of characters from text
- file fn. The atom -1 is returned on end of file. Example:
-
- -- read a text file into a sequence
- buffer = {}
- while 1 do
- line = gets(0)
- if atom(line) then
- exit -- end of file
- end if
- buffer = append(buffer, line)
- end while
-
-
- i = get_key()
- Return the key that was pressed by the user, without waiting for
- carriage return, or return -1 if no key was pressed
-
-
- include get.e
- s = get(fn)
- Read the next representation of a Euphoria object from file fn, and
- convert it into the value of that object. s will be a 2-element
- sequence {error status, value}. Error status values are:
-
- GET_SUCCESS -- object was read successfully
- GET_EOF -- end of file before object was read
- GET_FAIL -- object is not syntactically correct
-
- As a simple example, suppose your program asks the user to enter
- a number from the keyboard. If he types 77.5, get(0) would return
- {GET_SUCCESS, 77.5} whereas gets(0) would return "77.5\n".
-
- get() can read arbitrarily complicated Euphoria objects. You could
- have a long sequence of values in braces and separated by commas,
- e.g. {23, {49, 57}, 0.5, -1, 99, 'A', "john"}. A single call to
- get() will read in this entire sequence and return it's value as
- a result. The combination of print() and get() can be used to
- save any Euphoria object to disk and later read it back. This
- technique could be used to implement a database as one or more
- large Euphoria sequences stored in disk files. The sequences
- could be read into memory, updated and then written back to disk
- after each series of transactions is complete. See demo\mydata.ex.
-
- Each call to get() picks up where the previous call left off. For
- instance, a series of 5 calls to get() would be needed to read in:
- 99 5.2 {1,2,3} "Hello" -1.
-
- include file.e for the following:
- i1 = seek(fn, i2)
- Seek (move) to any byte position in the file fn or to the end of file
- if i2 is -1. For each open file there is a current byte position
- that is updated as a result of I/O operations on the file. The
- initial file position is 0 for files opened for read, write or update.
- The initial position is the end of file for files opened for append.
- The value returned by seek() is 0 if the seek was successful, and
- non-zero if it was unsuccessful. It is possible to seek past the
- end of a file. In this case undefined bytes will be added to the file
- to make it long enough for the seek.
-
- i = where(fn)
- This function returns the current byte position in the file fn.
- This position is updated by reads, writes and seeks on the file.
- It is the place in the file where the next byte will be read from,
- or written to.
-
- s = current_dir()
- Return the name of the current working directory.
-
- x = dir(st)
- Return directory information for the file or directory named by st.
- If there is no file or directory with this name then -1 is returned.
- This information is similar to what you would get from the DOS dir
- command. A sequence is returned where each element is a sequence
- that describes one file or subdirectory. For example:
- {
- {".", "d", 0 1994, 1, 18, 9, 30, 02},
- {"..", "d", 0 1994, 1, 18, 9, 20, 14},
- {"fred", "ra", 2350, 1994, 1, 22, 17, 22, 40},
- {"sub", "d" , 0, 1993, 9, 20, 8, 50, 12}
- }
- If st names a directory you will have entries for "." and "..", just
- as with the DOS dir command. If st names a file then x will have just
- one entry, i.e. length(x) will be 1. Each entry contains the name,
- attributes and file size as well as the year, month, day, hour, minute
- and second of the last modification. The attributes element is a
- string sequence containing characters chosen from:
-
- d - directory
- r - read only file
- h - hidden file
- s - system file
- v - volume-id entry
- a - archive file
-
- A normal file without special attributes would just have an empty
- string, "", in this field. See bin\walkdir.ex for an example that
- uses the dir() function.
-
-
- 4.6 Mouse Support
- -----------------
-
- include mouse.e -- required for these routines
-
- x = get_mouse()
- Return the last mouse event in the form {event, x, y}, or return -1
- if there has not been a mouse event since the last time get_mouse()
- was called.
-
- Constants have been defined in mouse.e for the possible mouse events.
- x and y are the coordinates of the mouse pointer at the time that
- the event occurred. e.g. {2, 100, 50} would indicate that the
- left button was pressed down while the mouse pointer was at position
- x=100, y=50 on the screen. get_mouse() returns immediately with
- either a -1 or a mouse event. It does not wait for an event to occur.
- You must check it frequently enough to avoid missing an event. When
- the next event occurs, the current event will be lost, if you haven't
- read it. In practice it is not hard to catch almost all events, and
- the ones that are lost are usually lost at a lower level in the
- system, beyond the control of your program. Losing a MOVE event is
- generally not too serious, as the next MOVE will tell you where the
- mouse pointer is.
-
- You can use get_mouse() in most text and graphics modes. (The SVGA
- modes may not work fully under MS-DOS).
-
-
- mouse_events(i)
- Use this procedure to select the mouse events that you want
- get_mouse() to report. For example, mouse_events(LEFT_DOWN+LEFT_UP+
- RIGHT_DOWN) will restrict get_mouse() to reporting the left button
- being pressed down or released, and the right button being pressed
- down. All other events will be ignored. By default, get_mouse()
- will report all events. It is good practice to ignore events that
- you are not interested in, particularly the very frequent MOVE event,
- in order to reduce the chance that you will miss a significant event.
- mouse_events() can be called at various stages of the execution of
- your program, as the need to detect events changes.
-
-
- mouse_pointer(i)
- If i is 0 hide the mouse pointer, otherwise turn on the mouse pointer.
- It may be necessary to hide the mouse pointer temporarily when you
- update the screen. Multiple calls to hide the pointer will require
- multiple calls to turn it back on. The first call to either get_mouse()
- or mouse_events() above, will also turn the pointer on (once).
-
-
- 4.7 Operating System
- --------------------
-
- a = time()
- Return the number of seconds since some fixed point in the past. The
- resolution on MS-DOS is about 0.05 seconds.
-
-
- s = date()
- Return a sequence with the following information:
- { year (since 1900),
- month (January = 1),
- day (day of month, starting at 1),
- hour (0 to 23),
- minute (0 to 59),
- second (0 to 59),
- day of the week (Sunday = 1),
- day of the year (January 1st = 1) }
-
-
- s = command_line()
- Return a sequence of strings, where each string is a word from the
- ex command line that started Euphoria. The first word will be the
- path to the Euphoria executable. The next word is the name of
- your Euphoria .ex file. After that will come any extra words typed
- by the user. You can use these words in your program. Euphoria
- does not have any command line options.
-
-
- x = getenv(s)
- Return the value of an environment variable. If the variable is
- undefined return -1. e.g.
-
- getenv("EUDIR") -- returns "C:\EUPHORIA" -- or D: etc.
-
-
- system(s, a)
- Pass a command string s to the operating system command interpreter
- for execution. The argument a indicates the manner in which to
- return from the system call.
- value of a return action
- 0 - restore previous graphics mode
- (clears the screen)
- 1 - make a beep sound, wait for a
- key press, then restore the
- graphics mode
- 2 - do not restore graphics mode
-
- Action 2 should only be used when it is known that the system call
- will not change the graphics mode.
-
-
- abort(a)
- Abort execution of the program. The argument a is an integer status
- value to be returned to the operating system. A value of 0 indicates
- successful completion of the program. Other values can indicate
- various kinds of errors. Euphoria for MS-DOS currently ignores this
- argument and always returns 0. abort() is useful when a program is
- many levels deep in subroutine calls, and execution must end
- immediately, perhaps due to a severe error that has been detected.
-
-
- Machine Dependent Routines
- --------------------------
- x = machine_func(a, x)
- machine_proc(a, x)
- These routines perform machine-specific operations such as graphics
- and sound effects. They are meant to be called indirectly via one of
- the support routines, written in Euphoria. A direct call can cause
- a machine exception if done incorrectly. Calls to these routines
- may not be portable across all machines and operating systems that
- Euphoria is implemented on.
-
-
-
- 4.8 Debugging
- -------------
-
- trace(x)
- If x is 1 then turn on full-screen statement tracing. If x is 0 then
- turn off tracing. Tracing only occurs in subroutines that were
- compiled with trace. See the section on Debugging.
-
-
-
- 4.9 Graphics & Sound
- --------------------
-
- clear_screen()
- Clear the screen using the current background color.
-
-
- position(a1, a2)
- Set the cursor to line a1, column a2, where the top left corner
- is position(1,1).
-
-
- include graphics.e -- for the following routines:
-
- i1 = graphics_mode(i2)
- Select graphics mode i2. See graphics.e for a list of valid
- graphics modes. If successful, i1 is set to 0, otherwise i1
- is set to 1.
-
-
- s = video_config()
- Return a sequence of values describing the current video
- configuration:
- {color monitor?, graphics mode, text rows, text columns,
- xpixels, ypixels, number of colors}
-
-
- scroll(i)
- Scroll the screen up (i positive) or down (i negative) by i lines.
-
-
- wrap(i)
- Allow text to wrap at right margin (i = 1) or get truncated (i = 0).
-
-
- cursor(i)
- Select a style of cursor. See graphics.e for some choices.
-
-
- text_color(i)
- Set the foreground text color. Add 16 to get blinking text
- in some modes. See graphics.e for a list of possible colors.
-
-
- bk_color(i)
- Set the background color - text or graphics modes.
-
-
- x = palette(i, s)
- Change the color for color number i to s, where s is a sequence of
- color intensities: {red, green, blue}. Each value in s can be from
- 0 to 63. If successful, a 3-element sequence containing the
- previous color for i will be returned, and all pixels on the screen
- with value i will be set to the new color. If unsuccessful, the
- atom -1 will be returned.
-
-
- i2 = text_rows(i1)
- Set the number of lines of text on the screen to i1 if possible.
- i2 will be set to the actual new number of lines.
-
-
- pixel(i, s)
- Set a pixel using color i at point s, where s is a 2-element screen
- coordinate {x, y}.
-
-
- i = get_pixel(s)
- Read the color number for a pixel on the screen at point s,
- where s is a 2-element screen coordinate {x, y}. -1 is returned
- for points that are off the screen.
-
-
- draw_line(i, s)
- Draw a line connecting two or more points in s, using color i.
- Example:
-
- draw_line(7, {{100, 100}, {200, 200}, {900, 700}})
-
- would connect the three points in the sequence using a thin white
- line, i.e. a line would be drawn from {100, 100} to {200, 200} and
- another line would be drawn from {200, 200} to {900, 700}.
-
-
- polygon(i1, i2, s)
- Draw a polygon with 3 or more vertices given in s, using a certain
- color i1. Fill the area if i2 is 1. Don't fill if i2 is 0. Example:
-
- polygon(7, 1, {{100, 100}, {200, 200}, {900, 700}})
-
- would make a solid white triangle.
-
-
- ellipse(i1, i2, s1, s2)
- Draw an ellipse with color i1. The ellipse neatly fits inside
- the rectangle defined by diagonal points s1 {x1, y1} and s2
- {x2, y2}. If the rectangle is a square then the ellipse will be a
- circle. Fill the ellipse when i2 is 1. Don't fill when i2 is 0.
- Example:
-
- ellipse(5, 0, {10, 10}, {20, 20})
-
- would make a magenta colored circle just fitting inside the square
- {10, 10}, {10, 20}, {20, 20}, {20, 10}.
-
-
- sound(i)
- Turn on the PC speaker at the specified frequency. If i is 0
- the speaker will be turned off.
-
-
- 4.10 Machine Level Interface
- ----------------------------
-
- With this low-level machine interface you can read and write to memory. You
- can also set up your own 386+ machine language routines and call them. The
- usual guarantee that Euphoria will protect you from machine-level errors
- does *not* apply when you use these routines. There are only some simple
- checks to catch the use of memory addresses that are negative or zero.
- (Theoretically address 0 is acceptable, but in practice it is usually an
- error so we catch it.)
-
- Most Euphoria programmers will never use this interface, but it is
- important because it makes it possible to get into every nook and cranny
- of the hardware or operating system. For those with very specialized
- applications this could be crucial.
-
- Machine code routines can be written by hand, or taken from the disassembled
- output of a compiler for C or some other language. Remember that your
- machine code will be running in 32-bit protected mode. See demo\callmach.ex
- for an example.
-
- i = peek(a)
- Read a single byte value in the range 0 to 255 from machine address a.
-
- poke(a, i)
- Write a single byte value, i, to memory address a. remainder(i, 256)
- is actually written.
-
- Writing to the screen memory with poke() can be much faster than using
- puts() or printf(), but the programming is more difficult and less
- portable. In most cases the speed is not needed. For example, the
- Euphoria editor never uses poke().
-
- call(a)
- Call a machine language routine that starts at location a. This
- routine must execute a RET instruction #C3 to return control
- to Euphoria. The routine should save and restore any registers
- that it uses. You can allocate a block of memory for the routine
- and then poke in the bytes of machine code. You might allocate
- other blocks of memory for data and parameters that the machine
- code can operate on. The addresses of these blocks could be poked
- into the machine code.
-
- include machine.e
-
- a = allocate(i)
- Allocate i contiguous bytes of memory. Return the address of the
- block of memory, or return 0 if the memory can't be allocated.
-
- free(a)
- Free up a previously allocated block of memory by specifying the
- address of the start of the block, i.e. the address that was
- returned by allocate().
-
- s = int_to_bytes(a)
- Convert an integer into a sequence of 4 bytes. These bytes are in
- the order expected on the 386+, i.e. least significant byte first.
- You would use this routine prior to poking the bytes into memory.
-
- a = bytes_to_int(s)
- Convert a sequence of 4 bytes into an integer value. The result could
- be greater than the integer type allows, so assign it to an atom.
-
-
-
- --- THE END ---
-
-