Full list of in-depth articles -
Feedback and questions -
Request demo -
1 October 2004 - New features of Tefigel
1
| New features of the Tefigel language |
|
1.1
| Generation scripts and generation templates |
|
|
1.3
| Enhanced "for each" loops |
|
1.4
| String substitution made easy |
|
|
2.1
| String table generator |
|
|
2.3
| Simple string editing with replace |
|
2.4
| A cross-platform/cross-model/cross-IDE bridge |
|
The new version (099) of Tefigel
introduces some useful new
commands, built-in functions, and facilities that simplify
the implementation of complex software generation solutions.
When the logic of a software generator is not trivial, a clear
separation between generation templates and generation scripts is
recommendable: complex templates full of generation logic are
difficult to read and to maintain. The new command tefigel
allows to write complex generation scripts without the otherwise
necessary templating syntax burden.
Metadata from different sources usually require different data
records. Yet a software generator should be agile enough to
avoid complex constructs of data type definition and declaration,
as provided by most general-purpose programming languages. Tefigel
now provides means to dynamically group and ungroup
interrelated data items.
for loops that scan lists of items
often require special actions on the first and
last items of the lists. Automatic loop variables ..._counter
and ..._loops provide a useful help for such tasks.
One of the main activities of software generators is string
processing. In many cases output strings are derived from
simple manipulations of one common input string. The new built-in
function replace simplifies this frequent task.
The following self-contained examples demonstrate how to
use the new features described in this article.
Your new task is to write a set of tables of strings for a
number of different types of items. The strings must comply to
a scheme with different casing styles: default case, lower case,
upper case, and lower case with first letter in upper case.
The code that you have to write should look like the code
in the following listing.
String table generator - Target code [ File "string_tab.out" ]
|
String ElectronicMedia[] =
{ /* 1/4 */
"DVD.dvd.DVD.Dvd",
/* 2/4 */
"CD.cd.CD.Cd",
/* 3/4 */
"Videotape.videotape.VIDEOTAPE.Videotape",
/* 4/4 */
"Cartridge.cartridge.CARTRIDGE.Cartridge" };
String Fruits[] =
{ /* 1/5 */
"apple.apple.APPLE.Apple",
/* 2/5 */
"orange.orange.ORANGE.Orange",
/* 3/5 */
"banana.banana.BANANA.Banana",
/* 4/5 */
"grapefruit.grapefruit.GRAPEFRUIT.Grapefruit",
/* 5/5 */
"strawberry.strawberry.STRAWBERRY.Strawberry" };
String Colors[] =
{ /* 1/8 */
"RED.red.RED.Red",
/* 2/8 */
"GREEN.green.GREEN.Green",
/* 3/8 */
"BLUE.blue.BLUE.Blue",
/* 4/8 */
"YELLOW.yellow.YELLOW.Yellow",
/* 5/8 */
"PINK.pink.PINK.Pink",
/* 6/8 */
"VIOLET.violet.VIOLET.Violet",
/* 7/8 */
"BLACK.black.BLACK.Black",
/* 8/8 */
"WHITE.white.WHITE.White" };
|
As you have to write a number of such tables, you decide to
write a lightweight generator that takes as input the file below.
String table generator - Input [ File "string_tab.main" ]
|
@ tefigel
output string_tab.out
string_tab(ElectronicMedia,DVD/CD/Videotape/Cartridge)
string_tab(Fruits,apple/orange/banana/grapefruit/strawberry)
string_tab(Colors,RED/GREEN/BLUE/YELLOW/PINK/VIOLET/BLACK/WHITE)
|
There are several minor details to take care of, thus the generator
logic is more than the required templating. This is a good opportunity
to take advantage of the tefigel and enhanced for
loop of Tefigel version 099. The core generator routine "string_tab"
is listed below.
String table generator - Main routine [ File "string_tab" ]
|
@ tefigel
interface(table_name,items)
# Use some blanks to indent table rows
set indent=
echo String table_name[] =
# items are slash-separated: scan the list using a
# slash-driven FOR loop
argdelim /
for item=items
set before= indent
set after=,
case item_counter
when=1
set before=indent{
when=item_loops
set after= };
endcase
set lc_item=~to_lower(item)
set UC_item=~to_UPPER(item)
set Uc_item=~to_Upper(item)
echo before/* item_counter/item_loops */
echo indent "item.lc_item.UC_item.Uc_item"after
endfor
argdelim
echo
|
Codefile "groups.main" below illustrates how to use:
- group to dynamically create lists of structured data while collecting metadata;
- ungroup to expand the structured data while generating the required software.
Sample use of group/ungroup - Input [ File "groups.main" ]
|
@ tefigel
echo Create a list of writers using dynamic data groups
new_list(Writers)
addWriter(Mark,Twain,1835-1910)
addWriter(William,Shakespeare,1564-1616)
addWriter(Jane,Austen,1775-1817)
echo The list contains:
echo "~list_contents(Writers)"
echo Scan the list ungrouping the items:
for cur_writer=~list_contents(Writers)
ungroup(cur_writer,|,FirstName,LastName,Dates)
echo writer #cur_writer_counter is LastName (FirstName) [Dates]
endfor
|
The output produced by the script above is listed below.
Sample use of group/ungroup - Output [ File "groups.out" ]
|
Create a list of writers using dynamic data groups
The list contains:
"Mark|Twain|1835-1910,William|Shakespeare|1564-1616,Jane|Austen|1775-1817"
Scan the list ungrouping the items:
writer #1 is Twain (Mark) [1835-1910]
writer #2 is Shakespeare (William) [1564-1616]
writer #3 is Austen (Jane) [1775-1817]
|
The following listing shows the code of subroutine "addWriter".
Sample use of group/ungroup - Subroutine [ File "addWriter" ]
|
@ tefigel
interface(FirstName,LastName,Dates)
add_item(Writers,~group(|,FirstName,LastName,Dates))
|
Two nested for loops expand a set of input file names
into a cartesian product of output file names with different
extensions.
Sample use of replace - Input [ File "replace.main" ]
|
@ tefigel
set base_ext=in
for file_name=table1.in,table2.in,figure1.in
for out_ext=html,txt,ps,pdf
set out_name=~replace(file_name,base_ext,out_ext)
echo Would generate "out_name" from "file_name"
endfor
echo
endfor
|
The output generated by the script above is listed below.
Sample use of replace - Output [ File "replace.out" ]
|
Would generate "table1.html" from "table1.in"
Would generate "table1.txt" from "table1.in"
Would generate "table1.ps" from "table1.in"
Would generate "table1.pdf" from "table1.in"
Would generate "table2.html" from "table2.in"
Would generate "table2.txt" from "table2.in"
Would generate "table2.ps" from "table2.in"
Would generate "table2.pdf" from "table2.in"
Would generate "figure1.html" from "figure1.in"
Would generate "figure1.txt" from "figure1.in"
Would generate "figure1.ps" from "figure1.in"
Would generate "figure1.pdf" from "figure1.in"
|
SoProMach can be used as a software generator with different IDEs (Integrated
Development Environments) such as Eclipse 3 and Visual Basic Express
2005 Beta 1 (see articles [1] and
[2]. This type of integration may involve
different platforms (Windows, Linux, Mac OS X). Moreover,
the input model to SoProMach can be a Sisendel
entity file or an XML file.
This implies that portability has three dimensions:
across platforms, across IDEs, and across model types.
The following Tefigel codefile realizes this type of 3D bridge
as required for the IDE-SoProMach integration case studies described
in the aforementioned articles.
Bridging different IDEs with SoProMach on different platforms [ File "ide_bridge.tfg" ]
|
@ tefigel
interface(file_path)
if init_tfg=
globset init_tfg=1
else
set init_tfg=0
endif
set running_on=~cur_platform
if running_on=Windows
set path_slash=\
set spm_script=w4_rungen.bat
set cmd_concat=&&
else
set path_slash=/
set spm_script=u4_rungen
set cmd_concat=;
endif
set path_depth=~field_count(file_path,path_slash)
sub path_depth 1
set file_name=~field(file_path,path_depth,path_slash)
set dir_length=~length(file_path)
sub dir_length ~length(file_name)
sub dir_length 1
set file_dir=~substr(file_path,0,dir_length)
set dot_extensions=~field_count(file_name,.)
sub dot_extensions 1
if dot_extensions>0
set file_extension=~field(file_name,dot_extensions,.)
else
set file_extension=
endif
if init_tfg=1
dash &
globset poc_path=file_dir&path_slash
dash
hook NEW_INPUT=file_path
else
hook NEW_INPUT=
case file_extension
when=ef
dash !
system cd poc_path cmd_concat poc_path!spm_script "file_path" "file_dir" "file_name"
dash
when=xml
dash !
system cd poc_path cmd_concat poc_path!spm_script "file_path" "file_dir" "~replace(file_name,.xml,)"
dash
otherwise
msg [warning] unexpected file extension "file_extension"
endcase
exit 0
endif
|
Updated on 29 October 2004
Full list of in-depth articles -
Feedback and questions -
Request demo -
|