By exploiting the hierarchical nature of the file-systems
usually available on most computing platforms,
Tefigel strongly encourages a modular approach to the
construction of file-generation environments, such
as the SoProTech[tm] projects. In particular, subroutines,
functions, packages and libraries, all these modular
concepts are directly mapped in Tefigel
onto standard file-system capabilities, such as
files and directories.
One of the key features of Tefigel is its file-oriented
implementation of modular programming: Tefigel makes it extremely
easy to split the generation of a text file into reusable, modular
functions, identified by plain text files that can be
directly CALLed by other text files, possibly with
parameters, as shown in the following code examples.
|
Source code - File "java_setget"
|
1
2 // Set and get methods
3 @ java/set_get(String,Status,status)
4 @ java/set_get(ContactInformation,ContactInformation,info)
|
|
Output of
"/opt/somusar/bin/tefigel java_setget"
|
1
2 // Set and get methods
3 public void setStatus(String status) {
4 this.status = status;
5 }
6
7 public String getStatus() {
8 return status;
9 }
10
11 public void setContactInformation(ContactInformation info) {
12 this.info = info;
13 }
14
15 public ContactInformation getContactInformation() {
16 return info;
17 }
18
|
|
|
Source code - File "java/set_get"
|
1 @ interface(MEMBERTYPE,MEMBER,mEMBER)
2 @ dash $
3 public void set$MEMBER(MEMBERTYPE mEMBER) {
4 this.mEMBER = mEMBER;
5 }
6
7 public MEMBERTYPE get$MEMBER() {
8 return mEMBER;
9 }
10
11 @ dash
|
|
Beside file-functions, Tefigel provides a set of
frequently useful built-in functions, such as LENGTH, SUBSTR,
DATE, and several others. These functions are particularly
useful in conjunction with the current call key
(default: ~),
that allows on-the-fly textual substitution of function results,
as shown below.
|
Source code - File "call_key"
|
1 # Embed function calls into output text
2 This sample shows how to embed call to functions, in particular
3 built-ins like date, into plain text lines.
4 String manipulation functions, such as length and substr are
5 also built in tefigel:
6 length of "the quick brown fox" is ~length(the quick brown fox)
7 substr from position 4 of length 5 of "the quick brown fox" is
8 "~substr(the quick brown fox,4,5)"
9 @ callkey $
10 This script has been run on $date from file $cur_input
11 @ callkey
12 # callkey is now again the default ~
|
|
Output of
"/opt/somusar/bin/tefigel call_key"
|
1 This sample shows how to embed call to functions, in particular
2 built-ins like date, into plain text lines.
3 String manipulation functions, such as length and substr are
4 also built in tefigel:
5 length of "the quick brown fox" is 19
6 substr from position 4 of length 5 of "the quick brown fox" is
7 "quick"
8 This script has been run on Thu Sep 27 2012 from file call_key
|
|
Tefigel's call key is another example of special character,
introduced earlier in this tutorial,
as it can be dynamically changed to
allow for maximum flexibility with respect to the type of input
and output of Tefigel itself: a constant call key like,
for instance, $ would have caused syntax conflicts when
generating source files of languages - such as Unix® shells -
that associate a special meaning with the character $.
An extensive and modular use of Tefigel rapidly leads to a significant number
of Tefigel files, or subroutines, related to one another, that can be
collected together as one or more packages. Thanks to its file-oriented
approach, Tefigel packages are simply sub-directories within a
file-system, that can be freely grouped together at any
depth level within the file-system, and then CALLed by means
of their pathname.
Aimed at improving code readability, maintainability, and portability,
the instruction LIBRARY allows a Tefigel program to search
for packages, subroutines and functions under a specified file-system
path (the library), thus allowing CALLs to use relative paths
instead of absolute ones, as shown below.
Code Example 17 - Library of Tefigel packages
|
Use a simple list-processing package, consisting of a few subroutines
and functions, to show how to use the LIBRARY instruction (on line
18) to dynamically set an entry point to a hierarchical collection of
Tefigel packages. Note on lines 14 and 28 that the second
parameter to subroutine "list/process" is a list item processor,
namely "mkstring".
|
|
Source code - File "use_list"
|
1 @ mark call .
2 @ mark rem |
3 @ dash &
4 --------- Without library: use full pathnames to call tefigel functions
5 1) Create list.
6 . lib_root/list/create(EMPLOYEE)
7 2) Add items to list.
8 . lib_root/list/add(EMPLOYEE,John Smith)
9 . lib_root/list/add(EMPLOYEE,Mark Twain)
10 . lib_root/list/add(EMPLOYEE,Bill Young)
11 . lib_root/list/add(EMPLOYEE,Tom Rich)
12 3) List contents: '~lib_root/list/contents(EMPLOYEE)'
13 4) Process list:
14 . lib_root/list/process(EMPLOYEE,lib_root/mkstring)
15 . lib_root/list/delete(EMPLOYEE)
16 5) List contents after delete: '~lib_root/list/contents(EMPLOYEE)'
17 --------- With library: use package hierarchy to call tefigel functions
18 @ library lib_root
19 1) Create list.
20 . list/create(EMPLOYEE)
21 2) Add items to list.
22 . list/add(EMPLOYEE,John Smith)
23 . list/add(EMPLOYEE,Mark Twain)
24 . list/add(EMPLOYEE,Bill Young)
25 . list/add(EMPLOYEE,Tom Rich)
26 3) List contents: '~list/contents(EMPLOYEE)'
27 4) Process list:
28 . list/process(EMPLOYEE,mkstring)
29 . list/delete(EMPLOYEE)
30 5) List contents after delete: '~list/contents(EMPLOYEE)'
|
|
Output of
"/opt/somusar/bin/tefigel use_list"
|
1 --------- Without library: use full pathnames to call tefigel functions
2 1) Create list.
3 2) Add items to list.
4 3) List contents: 'John Smith|Mark Twain|Bill Young|Tom Rich'
5 4) Process list:
6 List item 1/4 - first name: "John"; last name: "Smith"
7 List item 2/4 - first name: "Mark"; last name: "Twain"
8 List item 3/4 - first name: "Bill"; last name: "Young"
9 List item 4/4 - first name: "Tom"; last name: "Rich"
10 5) List contents after delete: ''
11 --------- With library: use package hierarchy to call tefigel functions
12 1) Create list.
13 2) Add items to list.
14 3) List contents: 'John Smith|Mark Twain|Bill Young|Tom Rich'
15 4) Process list:
16 List item 1/4 - first name: "John"; last name: "Smith"
17 List item 2/4 - first name: "Mark"; last name: "Twain"
18 List item 3/4 - first name: "Bill"; last name: "Young"
19 List item 4/4 - first name: "Tom"; last name: "Rich"
20 5) List contents after delete: ''
|
|
Generic list processor - File "lib_root/list/process"
|
1 |
2 | General-purpose list processing function: scan a list and process
3 | each item applying a given item processor
4 |
5 @ interface(KEY,PROCESSOR)
6 |
7 | Copy keyed list into CURLIST and keyed count into COUNTER.
8 |
9 @ set CURLIST=~value(KEY&LIST)
10 @ set CURCOUNTER=~value(KEY&COUNT)
11 |
12 | Quit on empty lists
13 |
14 @ if CURCOUNTER<1
15 @ quit
16 @ endif
17 |
18 | Loop on list, and call PROCESSOR on each item
19 |
20 @ set I=0
21 @ while I<CURCOUNTER
22 |
23 | Extract i-th field (0-based) from list and pass it to PROCESSOR
24 | as (i+1)-th, so that it is 1-based -- easier then to check for
25 | last item.
26 |
27 @ set ITEM=~field(CURLIST,I,|)
28 @ add I 1
29 . PROCESSOR(I,CURCOUNTER,ITEM)
30 @ endwhile
|
|
Specific list item processor - File "lib_root/mkstring"
|
1 |
2 | Process I-th item "REC" out of N items by splitting it into
3 | two blank-separated fields, "FIRST_NAME" and "LAST_NAME".
4 |
5 @ interface(I,N,REC)
6 @ set FIRST_NAME=~field(REC,0, )
7 @ set LAST_NAME=~field(REC,1, )
8 List item I/N - first name: "FIRST_NAME"; last name: "LAST_NAME"
|
|
Therefore the task of creating, extending, and installing
a library of Tefigel packages simply consists in creating,
adding, and copying text files and directories to a file-system
directory that implements the Tefigel library itself.
Filters are Tefigel functions dynamically associated with
patterns expressed as regular expressions: when an input line after
processing is ready to be written out by Tefigel, a pattern check is
performed against
the filters currently defined (possibly none), activating the
corresponding filter in case of pattern match.
Code Example 18 - Filters
|
Tefigel FILTERs to print out a specific subset of C preprocessor
control lines: the first filter "h_control"
captures lines beginning with a #, the second one "h_skip"
skips all other lines. Note that the actual input file
"errno.h" is specified as a command line parameter to Tefigel.
|
|
Source code - File "h_filter"
|
1 @ mark rem |
2 @ filter h_control ^#
3 @ filter h_skip ^.*$
|
|
Output of
"/opt/somusar/bin/tefigel h_filter errno.h"
|
1 #ifndef _ERRNO_H
2 #ifndef __need_Emath
3 #include <features.h>
4 #endif
5 #include <bits/errno.h>
6 #ifdef _ERRNO_H
7 #ifndef errno
8 #endif
9 #ifdef __USE_GNU
10 #endif /* __USE_GNU */
11 #endif /* _ERRNO_H */
12 #endif /* _ERRNO_H */
13 #if defined __USE_GNU || defined __need_error_t
14 # ifndef __error_t_defined
15 # endif
16 #endif
|
|
Code Example 19 - Filter 1
|
Checks whether the C preprocessor control line should be
printed out or not, ignoring #define and #undef.
Note on lines 2 and 3 use of comparison operator
~
, pronounced "like".
|
|
Source code - File "h_control"
|
1 @ interface(LINE)
2 @ eval ignore LINE~^#[ ]*define
3 @ or ignore LINE~^#[ ]*undef
4 @ if ignore=0
5 LINE
6 @ endif
|
|
|
Source code - File "h_skip"
|
|
|
Filters are particularly useful in two cases:
- To extract a subset of information out of a heterogeneous input stream, as shown in the previous example;
- To reformat the contents of a homogeneous input stream, typically a list, or a table, as discussed later in the document.
[Previous chapter]
[Next chapter]
[Back to top]
|