The Egg Language
The purpose
The purpose of the Egg language is
to assist in modular, object-oriented method of creating complex
documents. It allows both textual elements and formatting elements
stored like objects once and then repeated as needed in multiple
parts of the document. The Egg language is wholly independent of the
nature of the document. Books, websites, computer software can all
benefit from its universal capabilities. I’ll give a few
examples:
A book author might prefer to keep
certain episodes, descriptions, or names of locales and the book
characters defined elsewhere. In the main document of the book he
will refer to them by a variable name. It may by an uncommon way to
write a novel, but in technical or scientific writing references to
quoted material, or passages yet unwritten, are numerous. The
technical writer often needs to make references outside of the main
text such as indexes, library references, and notes. Those need to be
abstracted away from the numbering system of pages and notes, which
can only be built once the book is complete. If you ever wrote an
article, let alone a lengthy book, that uses numbered notes, you know
how much labor is involved in inserting a new note and renumbering
all the subsequent ones, both in the main text and in the notes
chapter. Similarly, if the chapter names include numbers, these are
very hard to maintain by hand when the chapters are moved around. The
book author will use Egg language to refer to various moving parts in
his book by name so that he can concentrate on creating content.
An Internet publisher of the same
book will need to immerse the document which is the book into a
framework of paging software, table of content page, furnish the page
numbers to footnotes and indexes, and possibly insert advertising
insets. The publisher will use Egg language to define the collection
of hypertext links, boilerplate content and decorations that
constitute the book reader software.
A web designer has to deal with
complex and hierarchical HTML and Javascript elements that constitute
a website. It is a good approach to define the overall structure of
the page: the logo, the menu, the title, the content, the insets, the
sidebar, the page header and footer in general terms and refer to
them by name only in order to define the general layout. Then each
such element can be defined in terms of its components. For example,
the menu is a single entity in the general layout, but is itself
composed of sections, and the sections – of menu items. The
top-down design is commonplace in software development, but in
creation of online content one has to combine PHP and Javascript
code, straight HTML, cascading style sheets, and server-side includes
into a single whole. The Egg language is the unifying methodology
that allows to bring object-oriented, technology-independent thinking
into website design. It also can replace narrow-purpose technologies
such as cascading style sheets and server-side includes. The designer
can think in terms of functional elements: logo, menu, content,
links, etc., rather than in technological terms of how they are to be
implemented.
A computer programmer typically can
take advantage of the powerful text organization apparatus of the
programming language that he uses. In C or similar languages, for
example, there are ways to aggregate variables, encapsulate
algorithms in functions, and insert files into the master file by
name. However, not every language has similar features. A programmer
proficient in Egg might choose to use it as a pre-processor for his
software either because the native programming language lacks the
organizational features or because he finds the Egg language easier
to use with everything he does. One area where Egg would be useful is
inserting decorative commenting patterns that some organizations
require before certain units of code.
The text that contains elements of
the Egg language will be called “Egg book” or simply
“book”. When, in this manual, I use the word “book”
in its everyday sense I will qualify it, for example, as
“natural-language book” or use words such as “document”,
or “file”.
All Egg books are in Unicode with
UTF-8 encoding preferred.
Egg expressions
An Egg expression (or simply an
“egg”) is any text enclosed in “Egg braces”.
The default Egg braces are the “curly” braces. So, this
is an Egg expression: {x}.
The braces are rarely used in
natural-language books, but they are common in computer languages.
Later I will explain how to distinguish braces used for Egg variables
from any other use. However, if your book is using plenty of braces
(for example, because it has C/C++/C# code inside) I recommend to
instead redefine the Egg braces as some other pair of Unicode
characters or short code words. The eggBuilder application has a
function to replace the canonical braces with any symbol you might
want. For most people, I think, double braces will work fine: {{x}}.
You might consider this pair of characters
«, »
(Unicode 00AB, 00BB)
if you have a convenient way to
input them.
The Egg expressions can be two
kinds: variables and instructions. A variable is something that
ultimately is bound to a value. A variable is resolved when it is
replaced with that value everywhere in the book. For example, this is
a short Egg book:
Someone, quickly, get {x}! –
{y} cried. We need to find {x}, before it’s too late!
If, somehow, eggBuilder knows that
{x} has value “John” and {y} has value “Elsa”,
then our book evaluates as:
Someone, quickly, get John! –
Elsa cried. We need to find John, before it’s too late!
The Egg instruction causes
eggBuilder to process the book in a certain way. For example, the
instruction
{page}
causes a page break to be inserted.
You cannot name a variable “page” because there is an
instruction with that name. EggBuilder processes this instruction by
saving the output file that is its current output file, and open
another file with a different page number embedded in the file name.
It also increments the current page number.
Another instruction is
{npage}
This, as you might guess, is
resolved as the current page number.
There are quite a few instructions,
many have complex syntax. This composite instruction, for example, is
a three-way conditional block that depends on two variables:
{if: {x}}
John is
found in “Bull And Claw”, sound asleep on a bench behind
the corner table.
{else if: {y}}
John cannot
be found anywhere.
{else}
His name is
not John!
{end if}
The eggBuilder application is all
about resolving the Egg variables and acting on Egg expressions. The
general principle is that everything inside the Egg braces is subject
to eggBuilder evaluation of one kind or another; everything outside
of the Egg braces is free text that is left unchanged. This is
similar to how HTML or other markup languages work.
Let us return to the study of Egg
instructions after we study Egg variables.
Variables
To resolve a variable is to find
its value. There are several ways to resolve a variable:
The Egg author provides an
“equate file” supplementing his book. For example, if
his book is in file “book.egg”, the equate file for it
should be named “book.init.eq”. The format of the equate
file is simple: each equate is an expression of the type
name = value
appearing on its
own line. For example, to resolve the example from the previous
chapter, the equate file should contain the following two lines:
x = John
y = Elsa
This is not all
there is to know about equate files: they can define not individual
variables but also arrays and tables. Those will be discussed later.
If a variable is an expression
containing other variables, it is resolved after the constituent
variables get resolved. For example,
{either {x} or
{y}}
resolves as
either John or
Peter
, provided that {x} resolves
as “John” and {y} resolves as “Peter”.
A variable may be bound by a
set expression. For example,
{set: species =
dog; epithet = beautiful }
Concerning
{species}, they are {epithet} animals.
{end set}
The two eggs
evaluate to “dog” and “beautiful” inside the
{set…} b- {end set} block. Outside of it they may have values
assigned by some other method, or unassigned at all.
A variable may be bound by a
loop expression. We shall discuss loops in detail later, but this is
an example of a loop-bound variable:
{for x in: 1
to: 10 by: 2}
loop {x};
{end for}
The variable {x} will take value
dictated by the loop instruction, and the book will evaluate to
loop 1; loop 3; loop 5; loop 7;
loop 9;
Finally, eggBuilder may be
unable to evaluate a variable by any of the above methods. Its last
resort is simply to ask the author. EggBuilder will build a dialog
listing all the unresolved variables in the book, with an input
field for each variable. Since the user may define variables in
terms of other variables, themselves unresolved, this process may
become iterative.
As case 2 implies, variables can
nest in other variables. For example, consider this book:
Trust me,
this { epithet { color } { model } } has very good gas mileage.
Let us assume there is no equate
file for it. What would eggBuilder do with it? We have eggs {
color } and {model } inside an outer egg. Eggbuilder must
resolve the innermost egg first. So eggBuilder will ask you to define
{ color } and {model }. It will not ask you to define {
epithet { color } { model } } at the same time, because that is a
complex variable. Let’s say, you answer
color = red
model = Ford
Now eggBuilder knows what to ask
next. It asks, what is { epithet red Ford }? Eggbuilder
evaluated the complex outer variable into a simple variable, and now
it needs to evaluate the simple variable. When you answer, for
example,
epithet red Ford = gorgeous 2012
red Mustang
the book becomes fully evaluated as
Trust me,
this gorgeous 2012 red Mustang has very good gas mileage.
But of course you could have given
any other answer, canceling all mentioning of the {color} and
{model}. The inner variable was merely a way to evaluate the
outer variable. Nonsensically, the second answer could have been
epithet red Ford = pogo stick
and you would have ended up with
Trust me,
this pogo stick has very good gas mileage.
There is yet another scenario.
Instead of reducing nested eggs, we increase nestedness. Instead of
answering
epithet red
Ford = gorgeous 2012 red Mustang
we could answer
epithet red
Ford = gorgeous {year} red Mustang
Now eggBuilder has one more variable
to evaluate: {year}. So we’ve opened another round of
questions before the book is ready. This can be done for amusement:
as several people take turn answering, when the book is eventually
evaluated in full, a surprising text might emerge!
The variables are kept on the stack,
that is, on an internal data structure correlating variable names
with values. There are several ways to nest one book or a book
segment inside another; when such nesting occurs, the nested
variables are put on top of the existing stack, and when the nested
evaluation is complete, the stack is popped so that the nested
variables become undefined. For example, case 3 describes a nested
loop body. Variable {x} is used inside the loop, where it
takes values 1, 3, etc. But what if outside of the loop there was
also a variable named {x}? No problem: the “outer”
{x} will evaluate outside of the loop, and independently of
it, the loop variable will be assigned values by the loop control.
The “outer” {x} will be inaccessible inside the
loop. But once the loop has been evaluated the “outer”
{x} will be, so to say, remembered. That is because variables
are evaluated starting with the top of the stack; inside the loop the
stack is taller and the top layer contains the value of the loop
variable {x}. Once the loop is done and the stack is popped,
its top layer is gone and a reference to {x} outside of the loop will
be evaluated (or fail to evaluate) with the shortened stack.
A reader familiar with computer
languages will recognize this scheme as “scoping” of
variables.
Instructions
There is a finite list of keywords
used to form instructions. They are case-sensitive. An instruction
may have parameters: for example, we have seen a loop instruction
with a “from”, “to” and “step”
keywords with corresponding values. Some instructions evaluate into a
text value to replace the instruction egg. Other instructions cause
complex patterns to be inserted in the book (like in the loop
example). Parameters are separated from the keyword by an equal
sign, and parameters can be listed using comma signs. Space is
optional with all punctuation. What follows is a list of
instructions, or rather instruction groups, in the order of
increasing complexity.
Paging instructions
{page} or {page = N},
where N is any integer.
Directs the
eggBuilder to begin a new page. If the N parameter is present,
the new page has the indicated number. By default page numbers are
1-based and increase by 1. Paging is implemented by generating
several output files, each for a single page. The file names are
built upon the same file name stem as the book name, and have the
page number embedded in them. Situations when paging is nested are
described in a separate chapter. See example at the end of this
instruction group.
{npage}
Evaluates as the current page
number.
For example, the following book,
named “flat_pages.egg”:
page A is {npage}{page}page B is
{npage}{page}page C is {npage}
Produces three output files,
“flat_pages_0.html”, “flat_pages_1.html”,
“flat_pages_2.html”. Their contents are, respectively,
page A is 1
page B is 2
page C is 3
Chapter instructions
{chap} or {chap = N},
where N is any integer.
Directs the
eggBuilder to begin a new chapter. If the N parameter is
present, the new chapter has the indicated number. The paragraph
counter is reset. By default chapter numbers are 1-based. The
instruction updates the internal chapter and paragraph counters but
has no direct effect on the output.
{nchap}
Evaluates as the current chapter
number.
Paragraph instructions
{para} or {para = N},
where N is any integer.
Directs the
eggBuilder to begin a new paragraph. If the N parameter is
present, the new paragraph has the indicated number. By default
paragraph numbers are 1-based. The instruction updates the internal
paragraph counter but has no direct effect on the output.
{npara}
Evaluates as the current paragraph
number.
{pagecount}
Evaluates to the number of pages in
the output.
File instruction
{file = <filename> },
where <filename> is absolute or relative to the project
folder name of an Egg book.
This evaluates
to the content of the indicated book. EggBuilder will search for an
equate file for the book (see back in Variables chapter, case 1). For
example if the instruction is {file = include1.egg}, EggBuilder will
search for “include1.init.eq” in the same folder. If
there is no equate file, the book in the file instruction is
evaluated based on the variables already bound to values at that
point. If there is an equate file, then its equates are added to the
stack for the duration of the evaluation of the file, and then they
are popped off the stack.
This is a
powerful tool because the file instruction allows us to define
independent modules of a book. An author could, for example, start
with the following book plan:
{ title }
{ file =
foreword.egg }
{ file =
introduce_characters.egg }
{ file =
{hero}_is_in_love.egg }
{ file =
scene_at_the_pond.egg }
{ file =
jealousy_and_despair.egg }
{ file =
happy_end.egg }
{ file =
epilogue.egg }
Now, { title
} and { hero } could be filled in the master book’s
equate file, something like:
title = Tryst On
the Pond
hero = Amoroso
The author can
concentrate on creating the 7 files for each chapter. Each chapter
will have independent set of its own variables, and it can share the
globally defined { title } and { hero } values. Note
that variables can be used to evaluate the file names.
Links to pages
{lnkthis
=TEXT}
Evaluates to an
HTML link (anchor tag) to the page in which it appears. TEXT in all
these instructions is the name of the link. For example, if this page
outputs as “book_123.html”, the tag will evaluate to <a
href=“book_123.html”>TEXT</a>
{lnknext
=TEXT}
Evaluates to an
HTML link (anchor tag) to the page next following the page in which
it appears. If there is no such page, evaluates to whitespace.
{lnkprev
=TEXT}
Evaluates to an
HTML link (anchor tag) to the page previous to the page in which it
appears. If there is no such page, evaluates to whitespace.
{lnkn=N;
TEXT}
Evaluates to an
HTML link (anchor tag) to the page number N (pages are zero-based
internally). If there is no such page, evaluates to whitespace.
{pagecount}
Evaluates to the number of pages in
the book.
{pagelast}
Evaluates to the number of the last
page in the book. To get to the first page, use {lnkn=0;TEXT};
to get to the last page, use {lnkn={pagelast};TEXT}.
Expressions
Expressions are combination of mutually connected control eggs. An
expression has an open and close control eggs. The open egg usually
has control parameters separated from the keyword by a colon.
Expressions have associated scopes. A scope is the section of the
book where a variable may be defined. If a variable is defined in an
expression scope, it is defined inside the scope and undefined
outside of it. Expressions, and therefore scopes can be nested.
Examples are in the chapter about { set }, but the same
scoping rules apply to all expressions.
Simple Blocks
{ block }
<block
body>
{ end block }
Blocks can be named:
{ block:
<name> }
<block
body>
{ end block }
If a block is named, its name is quoted as the block's context.
Blocks are simply a way to define variable scope. They cannot be
named, but they can be nested.
The { end block }
instruction is not necessary; if it is missing, the set block ends
when the block in which it is embedded ends, or when the book ends.
In other words, instructions { end set },
{ end if }, { else if
}, { else },
{ end for }, and {
end forpage } have an implied {
end block } in them for every {
block } embedded in them.
Conditional expressions
{if: <predicate1>}
<conditional content>
{end if}
First
<predicate1> is evaluated. The predicate can be any
expression. It is false if it evaluates to whitespace
or to “false”, or is an undefined variable;
otherwise, the evaluation is true.
If the predicate
evaluates to true, the entire block from the {if…}
egg to {end if} egg evaluates as <conditional content>.
If the predicate evaluates to false, the entire block
from the {if…} egg to {end if} egg evaluates to
whitespace.
{if: <predicate1>}
<conditional content>
{else}
<default content>
{end if}
Similar to
previous, the entire block from the {if…} egg to {end
if} egg evaluates as <conditional content> or as
<default content>.
{if: <predicate1>}
<content1>
{else if: <predicate2>}
<content2>
[…]
{else}
<default content>
{end if}
This is the most
general form: the predicates are evaluated till one evaluating to
true is found; the corresponding <contentN>
becomes the evaluation of the entire block.
We call the egg expressions {if…},
{else if…}, {else}, and {end if}
conditional blocks. The content between the conditional expressions
is called conditional bodies. The entire segment starting with {if…}
and ending in {end if} is called conditional expression.
A conditional expression has as many
scopes as it has blocks. So, a variable defined in the {if} block is
not defined in the corresponding { else if } or {else } blocks.
For example, consider the following
book:
{if: predicate1}
Roses are
red
{else if:
predicate{x}}
Violets are
blue
{else}
The future
is bleak
{end if}
Let us evaluate it using the
following equate file:
predicate2=defined
x=2
What do you think the evaluation
will be?
Correct, that book evaluates to
“Violets are blue”. That is because predicate{x}
evaluates to predicate2, and that variable evaluates to
something other than “false”. Note that “defined”
itself does not appear anywhere in the evaluated book.
Conditional blocks can be nested,
just like in procedural programming languages. Either the predicate
appearing in the {if:…} or {else if…} eggs, or the body
of the condition between conditional egg expressions can themselves
incorporate conditions, sets, or loops.
Set expressions
{set: x = v }
{set: x1 = v1; x2 = v2; […]}
{set: x1 = v1; x2 = v2; […]}
<set body> {end set}
The variables x,
x1, etc. receive the indicated values till the end of the set
block. The { end set } instruction is not necessary; if it is
missing, the set block ends when the block in which it is embedded
ends, or when the book ends. In other words, instructions { end
block }, { end if }, { else if }, { else }, {
end for }, and { end forpage } have an implied { end
set } in them for every { set… } embedded in
them.
This is a simple example.
My Book of Fish.
{set: species =
carp}
This is what is
known about {species}.
{file =
large_freshwater_fish.egg}
{set: species =
whale}
Regarding,
however, {species}, first we need to point out that it is not fish at
all!
{file =
water_mammal.egg}
The author has two chapters in
separate files. Both use the egg {species} as they supply
information about a certain class of creatures in general. He wants
to pull both into a book, first talking about carps and then about
whales.
This is an example of nested scopes.
{ set: x = Anthony }
{x} is near the beginning of the
alphabetical list
{block}
{x}
derives from Latin “Antonius”
{set:
x = Zachary }
{x} is near the end of the
alphabetical list
{end set }
{end block}
{x} has a familiar form “Tony”
( end set }
Here the same
variable egg {x} evaluated as “Anthony” in the outer
scope, and “Zachary” in the inner scope.
Procedure expressions
Procedures, or procs, are
expressions that take arguments. Procedures are not evaluated where
they are defined, but when they are called. For example, an author
has a certain style of placing images in his book. He always places
them centered with the maximum width 600. This is accomplished in
HTML by this tag:
<center><img
src=image.png width=600></center>
The author would like to not repeat
the center and width tags all the time. He wants to define an egg
variable for them. But here’s a problem: the image file name is
different each time. The author needs an egg that takes an argument,
or several arguments. In this case, it will take the image file name
as an argument. Such egg expressions, that take arguments, are
procedures. This is how you define a procedure:
{ proc define:
<proc name> }
<proc body>
{ end proc }
(that is a proc
without arguments)
{ proc x define:
<proc name> }
<proc body>
{ end proc }
(that is a proc
with one arguments)
Or for several arguments:
{ proc x, y [,…] define:
<proc name> }
<proc body>
{ end proc }
It is only interesting if <proc
body> uses argument eggs {x}, etc. Presumably, <proc
body> will expand to different value depending on the value of
the argument(s). Procedure definition does not evaluate to anything;
it is kept by eggBuilder internally till the proc is called.
This is how you call a proc:
{ <proc
name> }
(that is a proc without arguments called)
{ <proc
name>: x [, y,…] }
(that is a proc with one or more arguments called)
Let us finish with our example:
{ proc x define:
image }
<center><img
src={x} width=600></center>
{ end proc }
This can be placed anywhere in the
file; it is a proc definition. It cannot be placed inside any other
block; it is a good practice to place procedures either in the
beginning or the end of the book. The procedure is in scope and
available for use anywhere in the file where it is defined, or in the
file including the file with the definition. So another recommended
practice is to put the procedures in a separate file, and include
that file in the book that needs them.
Now any time the author want to
insert an image in his preferred style, he would call image:
{image: /images/figure1.png}
There are limitations: the procedure
names must be a single word and not be among existing eggBuilder
keywords. You are allowed to form the proc name dynamically, so long
as it does not evaluate to a keyword or undefined proc.
Procedure Blocks
Earlier, we read about simple blocks: those that have a name or are
unnamed. Procedure block all all that simple blocks are, but in
addition they have two procs associated with them: start proc and
finish proc. The syntax for them is
{ block [: <block-name>] [start: <start-proc name>
[: x [, y...]]] [finish : <fin-proc name> [: w [, z]]}
<block body>
{ end block }
The
{ end block }
instruction is not necessary, same as for simple blocks
Note that it is not necessary to have both a start proc and a finish
proc. The block procs are called, respectively, right before the
body of the block and right after. If either block proc has
arguments, those need to be defined in the outer scope of the block.
Triple procs
Elaborating on the procedure blocks, we have a triple proc (“trip”
for short). A triple proc is a collection of three procs with the
same name. They are useful to define tables or lists. Define them
like this:
{ head [x, y, …]
define: <trip name> }
<header
body>
{ end head }
{ item [x, y, …]
define: <trip name> }
<item body>
{ end item }
{ foot [x, y, …]
define: <trip name> }
<footer
body>
{ end foot }
Then use them like this:
{ head <trip name>[: x, y, ...] }
( item <trip name>[: x, y, …] }
( item <trip name>[: x, y, …] }
( item <trip name>[: x, y, …] }
{ foot <trip name>[: x, y, ...] }
An obvious example is
{ head define:
address-book }
<h1>Address
Book</h1>
<table><th>Name</th><th>Address</th><th>Phone<th><tr>
{ end head }
{ item name,
address, phone define: address-book }
<td>{name}</td><td>{address}</td><td>{phone}</td><tr>
{ end item }
{ foot define:
address-book }
</table>
{ end foot }
Now a table of phones and addresses can be expressed:
{ head address-book }
{ item address-book: Swanson, 1600 Maple St, 555-123-4567 }
{ item address-book: Jones, 120 Oak St, 555-123-9876 }
{ foot address-book }
References
A reference is a pair of elements in a book that are in an
asymmetrical relationship. A reference always has a base and a
destination. These are examples:
A footnote is a reference. The base here is the place in the body of
the text, where an asterisk or a numerical footnote is indicated.
That is the footnote's base. The footnote destination is at the
bottom of the page. There, a short (usually) text is placed also
marked with an asterisk or the same number. There are many ways to
style a footnote: use an asterisk or a few asterisks if there are
more than one footnote on the same page; use a little alphabet of
asterisks, daggers, crosses and other fancy symbols (that is pretty
old-fashioned), use regular numbers, or use Roman numbers.
Bibliographic citations are references. A detailed bibliography is
provided at the end of the book; in the body of the book abbreviated
markers into the bibliography are placed. The styles, again, vary.
Sometimes another style of numbering is used (so that
bibliographical notes not to be confused with footnotes); sometimes
the body contains an abbreviated name of the publication and it
refers to the full library listing in the bibliography section. The
base is the place where the bibliographical resource is mentioned in
the body of your book. The destination is the bibliography in the
end.
Chapter titles are references. The title logically belongs to the
beginning of the chapter. But the table of content (either at the
beginning of the book or at the end of it) also mentions the title.
The base is the beginning of the chapter, and the destination –
the table of content.
Subject matter indices are references. Often, especially in
technical writing, certain key words are placed at the end of the
book in the index section. The place where the key word is used in
the body of the book is the base, and the index section is the
destination.
A cross-reference is a place in the text that points to another
place in the book. These are common, for example, in so-called
“study” editions of the Bible, when a passage from an
New Testament would mention a related chapter and verse in the Old
Testament, or an episode in one gospel might mention the same
episode told also in another gospel. The base would be an
abbreviated chapter and verse citation on the margin of the main
text. The destination would be a related text in full elsewhere in
the book.
The base is always something that occurs in the natural flow of a
book. The destination is placed somewhere else: at the beginning of
the book, or at the end, or at the bottom of a page. The following
elements are necessary to form a referemce.
Reference base
A reference base is an expression placed in the main flow of the
book. The reference base (or simply reference) has the following
elements:
the keyword, 'ref'
the text of the reference is mandatory
the destination of the reference precedes the colon; if it is
omitted, a default destination at the end of the book is inserted by
default.
The short text placed at base is preceded by the keyword 'short';
if it is omitted, the sequential number of the reference is printed
according to the rules for the destination.
Example:
France
needs another Charlemagne {ref footnote: Also
known as Charles the Great, 748
– 814, first king of France} or at least a decent monarch.
This
book fragment will appear, possibly, thus:
France
needs another Charlemagneiv
or at least another decent monarch.
But
at the destination 'footnote',
this text will appear:
***
(i)
<your first footnote on the page>
(ii)
<your
second footnote on the page>
(iii)
<your
third footnote on the page>
(iv)
Also
known as Charles the Great, 748
– 814, first king of France.
But how do we know that destination 'footnote' is at the
bottom of the page and not someplace else; how do we know that the
footnotes start with a header consisting of a line with centered
three asterisks; how do we know that roman numerals should be used?
All that is specified at the two definitions, both with the name
'footnote'.
Reference definition
{ ref n[, s]
define: <dest name> }
<ref
item>
{ end ref }
Note that we are defining the style of the reference at base. For
example, since we want the style to be in superscript roman numeral,
we would code:
{ ref n
define: footnote }
<sub>{roman: {n}}</sub>
{ end ref }
,
where n is the number
of the reference (maintained automatically), and roman is
a built-in proc converting a positive integer to roman.
Generally,
an integer variable n is supplied to ref automatically, but the
author can add his own variable, such as the s
in the above definition. That is known as the “short”
reference: a text that might appear at base instead of the number.
For example, in bibliographical reference, at base we might see
One
researcher {ref bibliography: Niederhoffer} found that
…
Here
Niederhoffer
is a bibliographical key that appears at base as-is:
{ ref n, s define: bibliography }
[{s}]
{
end ref }
While the reference number n is still passed to the ref, it is not
used.
So the base will look simply:
One
researcher [Niederhoffer] found that …
The bibliography destination will have items like:
Niederhoffer:
Niederhoffer,
P.Q. (2007, July 30). Puzzling crystals confound scientists.
Washington
Post,
pp. C3, C15.
Reference insertion at base
Simply,
{ref <dest-name> [:x,...]}
Destination definition
The destination define is always a trip:
{ head
<placement> define: <dest name> }
<dest
header>
{ end head }
<placement>
is mandatory. Placements are
bot, top, left, right; (these
can be combined, e.g. bot, right)
chapterend
bookend
custom (this is the
placement that requires destination insertion egg)
{ item n [,
s] define: <dest name> }
<item>
{ end item }
{ foot define:
<dest name> }
<dest
footer>
{ end foot }
In our example:
{ head define: footnote }
<center>***</center><P>
{end head }
{ item n [, s] define: footnote }
({roman: { n }}) { s } <br>
{ end item }
Foot is not defined in our simple example. A more elaborate design
would be to construct an HTML table so that the reference numbers and
the reference text are separated by a tab rather by a space; in that
case, the footer will be necessary in order to close the HTML table.
Destination insertion at base
{ head <dest-name> }
This is the only destination marker needed; the processor will insert
the items and the foot as necessary. Moreover, if the destination
already implies location (like all of them but custom; e.g.
footnote is always at the bottom of the page), then there is no need
to mark a destination at all.
Loop expressions
Loops define a block that is
repeated several times (or once, or none at all), depending on the
loop control instruction. The general form is
{ for… }
< loop body >
{ end for }
Loops can nest other loops and they
can nest sets and conditionals. The definitions below use variable
names x, y, etc. for the loop variables, but of course
any simple variable can be used as loop variables. If a loop uses a
variable already defined outside of the loop, the homonymous loop
variable hides the outer variable inside the loop.
There are several variations of the
loop controls. First, there are enumerator loops:
{ for x in: v1, v2, v3, […] }
< loop body >
{ end for }
The loop body is
evaluated as many times as there are values following “in:”.
The loop variable is {x} and it is bound to each value in
turn. Of course, it is only interesting if < loop body >
uses variable {x}.
Next, we have numerical loops.
{ for x in: <start> to:
<finish>[ by: <step> ] }
< loop
body >
{ end for }
The loop body is
evaluated as the loop variable iterates from <start> to
<finish>. The “by: <step>”
expression can be omitted, and step = 1 is assumed. Expressions
<start>, <finish> and, if present,
<step> must evaluate to integers.
Through equate files, the author can
create arrays and tables. Let us take a detour and show how this is
done.
Detour: Arrays and tables
To create an array, give it a unique
name and define its entries in the equate file:
…
myArray={array}
cat
dog
sparrow
myArray={end
array}
…
As you can see, the array data
appears among other equates in a contiguous block that starts with an
equate whose name is the name of the array and the value is {array};
the array block ends when the same name is given value {end
array}. The values of the array are listed not in an equate form,
but simply one value per file line. The above defines an array of
three values.
Whenever an array is defined in the
equate file in eggBuilder’s scope, the following variables will
be defined globally, anywhere the equate file containing the array is
in scope:
{<array name>.N} is
bound to the values of the array, where N is an integer between 0 and
the size of the array less one. For example, { myArray.2 }
evaluates to “sparrow” in our example.
{<array name>.size} is
bound to the size of the array. In our example, { myArray.size }
evaluates to 3.
{<array name>.last} is
bound to the last existing index of the array. In our example, {
myArray.last } evaluates to 2, and generally, it is the array
size less 1.
A table has two dimensions. This is
how tables can be created in the equates file:
myTable={table}
country=USA
language=English
country=Germany
language=German
country=Italy
language=Italian
country=Holland
language=Dutch
myTable={end
table}
We see a 2 x 3 table defined here.
The name of the table is “myTable”. We see two names
appearing, “country and “language”. Therefore our
table has two columns by these names. The order of columns is
determined by the order in which the columns appear. We see that each
column is given three values. That is the number of rows in the
table.
It is allowed to leave some table
cells undefined. They are assumed to have a whitespace value by
default. For example, if the author does not know what language they
speak in Holland, he could leave that value out. The table will have
an empty string for the language spoken in Holland.
Whenever a table is defined in the
equate file in eggBuilder’s scope, the following variables will
be defined globally, anywhere the equate file containing the table is
in scope:
{ <table name>.colcount }
is bound to the number of the table’s columns.
{ <table name>.rowcount }
is bound to the number of the table’s rows.
{ <table name>.collast }
is bound to the number of the table’s columns.
{ <table name>.rowlast }
is bound to the number of the table’s rows.
{ <table name>.COL }
is bound to the name of the column number COL (zero-based), for COL
ranging from zero to the last defined column. In our example,
myTable.0 = country and myTable.1 = language.
{ <table name>.COL.ROW }
is bound to the value in column number COL (zero-based) and row
number ROW (also zero-based). In our example, myTable.0.1 =
Germany and myTable.1.1 = German.
Continuing with loop
expressions
Now that an array has been defined
through the equates file, an array loop can be written in the book.
{ for x in: <array name> }
< loop
body >
{ end for }
Here, <array
name> must appear in an array block in the equate file. The
following variables will be defined in the loop body:
{x} will
be bound to the iterated value in the array. That is, if the array is
like in our example, then {x} will be bound to “cat”,
then to “dog” and then to “sparrow”.
If a table has been defined, a table
loop may be written as follows:
{for x, y in: <table name>}
<loop body>
{end for}
In addition to the global table
values, {x} and {y} will be bound to the column number and the row
number for each value in the table. Columns are iterated first, so in
our example, the data will be grouped by rows: USA,
English, Germany, German, etc.
Also the variable {x.y} will
be bound to the value in the table (in other words, inside the table
loop
<table
name>.{x}.{y}
is the same as
{x.y}
Lastly, there is a universal loop
control.
{ for x [, y, z…] in:
<predicate> }
<loop body>
{ end for }
This is only
interesting if the loop variables are used in both <predicate>
and the <loop body>.
EggBuilder will
go over all equates in its current scope, and see if any values given
to the loop variables would allow the predicate to evaluate. The
order of output is dictate by the order of the loop variables in the
loop control.
For example, suppose the following
equates are in scope:
X1 Y2 Z2=def
X0 Y2 Z1=def
X0 Y0 Z1=def
Suppose the universal loop is
{ for x, y, z
in: X{x} Y{y} Z{z} }
Z: {z} Y: {y}
X: {x}
{ end for }
Observe that the predicate evaluates
to “def” for x=1, y=2 and z=2.
Therefore, the eggBuilder will bind the loop variables accordingly
and evaluate the loop body to:
Z: 2 Y: 2 X:
1
Observe that the predicate also
evaluates to non-empty string (it does not matter that it happens to
be “def”, any non-blank value would do) for x=0,
y=2 and z=1. Therefore, the eggBuilder will bind the
loop variables according to this combination and evaluate the loop
body to:
Z: 1 Y: 2 X:
0
Finally, there is another
combination, x=0, y=0 and z=1. This is the third
evaluation of the body:
Z: 1 Y: 0 X:
0
But in what order should eggBuilder
iterate? Clearly, eggBuilder should not go by the order of the
equates in the file, like we did. Instead, the order of the variables
as they appear in the list should determine the order of iterations.
Since the variable x is listed first, this is the most
significant variable, y is less significant and z is
the least significant. Therefore, the proper order is
-
The output of this loop is
Z: 1 Y: 0 X: 0
Z: 1 Y: 2 X: 0
Z: 2 Y: 2 X: 1
Page loops
Finally, a loop can be organized by
page number.
{ forpage x in: <start> to:
<finish>[ by: <step> ] }
<pageloop body>
{end forpage}
Pages are
numbered internally by zero-based page number. This loop will bind
the variable {x} to the page number inside the loop pody.
This is, for example, how a table of
content can be organized following a several-page book:
{file = page1}
<center>{npage}</center>
{page}
{file2 = page2}
<center>{npage}</center>
{page}
{file = page 3}
{npage}</center>
{page}
<P>
TABLE OF
CONTENT<br>
{forpage p in: 0
to: {pagecount}}
{lnkn={p}; Page
{p}}<br>
{end forpage}
This will produce three pages as
defined in the three page files. The last page will be a Table of
Content
<P>
TABLE OF
CONTENT<br>
<a
href=flat_pages_with_TOC_0.html>Page 0</a><br>
<a
href=flat_pages_with_TOC_1.html>Page 1</a><br>
<a
href=flat_pages_with_TOC_2.html>Page 2</a><br>
<a
href=flat_pages_with_TOC_3.html>Page 3</a><br>
(“flat_pages_with_TOC”
is the project name).
Conclusion
This completes the core Egg language
definition. I also plan a set of Egg extensions. The extensions will
utilize the linguistic core and provide more targeted functionality.
The book publisher extension will offer cross-referencing, foot notes
and chapter notes, page numbering options (such as having preface
page numbers in Roman numerals, and, of course, page number
placement), and a complete online book reader framework.
Other extensions are possible. For
example, one day I will produce a general purpose Website generator.
The future looks very bright.