|
|
|
|
|
|
Somusar/Tefigel[tm]
A Tutorial Introduction Francesco Aliverti-Piuri Copyright © 2003-2007 Somusar |
|
|
|
|
|
|
|
|
|
Unix is a registered trademark in the United States and other countries, licensed exclusively through X/Open Company Limited.
Linux is a registered trademark of Linus Torvalds in the United States and other countries.
Sun, Sun Microsystems, the Sun logo, Solaris, Java, and all Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.
Symbian and all Symbian-based marks and logos are trademarks of Symbian Software Limited.
Apple and Mac OS are registered trademarks of Apple Computer, Inc. in the United States and other countries.
Intel is a registered trademark of Intel Corporation in the United States and other countries.
PowerPC and CICS are registered trademarks of International Business Machines Corporation in the United States and other countries.
Microsoft, Windows, Visual Basic are either trademarks or registered trademarks of Microsoft Corp. in the United States and/or other countries.
Oracle is a registered trademark, and PL/SQL is a trademark of Oracle Corporation.
SAP and ABAP/4 are registered trademarks of SAP AG in Germany and several other countries.
PostScript is a registered trademark of Adobe Systems Incorporated in the United States and/or other countries.
So.mus.ar, the Somusar logo, Somusar/Software Production Technique, Somusar/Software Production Machine, Somusar/Sisendel, Somusar/Tefigel, Somusar/SoProTech, Somusar/SoProMach, Somusar/Software Entity, Somusar/Software Mold, Somusar/Software Mold Kit, Somusar/Software Mold Building, Somusar/Code Generator Building, Somusar/Generator Building, and Somusar/File Generation Scheme are trademarks of so.mus.ar. s.a.s. in Italy, in the European Union, in the United States of America and other countries.
Other trademarks or service marks referenced herein are property of their respective owners.
| Code Examples | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Figures | ||
|---|---|---|
| ||
This document is an introduction to the syntax, semantics and
usage of Somusar/Tefigel[tm], a
computer language and translator specifically designed to efficiently
assemble source files for virtually any computer language.
As an example, the HTML version of this very document, including all
of its code examples, has been assembled using Somusar/Tefigel[tm] - shortly
referred to as Tefigel.
Tefigel is a complete stand-alone tool, but its powerful features
are particularly useful within the Somusar/Software Production Technique[tm], described in
"Somusar/Software Production Technique[tm]: An Introduction
", where Tefigel is used as back-end language.
Main functions of Tefigel are:
The Somusar/Tefigel[tm] language processor is
currently available for the
following platforms:
Tefigel can be concisely defined as a
generalized, versatile file-oriented text and macro processor,
that significantly reduces repetitive copy & paste
activities during software development projects.
Hereinafter both the Somusar/Tefigel[tm] language and translator
are referred to simply as Tefigel.
Additional details
and the exact definition of the syntax and semantics of
Tefigel are provided in
"Somusar/Tefigel[tm]: Reference Guide
".
Basic elements of Tefigel programs and scripts are text files
and text lines, intermixed with Tefigel instructions and comments,
and name spaces of string, numeric and boolean variables.
In short, for the purpose of this document these elements can
be defined as follows:
Traditional programming language constructs, such as
control flow and arithmetic and boolean computation instructions, are
of course also available in Tefigel. These constructs have been
purposely designed and implemented in a very simple form for two reasons:
Finally, Tefigel's capabilities include simple constructs
to control its input and output flows, enabling the processing
of several input files, as well as the production of several output files.
The basic unit of work of Tefigel is the text file: the concept of Tefigel program or script is in fact purposely not clearly defined by the language, so that the translator can process any type of text file, independently of its contents and name or suffix. Nevertheless, usual programming concepts like instructions, comments and variables are clearly defined, as explained in the next paragraphs of this chapter.
Traditionally, the first code example of a computer language has always been a "Hello, world!" program. Tefigel copies most of its input to its output, apart from variables substitution and execution of instructions. Thus, Tefigel allows such a "Hello" program to be written in its simplest form as follows.
The simplest Somusar/Tefigel[tm] program: the traditional one-line greeting message. No actual processing takes place: input is copied to output. |
| Source code - File "hello_world" |
1 Hello, world!
|
| Output of "/opt/somusar/bin/tefigel hello_world" |
1 Hello, world!
|
A slightly more complex implementation of this example involves a variable and an instruction, namely ECHO, as follows.
Code Example 2 - Hello world II
Set a variable and write it out with an instruction. Note that contents of variable "greeting" is accessed by simply naming it where required, even between double quotes ". |
| Source code - File "hello_world.2" |
1 @ set greeting=Hello, world!
2 @ echo greeting
3 Here it comes once again: greeting, and again: "greeting".
|
| Output of "/opt/somusar/bin/tefigel hello_world.2" |
1 Hello, world!
2 Here it comes once again: Hello, world!, and again: "Hello, world!".
|
Tefigel commands consist of either lines beginning with a Tefigel instruction (that is, a recognized uppercase word), or lines beginning with the current command marker, as shown in the following example.
Short example introducing command lines, variables and the concept of command marker. |
| Source code - File "plain_cmd" |
1 Text lines, not to be altered by tefigel, as they contain neither
2 tefigel variables, nor tefigel commands.
3 @ echo Command line, echo message.
4 @ set MESSAGE="Hello!"
5 % echo Not a command line (yet), but contains a variable: MESSAGE.
6 @ mark CMD %
7 % echo Now a command line, due to command mark CMD. Variable: MESSAGE.
8 % unset MESSAGE
9 % echo After unset, variable MESSAGE is no longer a variable.
10 % mark CMD
11 % echo '%' is no longer the command line marker.
12 Some more text lines, not to be altered by tefigel, as they contain
13 neither tefigel variables, nor tefigel commands. Note that white
14 s p a c e s within text lines are left untouched.
|
| Output of "/opt/somusar/bin/tefigel plain_cmd" |
1 Text lines, not to be altered by tefigel, as they contain neither
2 tefigel variables, nor tefigel commands.
3 Command line, echo message.
4 % echo Not a command line (yet), but contains a variable: "Hello!".
5 Now a command line, due to command mark CMD. Variable: "Hello!".
6 After unset, variable MESSAGE is no longer a variable.
7 % echo '%' is no longer the command line marker.
8 Some more text lines, not to be altered by tefigel, as they contain
9 neither tefigel variables, nor tefigel commands. Note that white
10 s p a c e s within text lines are left untouched.
|
The variable command marker plays an important role in making Tefigel more widely usable. In fact, several computer languages define a constant command marker, such as # in C/C++ preprocessing, or * in RPG comments, or C in Fortran comments: Tefigel's variable command marker allows Tefigel instructions to be intermixed with, and easily recognizable within, virtually any textual computer language. The default command marker is the character @, but it can be set to any other character, as shown in the previous example.
Tefigel comments can be written in two ways, as the next example
shows:
Tefigel comments using instruction REM or a variable comment marker. |
| Source code - File "comments" |
1 ------------ Commenting via default "#" -------------------------------
2 Plain text before the first comment.
3 # This is a tefigel comment, and will be ignored
4 # by the tefigel translator
5 Plain text after the first comment.
6 ------------ Commenting via a new comment marker (1: use "|") -------
7 @ mark rem |
8 Plain text before the second comment.
9 | After command mark rem above, lines starting with a |
10 | are treated as comments.
11 Plain text after the second comment.
12 ------------ Commenting via a different comment marker (2: use "%") -------
13 @ mark rem %
14 Plain text before the third comment.
15 % After command mark rem above, lines starting with a %
16 % are treated as comments.
17 Plain text after the third comment.
18 | Note that lines starting with a | are no longer
19 | treated as comments.
|
| Output of "/opt/somusar/bin/tefigel comments" |
1 ------------ Commenting via default "#" -------------------------------
2 Plain text before the first comment.
3 Plain text after the first comment.
4 ------------ Commenting via a new comment marker (1: use "|") -------
5 Plain text before the second comment.
6 Plain text after the second comment.
7 ------------ Commenting via a different comment marker (2: use "%") -------
8 Plain text before the third comment.
9 Plain text after the third comment.
10 | Note that lines starting with a | are no longer
11 | treated as comments.
|
As shortly introduced above, Tefigel features an enhanced preprocessor-like approach: the first character in an input text line may have a special function, such as being a command or comment marker. The definition of a marker is achieved using instruction MARK, which allows to define several types of markers: beyond commands and comments, also function/subroutine CALLs can be associated with a marker.
Use of Tefigel markers. |
| Source code - File "markers" |
1 @ rem Plain comment
2 @ echo Plain command with default command marker '@'
3 @ mark rem |
4 @ mark CMD %
5 | Comment with new comment marker '|'
6 % echo Command with new command marker '%'
7 Plain text line with placeholder.
8 % set placeholder=<some text>
9 Plain text line with placeholder.
|
| Output of "/opt/somusar/bin/tefigel markers" |
1 Plain command with default command marker '@'
2 Command with new command marker '%'
3 Plain text line with placeholder.
4 Plain text line with <some text>.
|
Another dynamic syntax construct of Tefigel consists in its
set of special characters, which are special-purpose operators
that can be used within normal text lines and dynamically changed
using appropriate instructions.
Special characters include a DASH operator - explained in a
following paragraph - to concatenate strings and create name-value contents
association; a LINEBREAK operator,
to split one input logical line across two or more physical lines;
a CALLKEY operator, to issue function calls from within text lines;
and a few more.
Split a logical line on two physical lines, and concatenate strings using the current dash operator. |
| Source code - File "special_chars" |
1 Text on two physical lines %
2 separated by a '%'
3 @ linebreak %
4 Text on two physical lines %
5 separated by a '%'
6 -----------
7 Line with a bro-ken word
8 @ dash -
9 Line with a bro-ken word
10 -----------
|
| Output of "/opt/somusar/bin/tefigel special_chars" |
1 Text on two physical lines %
2 separated by a '%'
3 Text on two physical lines separated by a '%'
4 -----------
5 Line with a bro-ken word
6 Line with a broken word
7 -----------
|
Tefigel variables are basically placeholders for character strings, although basic arithmetic and boolean operations can be performed on them, if the value that they hold allows such operations. The next example briefly shows how Tefigel variables can be used.
Variables can be of different types (strings, numbers and boolean), although they are all internally treated as strings, and function as placeholders. |
| Source code - File "plain_var" |
1 Following variables:
2 - "Number"
3 - "Class"
4 - "BoolCondition"
5 - "String"
6 - "Identifier"
7 - "Empty"
8 are currently not set.
9 @ set Number=256
10 @ set Class=Customer
11 @ set Identifier=some_id
12 @ eval BoolCondition Number>0
13 @ set String= plain string with some blanks and various quotes ("'`)
14 @ set Empty=
15 @ add Number Number
16 ------------------ After set and eval:
17 Following variables are now placeholders:
18 - "Number"
19 - "Class"
20 - "BoolCondition"
21 - "String"
22 - "Identifier"
23 - "Empty"
|
| Output of "/opt/somusar/bin/tefigel plain_var" |
1 Following variables:
2 - "Number"
3 - "Class"
4 - "BoolCondition"
5 - "String"
6 - "Identifier"
7 - "Empty"
8 are currently not set.
9 ------------------ After set and eval:
10 Following variables are now placeholders:
11 - "512"
12 - "Customer"
13 - "1"
14 - " plain string with some blanks and various quotes ("'`)"
15 - "some_id"
16 - ""
|
Two very important operations that can be applied to Tefigel variables via the current dash are string concatenation, shown in the next example, and contents association stored into so-called associative variables; the latter topic requires a more complex example and is described later in the document.
Code Example 8 - String concatenation via DASH
Usage of string concatenation via DASH to generate a Java set method. |
| Source code - File "string_cat" |
1 @ dash $
2 @ set MEMBER=Quantity
3 @ set MEMBERTYPE=int
4 public void set$MEMBER(MEMBERTYPE a$MEMBER) {
5 this.MEMBER = a$MEMBER;
6 }
|
| Output of "/opt/somusar/bin/tefigel string_cat" |
1 public void setQuantity(int aQuantity) {
2 this.Quantity = aQuantity;
3 }
|
String concatenation and contents association allow Tefigel users to group Tefigel variables in aggregates like records, lists, mappings and arrays, which are globally referred to as associative variables.
The dash operator is also variable as the command and comment markers previously discussed, to allow Tefigel to flexibly deal with the variety of syntax rules and tokens of as many computer languages as possible.
Tefigel variables are grouped in nested name spaces, or scopes, which are created and deleted either implicitly when a CALL to a subroutine or function is issued, or explicitly by means of PUSH and POP, as shown in the following example.
Three nested variables namespaces. |
| Source code - File "namespaces" |
1 Namespace 1) Variable "eks" currently evaluates to 'X'.
2 @ set X=
3 Namespace 1) Variable "eks" now evaluates to 'X'.
4 @ set X=namespace 1
5 Namespace 1) Variable "eks" now evaluates to 'X'.
6 @ push
7 Namespace 2) Variable "eks" now evaluates to 'X'.
8 @ set X=namespace 2
9 Namespace 2) Variable "eks" now evaluates to 'X'.
10 @ push
11 Namespace 3) Variable "eks" now evaluates to 'X'.
12 @ set X=namespace 3
13 Namespace 3) Variable "eks" now evaluates to 'X'.
14 @ pop
15 Namespace 2) Variable "eks" now evaluates to 'X'.
16 @ set X=namespace 2, second value
17 Namespace 2) Variable "eks" now evaluates to 'X'.
18 @ pop
19 Namespace 1) Variable "eks" now evaluates to 'X'.
20 @ unset X
21 Namespace 1) Variable "eks" now evaluates to 'X'.
|
| Output of "/opt/somusar/bin/tefigel namespaces" |
1 Namespace 1) Variable "eks" currently evaluates to 'X'.
2 Namespace 1) Variable "eks" now evaluates to ''.
3 Namespace 1) Variable "eks" now evaluates to 'namespace 1'.
4 Namespace 2) Variable "eks" now evaluates to 'namespace 1'.
5 Namespace 2) Variable "eks" now evaluates to 'namespace 2'.
6 Namespace 3) Variable "eks" now evaluates to 'namespace 2'.
7 Namespace 3) Variable "eks" now evaluates to 'namespace 3'.
8 Namespace 2) Variable "eks" now evaluates to 'namespace 2'.
9 Namespace 2) Variable "eks" now evaluates to 'namespace 2, second value'.
10 Namespace 1) Variable "eks" now evaluates to 'namespace 1'.
11 Namespace 1) Variable "eks" now evaluates to 'X'.
|
A global name space is also always available via the instruction GLOBSET, which is useful for example to preserve context across subsequent CALLs to the same subroutine. Name spaces are actually very seldom used explicitly via PUSH and POP; in fact, they are internally used by Tefigel to save/restore context before and after subroutine CALLs.
Tefigel provides all the basic tools usually available in most, if not all, procedural languages to enable the implementation of sequential algorithms and to convert an input flow into an output flow, namely computation of arithmetic and logical - or boolean - expressions, language structures to control the processing flow, and input/output instructions to manage the inbound and outbound data flows.
Tefigel has been designed mainly for generating text files and not for complex, general-purpose software systems. Its set of arithmetic instructions comprises thus very basic operations, such as ADD, SUB, MUL, DIV, TRUNC, NEG, as shown by the next example. All computations are performed in floating point, as for a pocket calculator.
Simple arithmetic computations: two divisions on lines 5 and 9, and a subtraction on line 7. |
| Source code - File "arith" |
1 # Sample arithmetic computation
2 @ set A=3
3 @ set B=6
4 @ set C=B
5 @ div C A
6 B divided by A yields C
7 @ sub B 1
8 @ set C=B
9 @ div C A
10 B divided by A yields C
|
| Output of "/opt/somusar/bin/tefigel arith" |
1 6 divided by 3 yields 2
2 5 divided by 3 yields 1.666666666666667
|
Control flow in Tefigel is supported by traditional constructs, such as IF..ELSE..ENDIF and WHILE..ENDWHILE. Additionally, instructions LABEL, JUMP, and JUMPCOND allow conditional and unconditional branching. A simple loop is illustrated by the next example.
Loop three times, printing out a message on each loop. |
| Source code - File "loop" |
1 ---- Begin loop
2 @ loop I=0,2
3 loop #I
4 @ endloop
5 ---- End loop
|
| Output of "/opt/somusar/bin/tefigel loop" |
1 ---- Begin loop
2 loop #0
3 loop #1
4 loop #2
5 ---- End loop
|
As for arithmetic computation, the language constructs for boolean computation are very primitive in Tefigel: the set of boolean instructions consists of instructions EVAL, AND, OR and NOT, whereas the set of boolean test operators consists of:
Code Example 12 - Boolean computation and control flow
An example of logical computation is given on lines 6 and 7. Conditional control flow (IF..ELSE..ENDIF) is illustrated on lines 8-10-12 and 14-16-18. An example of unconditional branching (goto) is provided on lines 4 and 19. |
| Source code - File "logical" |
1 @ set A=true
2 @ set B=false
3 @ set C=unknown
4 @ label back
5 ---- Begin logical expression evaluation
6 @ eval expr A#B
7 @ and expr A#C
8 @ if expr=1
9 A, B, C are all different
10 @ else
11 A, B, C are not all different
12 @ endif
13 ---- End logical expression evaluation
14 @ if C=true
15 @ quit
16 @ else
17 @ set C=true
18 @ endif
19 @ jump back
|
| Output of "/opt/somusar/bin/tefigel logical" |
1 ---- Begin logical expression evaluation
2 true, false, unknown are all different
3 ---- End logical expression evaluation
4 ---- Begin logical expression evaluation
5 true, false, true are not all different
6 ---- End logical expression evaluation
|
Another main function of Tefigel is constituted by
its set of input and output control instructions.
Input flow is managed by means of instructions
PROCESS and CALL, which respectively allow
to process an input file in the same or in a new
name space, or by means of instruction
ATTACH which barely attaches the contents of a given file
to Tefigel's output without actually processing it - that is,
without applying neither variable substitution nor instruction
recognition.
Output flow is managed by means of instructions OUTPUT and
APPEND, which redirect the standard output of Tefigel to a given
file, respectively creating it from scratch, or extending it by appending
new text to the text that it previously contained.
Create two output files "outp1" and "outp2" on lines 2 and 7, and extend "outp1" on line 12. Contents are provided by three input files "inp1", "inp2" and "inp3", each of which gets in turn PROCESSed, CALLed and ATTACHed. Note that standard output is left empty, as no output text appears before the first OUTPUT instruction. |
| Source code - File "in_out" |
1 @ set GREETING=Hello!
2 @ output outp1
3 @ process inp1
4 @ call inp2
5 @ attach inp3
6 @ set GREETING=Good morning!
7 @ output outp2
8 @ call inp1
9 @ attach inp2
10 @ process inp3
11 @ set GREETING=Goodbye!
12 @ append outp1
13 @ attach inp1
14 @ process inp2
15 @ call inp3
|
| Output of "/opt/somusar/bin/tefigel in_out" |
|
|
The resulting contents of the output files of this example are listed below.
| First output file - File "outp1" |
|---|
1 [File "inp1"] Today's greeting is Hello!
2 [File "inp2"] Today's greeting is Hello!
3 [File "inp3"] Today's greeting is GREETING
4 [File "inp1"] Today's greeting is GREETING
5 [File "inp2"] Today's greeting is Goodbye!
6 [File "inp3"] Today's greeting is Goodbye!
|
| Second output file - File "outp2" |
|---|
1 [File "inp1"] Today's greeting is Good morning!
2 [File "inp2"] Today's greeting is GREETING
3 [File "inp3"] Today's greeting is Good morning!
|
The actual contents of the input files of this example are listed below.
| First input file - File "inp1" |
|---|
1 [File "inp1"] Today's greeting is GREETING
|
| Second input file - File "inp2" |
|---|
1 [File "inp2"] Today's greeting is GREETING
|
| Third input file - File "inp3" |
|---|
1 [File "inp3"] Today's greeting is GREETING
|
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.
Generate a Java code fragment with set and get methods for some class members. |
| 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
|
Code Example 15 - Subroutine for Java[tm] set/get
Arguments supplied to CALL are made available to subroutines and functions via automatic positional assignments performed by the INTERFACE instruction. |
| 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.
Code Example 16 - Call key and built-ins
Usage of CALLKEY and built-ins within a text file. |
| 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 Tue Feb 27 2007 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.
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.
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
|
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
|
Completely empty script, ignores input and produces no output. |
| Source code - File "h_skip" |
|
|
Filters are particularly useful in two cases:
During the design of Tefigel particular care has been taken to keep
its syntax as flexible as possible, and allow to use it
to generate source files for as many computer languages as
possible, at the light of the SoProTech[tm]
discussed in
"Somusar/Software Production Technique[tm]: An Introduction
".
The next chapters contain several short
examples where Tefigel is used to produce fragments of source
code in different languages belonging to different language
classes:
The numerous examples of the next paragraphs, as well as
the other various code examples
scattered across this document, should provide sufficient confidence and
insight on the fact that Tefigel can be easily applied as a
generic precompiler to practically any computer language,
including - beyond the aforelisted languages -
several other general-purpose and special-purpose languages
and protocols, such as:
As previously noted, this broad range of applicability was not
a merely theoretical target of Tefigel; instead, it was one of
the main practical objectives while designing Tefigel as a
back-end language for the SoProTech[tm].
It is worthwile noting that the next simple examples aim at demonstrating
the syntactical applicability of Tefigel and its flexibility
in the generation of
software in the different languages shown below; its
practical and industrial applicability are best
described in
"Somusar/Software Production Technique[tm]: An Introduction
".
The only requirement for a computer language to be generatable
by the current version of Tefigel is that its source code can be written in a
single-byte character set.
Generate set and get methods for two members of a Java class. |
| Source code - File "language/j_getset" |
1 @ dash &
2 @ language/java/get_set(int,Quantity,quantity)
3 @ language/java/get_set(double,Percentage,percentage)
|
| Output of "/opt/somusar/bin/tefigel language/j_getset" |
1 public int getQuantity() {
2 return quantity;
3 }
4
5 public void setQuantity( int quantity ) {
6 this.quantity = quantity;
7 }
8
9 public double getPercentage() {
10 return percentage;
11 }
12
13 public void setPercentage( double percentage ) {
14 this.percentage = percentage;
15 }
16
|
| Java[tm] get/set subroutine - File "language/java/get_set" |
|---|
1 @ interface(TYPE,IdId,idId)
2 public TYPE get&IdId() {
3 return idId;
4 }
5
6 public void set&IdId( TYPE idId ) {
7 this.idId = idId;
8 }
9
|
Generate set and get methods for two members of a C# class. |
| Source code - File "language/cs_getset" |
1 @ dash &
2 @ language/cs/get_set(int,Quantity,quantity)
3 @ language/cs/get_set(double,Percentage,percentage)
|
| Output of "/opt/somusar/bin/tefigel language/cs_getset" |
1 public int Quantity {
2 get {
3 return quantity;
4 }
5 set {
6 quantity = value;
7 }
8 }
9
10 public double Percentage {
11 get {
12 return percentage;
13 }
14 set {
15 percentage = value;
16 }
17 }
18
|
| C# get/set subroutine - File "language/cs/get_set" |
|---|
1 @ interface(TYPE,IdId,idId)
2 public TYPE IdId {
3 get {
4 return idId;
5 }
6 set {
7 idId = value;
8 }
9 }
10
|
Generate set and get methods for two members of a C++ class. |
| Source code - File "language/cpp_getset" |
1 @ dash &
2 @ language/cpp/get_set(int,Quantity,quantity)
3 @ language/cpp/get_set(double,Percentage,percentage)
|
| Output of "/opt/somusar/bin/tefigel language/cpp_getset" |
1 int getQuantity() {
2 return quantity;
3 }
4
5 void setQuantity( int quantity ) {
6 this->quantity = quantity;
7 }
8
9 double getPercentage() {
10 return percentage;
11 }
12
13 void setPercentage( double percentage ) {
14 this->percentage = percentage;
15 }
16
|
| C++ get/set subroutine - File "language/cpp/get_set" |
|---|
1 @ interface(TYPE,IdId,idId)
2 TYPE get&IdId() {
3 return idId;
4 }
5
6 void set&IdId( TYPE idId ) {
7 this->idId = idId;
8 }
9
|
Generate a set of homogeneous buttons for an HTML form. Lines 6-9 show an example of variable number of arguments provided to a Tefigel subroutine. |
| Source code - File "language/html/formbuttons" |
1 #
2 # HTML document browsing buttons
3 #
4 <table cellpadding=0 cellspacing=0>
5 <tr>
6 @ language/html/formbutton(First)
7 @ language/html/formbutton(Prev,Prev.)
8 @ language/html/formbutton(Next)
9 @ language/html/formbutton(Last)
10 </tr>
11 </table>
|
| Output of "/opt/somusar/bin/tefigel language/html/formbuttons" |
1 <table cellpadding=0 cellspacing=0>
2 <tr>
3 <td>
4 <input type="BUTTON" width=60 name="First" value="First">
5 </td>
6 <td>
7 <input type="BUTTON" width=60 name="Prev" value="Prev.">
8 </td>
9 <td>
10 <input type="BUTTON" width=60 name="Next" value="Next">
11 </td>
12 <td>
13 <input type="BUTTON" width=60 name="Last" value="Last">
14 </td>
15 </tr>
16 </table>
|
| HTML subroutine - File "language/html/formbutton" |
|---|
1 #
2 # HTML form button
3 #
4 @ interface(NAME,label)
5 @ if label=
6 @ set label=NAME
7 @ endif
8 @ set WIDTH=60
9 <td>
10 <input type="BUTTON" width=WIDTH name="NAME" value="label">
11 </td>
|
Produce two sets of XML nested tags, complete with values. Depth depends on the number of input parameters. |
| Source code - File "language/xml.in" |
1 @ dash $
2 @ language/xml(Tag1=Value1,Tag2=Value2)
3
4 @ linebreak \
5 @ language/xml(\
6 TagA=ValueA,\
7 TagB=ValueB,\
8 TagC=ValueC,\
9 TagD=ValueD)
10
|
| Output of "/opt/somusar/bin/tefigel language/xml.in" |
1 <Tag1>
2 Value1
3 <Tag2>
4 Value2
5 </Tag2>
6 </Tag1>
7
8 <TagA>
9 ValueA
10 <TagB>
11 ValueB
12 <TagC>
13 ValueC
14 <TagD>
15 ValueD
16 </TagD>
17 </TagC>
18 </TagB>
19 </TagA>
20
|
| XML subroutine - File "language/xml" |
|---|
1 @ set I=0
2 @ set INDENT=
3 @ set BLANKS=
4 #
5 # Scan list of arguments, printing
6 # out indented open tag clause and value
7 #
8 @ while I<REG_COUNT
9 @ set ITEM=REG_$I
10 @ set TAG$I=~field(ITEM,0,=)
11 @ set VAL$I=~field(ITEM,1,=)
12 @ set IND$I=INDENT
13 INDENT<~value(TAG$I)>
14 INDENT$BLANKS~value(VAL$I)
15 @ set INDENT=~value(IND$I)BLANKS
16 @ add I 1
17 @ endwhile
18 #
19 # Scan list of arguments backward, printing
20 # out indented close tag clause
21 #
22 @ while I>0
23 @ sub I 1
24 ~value(IND$I)</~value(TAG$I)>
25 @ endwhile
|
Generate a short SOAP request and response, as per Example 1 of document http://www.w3.org/TR/2000/NOTE-SOAP-20000508 |
| Source code - File "language/soap" |
1 ---- Simple SOAP Request ----
2 @ language/soap_code(GetLastTradePrice,symbol/DIS)
3 ---- Simple SOAP Response ----
4 @ language/soap_code(GetLastTradePriceResponse,Price/34.5)
|
| Output of "/opt/somusar/bin/tefigel language/soap" |
1 ---- Simple SOAP Request ----
2 <SOAP-ENV:Envelope
3 xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
4 SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
5 <SOAP-ENV:Body>
6 <m:GetLastTradePrice xmlns:m="Some-URI">
7 <symbol>DIS</symbol>
8 </m:GetLastTradePrice>
9 </SOAP-ENV:Body>
10 </SOAP-ENV:Envelope>
11 ---- Simple SOAP Response ----
12 <SOAP-ENV:Envelope
13 xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
14 SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
15 <SOAP-ENV:Body>
16 <m:GetLastTradePriceResponse xmlns:m="Some-URI">
17 <Price>34.5</Price>
18 </m:GetLastTradePriceResponse>
19 </SOAP-ENV:Body>
20 </SOAP-ENV:Envelope>
|
| SOAP request/response fragment - File "language/soap_code" |
|---|
1 #
2 # REQUEST_RESPONSE_ID contains id of request or response
3 #
4 @ interface(REQUEST_RESPONSE_ID,PARAM_INFO)
5 #
6 # PARAM_INFO contains tag/id of parameter #1 - note "/" used as a separator
7 #
8 @ set PARAM_TAG_1=~field(PARAM_INFO,0,/)
9 @ set PARAM_ID_1=~field(PARAM_INFO,1,/)
10 <SOAP-ENV:Envelope
11 xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
12 SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
13 <SOAP-ENV:Body>
14 <m:REQUEST_RESPONSE_ID xmlns:m="Some-URI">
15 <PARAM_TAG_1>PARAM_ID_1</PARAM_TAG_1>
16 </m:REQUEST_RESPONSE_ID>
17 </SOAP-ENV:Body>
18 </SOAP-ENV:Envelope>
|
Generating a PHP fragment that in turn will generate some HTML. |
| Source code - File "language/php" |
1 @ set TITLEHEADER=<h4>
2 @ set TITLE=Generated PHP fragment
3 <?php
4 // Small fragment of PHP, printing out some HTML
5 print "TITLEHEADER\n";
6 print "TITLE\n";
7 ?>
|
| Output of "/opt/somusar/bin/tefigel language/php" |
1 <?php
2 // Small fragment of PHP, printing out some HTML
3 print "<h4>\n";
4 print "Generated PHP fragment\n";
5 ?>
|
Generate set and get "methods" for two "members" of a C "class". |
| Source code - File "language/c_getset" |
1 @ dash &
2 @ language/c/get_set(int,Quantity,quantity)
3 @ language/c/get_set(double,Percentage,percentage)
|
| Output of "/opt/somusar/bin/tefigel language/c_getset" |
1 static int quantity;
2
3 int getQuantity() {
4 return quantity;
5 }
6
7 void setQuantity( int v_quantity ) {
8 quantity = v_quantity;
9 }
10
11 static double percentage;
12
13 double getPercentage() {
14 return percentage;
15 }
16
17 void setPercentage( double v_percentage ) {
18 percentage = v_percentage;
19 }
20
|
| C get/set subroutine - File "language/c/get_set" |
|---|
1 @ interface(TYPE,IdId,idId)
2 static TYPE idId;
3
4 TYPE get&IdId() {
5 return idId;
6 }
7
8 void set&IdId( TYPE v_&idId ) {
9 idId = v_&idId;
10 }
11
|
Visual Basic® fragment containing a comment and a message to be printed out in a message box. |
| Source code - File "language/vbasic" |
1 @ set msg=Hello!
2 ' Print out a message
3 MsgBox "The message is: msg"
4
|
| Output of "/opt/somusar/bin/tefigel language/vbasic" |
1 ' Print out a message
2 MsgBox "The message is: Hello!"
3
|
Small fragment of PROCEDURE DIVISION that prints out a message. |
| Source code - File "language/cobol" |
1 @ set program_name=PROGRAM 0
2 @ set hello_message=Hello, world!
3 ****************************************************************
4 PROCEDURE DIVISION.
5 P0.
6 ** print a message
7 DISPLAY 'program_name: hello_message'.
8
|
| Output of "/opt/somusar/bin/tefigel language/cobol" |
1 |