GeL: a Lua binding for Gema
| Introduction | Usage
| Functions | Examples |
1. Introduction top
next
gema actions are enough for everyday usage but occasionally
you may need more power to define a complex transformation.
You might, also, want to use the superior matching capabilities
of gema to drive your program.
GeL is a Lua 5 library that:
- allows the execution of Lua function (and hence of a C function)
in a gema action
- provides the powerful text matching mechanisms offered by gema as
a set of Lua functions
it has been tested with Lua 5.0.2.
Refer to the detailed documentation
to build gel togheter with gema, .
1.1 Status
GeL is not as mature as gema or Lua, please report any bugs
you may find using SourceForge bug
tracking subsystem (you don't need to log in as a
SourceForge user) or sending an e-mail to Remo Dentato.
1.2 Licence
GeL is released under the same licence of Gema. No specific reference
needs to be made to GeL as long as the due reference to Gema and Lua have
been made.
2.1
Gema like
Gel may be used exactly as if it was gema,
any valid gema script should work when executed by gel:
gel
[gemaopts]
[-f rules.gema] [-l script.lua] [infile
[outfile]]
. The only differences are:
- The @lua{} function is available to execute lua scripts
in actions
- Text enclosed between "![" and "!]"
is considered lua code and is immediately executed
Rules specfied with '-f'
are loaded, the lua script specified with '-l'
is executed (possibily defining lua function to be used in some gema action)
and the infile is translated
to the outfile applying
the rules defined in the default domain.
All the gema options are recognized.
2.2 Lua like
Gel may be used as a Lua (non interactive) interpreter:
gel
[gemaopts] [-f rules.gema]
-lua script.lua [args]
Rules specfied with '-f'
are loaded then the control is passed to the lua script specified with
'-lua'.
No input file is opened and it's a script responsability to begin the
transformation process.
The optional arguments args
are passed to the script in the global table arg:
- arg.n will contain
the number of arguments;
- arg[0] will contain
the name of the script;
- arg[x] with x
between 1 and arg.n,
the arguments.
All the gema options are recognized.
2.3 Gua
Gua is a stand-alone Lua interpreter linked against
the gel library.
gua
[luaopts] [script.lua [args]]
I added gua
to this distribution to show how easy is to embed gel functions in your
lua enabled programs.
The only difference between gua.c
and the original lua.c
you can find in the Lua 5.0 distribution, is the addition of the function
call gel_init(l) at line
386.
Actually there is another difference that it's not
related to gel, I had to add a fflush(stderr) to the l_message() function
to fix a problem with the mingw compiler.
2.4 libgel
All the gel function are available as static library named
libgel.a on Unix or libgel.lib on Windows. The building
process will automatically generate it.
3.1 Gema
Some new functions havr been added to gema:
- @lua{string}
- that executes string as a piece of lua code. Returns
a value only if the lua code explicitly uses return:
- @lua{f()} returns nothing
- @lua{return f()} returns the first value returned by
f().
- @rules{group}
- Reports the status of the nth group of rules. Two new escape sequences
( \Q and \q) have been added to create groups of rules;
up to 8 groups can be created numbered from 0 to7.
To understand this new feature, imagine you want to use different rules
to parse a block of text. A possible solution is to set a variable and
then use @cmpn to have different behaviors with respect to the same
match.
Instead, using \Q in a pattern means that that a match should fail if
the specified group is disabled.
- @rules{group;switch}
- Modify the status of the nth group:
0: turn off
1: turn on
x: toggle
- @line{mark}
- the @line function has been extendend to support the \M
escape sequence
- @column{mark}
- the @column function has been extendend to support the \M
escape sequence
3.2 Lua
Lua functions can be loaded in three ways:
- using the -l
option in the command line;
- executing @lua{dofile("filename")}
in an action;
- embedding the lua code in the gema rule file between "!["
and "!]".
The examples in the next section should clarify how
to use those three methods.
There are new lua
functions to interact with gema environment:
- gel.set(varname,value)
- Set the value of varname (same as @set{}).
- gel.get(varname)
- Get the value of varname (same as @var{} in gema). Returns
nil if the variable is unassigned.
- gel.push(varname,value)
- Use varname as a stack and push a value on top (same as @push{}in
gema).
- gel.pop(varname)
- Use varname as a stack and pop the value on top (same as @pop{}in
gema). It also returns the popped value.
- gel.write(string)
- Write a string at the current position in the gema output (only works
if executed in a function called by gema with @lua{}).
- gel.parsestring(string,[domain,[output]])
- Translate the string using the rules defined into the named domain
and write the result to the output file. The output parameter can be
the name of a file to be created, or nil meaning that the result should
be returned as the value of the function.
If output is "-" the translation will be written in the current
gema output.
If domain is "" or nil the default domain will be used.
- gel.parsefile(file,[domain,[output]])
- Same as gel.parsestring but the text to be translated is taken from
the specified file.
- gel.parsestream(stream,[domain,[output]])
- Same as gel.parsestring but the text to be translated is taken from
the specified stream.
- gel.streamfile(filename)
- Create, from the specified file, a stream to be used with gel.parsestream()
- gel.streamstring(string)
- Create, from the given string, a stream to be used with gel.parsestream()
- gel.streamclose(stream)
- Close the given stream.
- gel.streameof(stream)
- Check if there is some text left in the stream.
- gel.streamgetc(stream)
- Get next char from the stream.
- gel.streampeek(stream)
- Returns te next char from the stream without advancing the stream.
- gel.rulefile(file)
- Read new patterns from the specified file. In gema it would be @define{@read{file}}
- gel.rulestring(string)
- Defines new patterns. Equivalent to @define{string}.
- gel.ruleclear(domain)
- Delete all patterns defined in the specified domain.
Here you will find some short examples on:
The best way to see GeL in action is to have a look at the
example directory in the distribution package.
4.1 Defining
lua functions
There are three methods for having lua functions defined:
- Write the functions in a file and execute it through the command line
-lua option
- Write the functions in a file and execute in an action through the
@lua{} function. This
method also allows you to load a different set of lua functions depending
on a match.
- Embed the lua functions in the gema file using the new syntax "!["
"!]"
Here you will find the same task solved using the three
methods.
Consider the following task as an example of a function
not available in gema (it could have been any other function not easily
definable in gema):
- Find numbers in a file and create another file with every number
replaced by its logarithm (if n > 0) or by the string "-infty"
(if n <= 0).
Let's assume that the lua function is stored in the inflog.lua
file:
function inflog(x)
if x>0 then return math.log(x)
else return "-infty"
end
end |
You can write a file inflog.gma
as follows:
<N>=@lua{return inflog($0)} |
And execute it with (method 1):
gel -lua inflog.lua -f inflog.gma dat1.dat dat2.dat |
Or you could write inflog.gma as follows (method 2):
@lua{dofile("inflog.lua")}
<N>=@lua{return inflog($0)} |
And execute it with:
gel -f inflog.gma dat1.dat dat2.dat |
Or you could forget inflog.lua,
write inflog.gel as follows
(method 3):
![
function inflog(x)
if x>0 then return math.log(x)
else return "-infty"
end
end
!]
<N>=@lua{return inflog($0)} |
And execute it with:
gel -f inflog.gel dat1.dat dat2.dat |
Note that the file extensions are totaly unimportant.
4.2 Returning values
from lua
Normally return values of lua functions are discarded. You
can have the first return value as result of the @lua{}
function using an explicit return
statement.
Another method is to use the gel.write
function.
To show how those two methods are used, let's consider the
following task:
- Collect identifiers and sourround them with "<id>"
and "</id>" tags. If it's not the first time you encounter
that identifers, add the attribute "first" to the id tag with
the line where you first encountered it as value. At the end, write
a sorted index of identifiers with the line where they first appear.
and a possible solution where both return
and gel.write are used:
![
id_ln={}; n_id={}; table.setn(n_id,0)
function check_id(id,ln)
local t=""
if id_ln[id] then
t=" first=\""..id_ln[id].."\""
else
id_ln[id]=ln
table.insert(n_id,id)
end
return "<id"..t..">"..id.."</id>"
end
function sort_id()
table.sort(n_id)
gel.write("\n")
for n,id in pairs(n_id) do
gel.write(id.." "..id_ln[id].."\n")
end
end
!]
<I>=@lua{return check_id("$0",@line)}
\Z=@lua{sort_id()} |
4.3 Accessing
gema variables
Gema has separate functions to manipulate variables, command
line switches and command line parameters. Gel provides a function to
get a value from lua and a function to set it. If the given name starts
with "-" it is considered a parameter or a switch (in that order).
The following table summarize the equivalence between Gel
and Gema constructs.
Gel |
Gema |
gel.get("n") |
@var{n} |
gel.get("n") |
$n |
gel.get("n")
or 0 |
@var{n;0} |
gel.get("n")
or 0 |
${n;0} |
gel.get("@line") |
@line |
gel.get("@column") |
@column |
gel.get("-k")* |
@get-switch(k)
|
gel.get("-idchars")* |
no equivalent |
gel.set("n",5) |
@set{n;5} |
gel.set("-k",1)* |
@set-switch{k;1} |
gel.set("-idchars",".")* |
@set-parm{idchars;.} |
gel.push("n",9) |
@bind{n;9} |
gel.push("n",9) |
@push{n;9} |
gel.pop("n") |
@unbind{n} |
gel.pop("n") |
@pop{n} |
*Not
yet implemented.
4.4 Parsing from Lua
Gel provides three lua functions to translate text according
to gema rules:
gel.parsestring() and gel.parsefile()and
gel.parsestream().
![
list_type = "" -- Set when the start of list is found
function li_dot(dot)
gel.write("<ld>")
if list_type == "desc" then
gel.parsestring(dot,"-","par")
elseif list_type == "enum" then
n=gel.get{"i"}
gel.write(n)
gel.set("i",n+1)
else
gel.write(dot)
end
gel.write("</ld>\n")
end
!]
list:\N\W[*]*\P\N\W[\G=<li>@lua{li_dot("$1")}@par{$2}
|
Gel was made by
Remo Dentato and enahanced by Reuben Thomas.
|