|
|
|
|
Somusar/Tefigel[tm]
A Tutorial Introduction Francesco Aliverti-Piuri Copyright © 2003-2012 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 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.
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 **************************************************************** 2 PROCEDURE DIVISION. 3 P0. 4 ** print a message 5 DISPLAY 'PROGRAM 0: Hello, world!'. 6 |
RPG fragment containing a comment and a message to be printed out. |
Source code - File "language/RPG" |
1 @ set msg=Unknown Code 2 * Display an error message 3 Dtext m msgtext('msg') |
Output of "/opt/somusar/bin/tefigel language/RPG" |
1 * Display an error message 2 Dtext m msgtext('Unknown Code') |
SQL fragment containing a comment and a simple SELECT. |
Source code - File "language/SQL" |
1 @ set sqltable=EMPLOYEE 2 @ set search_key=POSITION 3 @ set search_val=Manager 4 @ dash $ 5 -- 6 -- By convention, each table contains a column with suffix ID. 7 -- 8 SELECT sqltable$ID FROM sqltable 9 WHERE search_key = 'search_val'; |
Output of "/opt/somusar/bin/tefigel language/SQL" |
1 -- 2 -- By convention, each table contains a column with suffix ID. 3 -- 4 SELECT EMPLOYEEID FROM EMPLOYEE 5 WHERE POSITION = 'Manager'; |
Generate a very simple "Hello, World!" Perl script. |
Source code - File "language/perl" |
1 @ mark rem | 2 @ set MESSAGE=Hello, world! 3 @ set VAR=$msg 4 # Simple Perl Script 5 VAR = "MESSAGE\n"; 6 7 print VAR; |
Output of "/opt/somusar/bin/tefigel language/perl" |
1 # Simple Perl Script 2 $msg = "Hello, world!\n"; 3 4 print $msg; |
Generate a Python fragment, containing a "usage" subroutine. |
Source code - File "language/python" |
1 @ mark rem | 2 @ set PROGRAM=some_tool 3 @ set PARAMETERS=[-o output] [input] 4 # Usage routine for script PROGRAM 5 def usage(): 6 print "Usage: PROGRAM PARAMETERS" 7 exit(1) |
Output of "/opt/somusar/bin/tefigel language/python" |
1 # Usage routine for script some_tool 2 def usage(): 3 print "Usage: some_tool [-o output] [input]" 4 exit(1) |
Generate a simple "Hello" script in REXX. |
Source code - File "language/rexx" |
1 @ set msg=Hello! 2 /* Simple REXX script */ 3 say "msg" 4 exit |
Output of "/opt/somusar/bin/tefigel language/rexx" |
1 /* Simple REXX script */ 2 say "Hello!" 3 exit |
Generate a simple LaTeX example. |
Source code - File "language/latex" |
1 @ set LANG=LaTeX 2 This is a simple LANG example, % --- LANG comment here 3 with several whitespaces and % --- one more comment 4 comments. |
Output of "/opt/somusar/bin/tefigel language/latex" |
1 This is a simple LaTeX example, % --- LaTeX comment here 2 with several whitespaces and % --- one more comment 3 comments. |
After the basic elements of Tefigel have been introduced, it is now possible to shortly describe some more advanced and useful features and applications of Tefigel.
The main driver to the definition and implementation of Tefigel
has been its role as the back-end language within the SoProTech[tm],
fully described in
"Somusar/Software Production Technique[tm]: An Introduction
".
Thus, Tefigel -
although fully applicable as a powerful stand-alone tool - should
be viewed as a part of a larger picture, as illustrated below.
Figure 1 - Tefigel and Sisendel
This concept is also illustrated and described in "Somusar/Software Production Technique[tm]: A Sample Project ".
Multilevel contents association is a simple mechanism that can be used to build reference-to-contents relationships stored into associative variables, as the next example shows. "Multilevel" means that nested contents of an aggregated group of data can be directly referenced to at any level of its nesting.
Usage of DASH to accomplish contents association. Note that dynamically changing DASH does not impact contents association. Multilevel association is shown on source lines 7, 8, 16, 17, 28 and 30. Built-in VALUE, used on lines 25, 27, 30 and 33, repeatedly expands its parameter - usually an associative variable - until all placeholders therein contained have been substituted with their current value. |
Source code - File "associate" |
1 # 2 # Set type definitions for Java 3 # 4 @ dash : 5 @ set Java:Float=double 6 @ set Java:Boolean=boolean 7 @ set Java:String:Short=String 8 @ set Java:String:Long=String 9 Type definition for "Float" in Java:: JavaFloat 10 # 11 # Set type definitions for SQL 12 # 13 @ dash / 14 @ set SQL/Float=decimal(10,2) 15 @ set SQL/Boolean=char(1) 16 @ set SQL/String/Short=varchar(20) 17 @ set SQL/String/Long=varchar(200) 18 Type definition for "StringLong" in SQL: SQLStringLong 19 # 20 # Access values by means of associative operator dash and built-in value 21 # 22 @ dash . 23 @ set Type=Boolean 24 @ set Language=Java 25 Definition of "Type" in Language: ~value(Language.Type) 26 @ set Language=SQL 27 Definition of "Type" in Language: ~value(Language.Type) 28 @ set Type=String.Long 29 Mapping of Type between Java and SQL: 30 SQL ~value(SQL.Type) maps to Java ~value(Java.Type) 31 @ set Type=Float 32 Mapping of Type between Java and SQL: 33 SQL ~value(SQL.Type) maps to Java ~value(Java.Type) |
Output of "/opt/somusar/bin/tefigel associate" |
1 Type definition for "Float" in Java: double 2 Type definition for "StringLong" in SQL: varchar(200) 3 Definition of "Boolean" in Java: boolean 4 Definition of "Boolean" in SQL: char(1) 5 Mapping of StringLong between Java and SQL: 6 SQL varchar(200) maps to Java String 7 Mapping of Float between Java and SQL: 8 SQL decimal(10,2) maps to Java double |
Data translation filters are a means to process input textual data
that are structured in various regular forms like lists or tables,
for instance comma-separated records, or name-value pairs.
With Tefigel filters it is rather simple to
convert data from tabular form, such as the following
file of bar-separated records to - for example - XML.
Input table - File "data_tab" |
---|
1 Name|Position|Age|Salary 2 3 John Smith|Product manager|34|120,000 4 Mark Twain|Technical writer|67|250,000 5 # This is a comment and should be ignored by tefigel filters 6 Bill Young|Java programmer|4|85,000 7 # This is a comment and should be ignored by tefigel filters 8 Tom Rich|Millionaire|49|0 |
It should be noted that the first line in the input file above contains the description of the records, thus making the file self-described. Additional information in the file header would easily allow to associate a complete metadata description of the table contents, specifying for example the type of the data fields.
Code Example 38 - Table filters
Tefigel FILTERs to translate data from raw tabular form into simple XML: the first filter "t_data" processes lines containing separator "|", the second one "t_skip" skips all other lines (empty and comments). Note use of the special character instruction ARGDELIM, that sets the parameter separator to "/" instead of ",". |
Source code - File "t_filter" |
1 @ argdelim / 2 @ filter t_data | 3 @ filter t_skip ^.*$ |
Output of "/opt/somusar/bin/tefigel t_filter data_tab" |
1 <!-- next record > 2 <Name> John Smith </Name> 3 <Position> Product manager </Position> 4 <Age> 34 </Age> 5 <Salary> 120,000 </Salary> 6 <!-- next record > 7 <Name> Mark Twain </Name> 8 <Position> Technical writer </Position> 9 <Age> 67 </Age> 10 <Salary> 250,000 </Salary> 11 <!-- next record > 12 <Name> Bill Young </Name> 13 <Position> Java programmer </Position> 14 <Age> 4 </Age> 15 <Salary> 85,000 </Salary> 16 <!-- next record > 17 <Name> Tom Rich </Name> 18 <Position> Millionaire </Position> 19 <Age> 49 </Age> 20 <Salary> 0 </Salary> |
Code Example 39 - Table filter 1
This filter splits matching input record into separate fields, and writes them out as XML fragments. Note use of GLOBSET to store field descriptor tags recognized on first input row into global name space variables called COL_0, COL_1, etc. Also note use of built-in FIELD to extract n-th field from the bar-separated record: note that separator "|" is also a parameter to built-in FIELD. |
Source code - File "t_data" |
1 @ interface(LINE) 2 @ eval ignore LINE~^# 3 @ if ignore=0 4 @ set VAL_0=~field(LINE/0/|) 5 @ set VAL_1=~field(LINE/1/|) 6 @ set VAL_2=~field(LINE/2/|) 7 @ set VAL_3=~field(LINE/3/|) 8 @ if COL_0= 9 @ globset COL_0=VAL_0 10 @ globset COL_1=VAL_1 11 @ globset COL_2=VAL_2 12 @ globset COL_3=VAL_3 13 @ else 14 <!-- next record > 15 <COL_0> VAL_0 </COL_0> 16 <COL_1> VAL_1 </COL_1> 17 <COL_2> VAL_2 </COL_2> 18 <COL_3> VAL_3 </COL_3> 19 @ endif 20 @ endif |
Code Example 40 - Table filter 2
Completely empty script, ignores input and produces no output. |
Source code - File "t_skip" |
|
In large software development projects it is often
necessary to maintain a high level of consistency across different
development teams using different programming languages.
Although this type of consistency is actually one of the main features
of the SoProTech[tm], in some simple cases it is
possible to achieve a good level of consistency by using just
Tefigel.
The next example shows how to effectively and quickly
generate consistent Java[tm] and C declarations by FILTERing
a textual list of instructions. An HTML documentation
file could just as easily be generated.
The starting point of the example is the list of Tefigel instructions.
Purpose of the example is to process this list and generate
the corresponding sets of declarations in both Java[tm] and C.
Instruction set of Tefigel - File "instr_set" |
---|
1 # Instructions on variables 2 GLOBSET 3 POP 4 PUSH 5 SET 6 UNSET 7 8 # Arithmetic instructions 9 ADD 10 DIV 11 MUL 12 SUB 13 TRUNC 14 NEG 15 16 # Logical instructions 17 AND 18 EVAL 19 NOT 20 OR 21 22 # Control flow 23 IF 24 ELSE 25 ENDIF 26 WHILE 27 ENDWHILE 28 JUMPCOND 29 JUMP 30 LABEL 31 32 # Subroutines and functions 33 CALL 34 FILTER 35 LIBRARY 36 QUIT 37 RETVALUE 38 39 # Input/output 40 APPEND 41 ATTACH 42 ECHO 43 MSG 44 OUTPUT 45 PROCESS 46 PROCESS_IF_READABLE 47 48 # Special characters and operators 49 ARGDELIM 50 CALLKEY 51 DASH 52 ESCAPE 53 LINEBREAK 54 MARK 55 56 # Miscellaneous instructions 57 DUMP 58 REM 59 RESET 60 SWITCH 61 SYSTEM 62 VERSION |
The list filter consists of one main script and two input filters, one for processing lines containing instructions and blank lines, one for processing comment lines.
This Tefigel filter produces two output files, creating them via the instruction OUTPUT on lines 9 and 15. It declares on lines 19 and 20 two filters, one for input comment lines (instr_comment), and one for non-comment lines (instr_code). Then it PROCESSes the instruction set on line 21, and APPENDs one trailing line to each file at the end. The filter does not write anything to its standard output, which is thus empty. |
Source code - File "instr_filter" |
1 @ mark rem | 2 @ dash $ 3 @ switch STRICT_CMDMARK=1 4 | 5 | Initialization: naming and creation of output files 6 | 7 @ globset j_out=Out/InstrSet.java 8 @ globset h_out=Out/instr_set.h 9 @ output j_out 10 // 11 // j_out - generated on ~date at ~time 12 // 13 14 public class InstrSet { 15 @ output h_out 16 /* 17 * h_out - generated on ~date at ~time 18 */ 19 @ filter instr_comment ^# 20 @ filter instr_code ^[^#]*$ 21 @ process instr_set 22 @ filter instr_code 23 @ filter instr_comment 24 @ append j_out 25 } 26 @ append h_out 27 |
Output of "/opt/somusar/bin/tefigel instr_filter" |
|
Code Example 42 - List filter 1
This filter counts the instruction codes (variable instruction_code), skips blank input lines, and prints proper Java and C definitions to the corresponding output files. Note use of built-in TABS on lines 22 and 24. |
Source code - File "instr_code" |
1 @ interface(input_line) 2 | 3 | Skip blank lines on input. 4 | 5 @ eval blank input_line~^[ ]*$ 6 @ if blank=1 7 @ quit 8 @ endif 9 | 10 | If instruction_code is not set yet, then we are at the beginning 11 | of the input file: set it to 0. Otherwise increment it. 12 | 13 @ if instruction_code= 14 @ globset instruction_code=0 15 @ else 16 @ add instruction_code 1 17 @ endif 18 | 19 | Append definition to both files. Format lines using built-in tabs 20 | 21 @ append j_out 22 ~tabs(public final int input_line = instruction_code;,40) 23 @ append h_out 24 ~tabs(#define INSTR_$input_line instruction_code,40) |
Code Example 43 - List filter 2
Translate input comment to proper format, appending it to both output files. |
Source code - File "instr_comment" |
1 @ interface(input_line) 2 @ set comment_length=~length(input_line) 3 @ sub comment_length 1 4 @ set comment=~substr(input_line,1,comment_length) 5 @ append j_out 6 7 // 8 //comment 9 // 10 11 @ append h_out 12 13 /* 14 * comment 15 */ 16 |
The resulting Java[tm] and C output files are listed below.
The instruction set in Java[tm] - File "Out/InstrSet.java" |
---|
1 // 2 // Out/InstrSet.java - generated on Thu Sep 27 2012 at 13:05:13.410 3 // 4 5 public class InstrSet { 6 7 // 8 // Instructions on variables 9 // 10 11 public final int GLOBSET = 0; 12 public final int POP = 1; 13 public final int PUSH = 2; 14 public final int SET = 3; 15 public final int UNSET = 4; 16 17 // 18 // Arithmetic instructions 19 // 20 21 public final int ADD = 5; 22 public final int DIV = 6; 23 public final int MUL = 7; 24 public final int SUB = 8; 25 public final int TRUNC = 9; 26 public final int NEG = 10; 27 28 // 29 // Logical instructions 30 // 31 32 public final int AND = 11; 33 public final int EVAL = 12; 34 public final int NOT = 13; 35 public final int OR = 14; 36 37 // 38 // Control flow 39 // 40 41 public final int IF = 15; 42 public final int ELSE = 16; 43 public final int ENDIF = 17; 44 public final int WHILE = 18; 45 public final int ENDWHILE = 19; 46 public final int JUMPCOND = 20; 47 public final int JUMP = 21; 48 public final int LABEL = 22; 49 50 // 51 // Subroutines and functions 52 // 53 54 public final int CALL = 23; 55 public final int FILTER = 24; 56 public final int LIBRARY = 25; 57 public final int QUIT = 26; 58 public final int RETVALUE = 27; 59 60 // 61 // Input/output 62 // 63 64 public final int APPEND = 28; 65 public final int ATTACH = 29; 66 public final int ECHO = 30; 67 public final int MSG = 31; 68 public final int OUTPUT = 32; 69 public final int PROCESS = 33; 70 public final int PROCESS_IF_READABLE = 34; 71 72 // 73 // Special characters and operators 74 // 75 76 public final int ARGDELIM = 35; 77 public final int CALLKEY = 36; 78 public final int DASH = 37; 79 public final int ESCAPE = 38; 80 public final int LINEBREAK = 39; 81 public final int MARK = 40; 82 83 // 84 // Miscellaneous instructions 85 // 86 87 public final int DUMP = 41; 88 public final int REM = 42; 89 public final int RESET = 43; 90 public final int SWITCH = 44; 91 public final int SYSTEM = 45; 92 public final int VERSION = 46; 93 } |
The instruction set in C - File "Out/instr_set.h" |
---|
1 /* 2 * Out/instr_set.h - generated on Thu Sep 27 2012 at 13:05:13.410 3 */ 4 5 /* 6 * Instructions on variables 7 */ 8 9 #define INSTR_GLOBSET 0 10 #define INSTR_POP 1 11 #define INSTR_PUSH 2 12 #define INSTR_SET 3 13 #define INSTR_UNSET 4 14 15 /* 16 * Arithmetic instructions 17 */ 18 19 #define INSTR_ADD 5 20 #define INSTR_DIV 6 21 #define INSTR_MUL 7 22 #define INSTR_SUB 8 23 #define INSTR_TRUNC 9 24 #define INSTR_NEG 10 25 26 /* 27 * Logical instructions 28 */ 29 30 #define INSTR_AND 11 31 #define INSTR_EVAL 12 32 #define INSTR_NOT 13 33 #define INSTR_OR 14 34 35 /* 36 * Control flow 37 */ 38 39 #define INSTR_IF 15 40 #define INSTR_ELSE 16 41 #define INSTR_ENDIF 17 42 #define INSTR_WHILE 18 43 #define INSTR_ENDWHILE 19 44 #define INSTR_JUMPCOND 20 45 #define INSTR_JUMP 21 46 #define INSTR_LABEL 22 47 48 /* 49 * Subroutines and functions 50 */ 51 52 #define INSTR_CALL 23 53 #define INSTR_FILTER 24 54 #define INSTR_LIBRARY 25 55 #define INSTR_QUIT 26 56 #define INSTR_RETVALUE 27 57 58 /* 59 * Input/output 60 */ 61 62 #define INSTR_APPEND 28 63 #define INSTR_ATTACH 29 64 #define INSTR_ECHO 30 65 #define INSTR_MSG 31 66 #define INSTR_OUTPUT 32 67 #define INSTR_PROCESS 33 68 #define INSTR_PROCESS_IF_READABLE 34 69 70 /* 71 * Special characters and operators 72 */ 73 74 #define INSTR_ARGDELIM 35 75 #define INSTR_CALLKEY 36 76 #define INSTR_DASH 37 77 #define INSTR_ESCAPE 38 78 #define INSTR_LINEBREAK 39 79 #define INSTR_MARK 40 80 81 /* 82 * Miscellaneous instructions 83 */ 84 85 #define INSTR_DUMP 41 86 #define INSTR_REM 42 87 #define INSTR_RESET 43 88 #define INSTR_SWITCH 44 89 #define INSTR_SYSTEM 45 90 #define INSTR_VERSION 46 91 |
Additional information on the different aspects of the
Somusar/Software Production Technique[tm] can be found in the other volumes of
the Somusar/SoProTech[tm] Booklet Series, listed below.
Vol. I -
somusar/SoProTech: An Introduction
Vol. II -
somusar/SoProTech: A Sample Project
Vol. III -
somusar/Sisendel: A Tutorial Introduction
Vol. V -
somusar/Sisendel: Reference Guide
Vol. VI -
somusar/Tefigel: Reference Guide
Vol. VII -
somusar/SoProMach: User's Guide
Vol. VIII -
somusar/tjpp: User's Guide
Vol. IX -
Code Generation Somusar Style
An introduction to the Somusar/Software Production Technique[tm], a new, fast, and efficient
technology to make high-quality multifacet software.
Description of a sample project, serving as a proof-of-concept
for the Somusar/Software Production Technique[tm], and the Somusar/Sisendel[tm] and Somusar/Tefigel[tm] languages.
A few code examples are provided and
demonstrate the practical applicability of the technique.
A tutorial introduction to Somusar/Sisendel[tm], describing all
features of the simple software entity design language. Several code examples
practically demonstrate the conciseness and flexibility
of the language.
Sisendel reference guide: official definition of syntax and semantics
of the Somusar/Sisendel[tm] language.
Tefigel reference guide: official definition of syntax and semantics
of the Somusar/Tefigel[tm] language.
The Somusar/Software Production Machine[tm] User's Guide. How to install and operate
SoProMach.
The Somusar/tjpp[tm] User's Guide. How to install and operate
the Java[tm] preprocessor.
Proof-of-concept samples of what you can generate with Somusar/SoProMach[tm].