TTM est un langage de programmation de traitement de macros à usage général , orienté chaîne, développé en 1968 par Steven Caine et E. Kent Gordon au California Institute of Technology .
Description
La description suivante est tirée du manuel de référence TTM original et de l'extension de traitement par lots ultérieure.
TTM est un langage récursif et interprétatif conçu principalement pour la manipulation de chaînes, l'édition de texte, la définition et l'expansion de macros et d'autres applications généralement classées comme programmation système. Il est dérivé de GAP et GPM.
Initialement, TTM était prévu comme la partie de traitement de macros d'un assembleur pour l'IBM System/360 et a été conçu pour surmonter les restrictions et les incohérences qui existaient dans les assembleurs standard de ce système.
TTM a été conçu pour avoir toute la puissance possédée par les assembleurs de macros généraux antérieurs, mais avec les malheureuses difficultés syntaxiques et sémantiques supprimées.
Au cours du développement de TTM, il est devenu évident que d'autres applications que le traitement de macros en assembleur étaient possibles. Il s'agit notamment de l'édition de données, de la manipulation de texte, de la compilation d'expressions et du traitement de macros pour des processeurs de langage autres que les assembleurs.
La version initiale de TTM a été implémentée pour fonctionner de manière conversationnelle sous le système de partage de temps de base de Caltech pour l' IBM System/360 Model 50. [ D'autres versions ont été écrites pour fonctionner dans l'environnement de traitement par lots d'OS/360 et pour fonctionner devant ou en conjonction avec divers processeurs de langage.
Syntaxe et sémantique
L'implémentation de référence suppose que TTM reçoit un fichier texte contenant une combinaison de texte ordinaire et d'appels de fonctions TTM (c'est-à-dire des invocations). Le texte est analysé caractère par caractère. Tout texte ordinaire est transmis à la sortie sans changement (à l'exception des échappements). Si une fonction TTM est rencontrée, elle est collectée et exécutée.
La forme générale d'un appel de fonction TTM ressemble à ceci :
#<nom de la fonction;arg1;arg2;...;argn>
où le nom de la fonction et les arguments sont des chaînes de caractères arbitraires ne contenant pas de caractères significatifs : « # », « < », « > » et « ; ». La fonction est invoquée avec les arguments spécifiés et le texte résultant est inséré dans le texte d'origine à la place de l'appel de fonction. Si l'appel de fonction a été préfixé par un seul caractère « # », l'analyse reprendra juste avant le texte inséré à partir de l'appel de fonction.
C'est ce qu'on appelle l'invocation active .
Si l'appel de fonction a été préfixé par deux caractères « # », l'analyse reprend juste après le texte inséré. C'est ce qu'on appelle l'invocation passive .
Lors de la collecte d'un appel de fonction, des appels de fonction supplémentaires peuvent être rencontrés, par exemple, ceci :
#<nom de la fonction;arg1;#<f2;arg;...>;...;argn>
L'appel de fonction imbriquée sera invoqué lorsqu'il sera rencontré et le résultat sera inséré dans le texte de l'appel de fonction externe et l'analyse de l'appel de fonction externe reprendra à l'endroit indiqué par le nombre de caractères « # » précédant l'appel imbriqué.
Si une fonction prend, par exemple, 2 arguments, tous les arguments supplémentaires sont ignorés. Pour les fonctions définies par l'utilisateur, si trop peu d'arguments sont fournis, un argument supplémentaire est ajouté avec la valeur de la chaîne vide (""). Une fonction peut avoir un maximum de 62 arguments.
Comme avec d’autres langages de programmation applicatifs , une fonction TTM peut être récursive et peut être définie comme le résultat de l’invocation d’une séquence d’autres appels de fonction.
Les fonctions sont soit intégrées , soit définies par l'utilisateur . Un grand nombre de fonctions intégrées existent et sont définies dans le manuel de référence TTM
Définition de la fonction
Les fonctions définies par l'utilisateur sont créées à l'aide des deux fonctions intégrées suivantes.
- #<ds;nom;texte>
- #<ss;nom;text1;text2...;textn>
La première fonction, ds pour « define string », définit une chaîne nommée dans le dictionnaire TTM. Le nom est « name » et sa valeur est « text ». L'appel de cette chaîne nommée entraînera le remplacement de son appel par la valeur (c'est-à-dire « text »).
La deuxième fonction, ss pour « segment string », analyse le texte d'une chaîne précédemment définie à la recherche d'occurrences de ses arguments : text1, text2, ... textn. Lorsqu'une occurrence est trouvée, elle est remplacée par une marque de segment . Toutes les occurrences de chaque argument sont remplacées par la même marque de segment.
Lorsqu'une chaîne segmentée est invoquée, chaque argument de l'appel est substitué à la marque de segment correspondante. Considérez cet exemple.
[01] #<ds;F;abcxxdefyy> [02] #<ss;F;xx;yy> [03] #<F;11;22>
La chaîne F est définie (ligne 1) et son corps "abcxxdefyy" est segmenté sur les deux chaînes "xx" et "yy" (ligne 2). Lorsqu'elle est invoquée (ligne 3), elle renverra la valeur "abc11def22". En effet, nous avons une fonction F définie par l'utilisateur avec deux arguments.
S'échapper
Il est possible d'échapper à un ou plusieurs caractères en utilisant l'une des deux conventions.
- <...> – échapper plusieurs caractères.
- @ – échapper à un seul caractère
Si une chaîne est entourée de <...>, elle est analysée mais pas interprétée par TTM. Au cours du processus d'analyse, les crochets extérieurs < et > sont supprimés. S'il existe des occurrences imbriquées de <...>, elles sont analysées mais les < et > ne sont pas supprimés. Les crochets doivent être équilibrés : le nombre de caractères « < » doit être égal au nombre de caractères « > ».
La convention d'échappement '@' oblige l'interpréteur à transmettre tel quel le caractère après le '@'. Le '@' initial est laissé s'il se trouve dans une séquence d'échappement <...>, sinon il est supprimé. Une utilisation est d'autoriser des occurrences déséquilibrées des caractères '<' ou '>'.
Exemples
Exemple 1 : Définition de fonction
L'exemple le plus basique consiste à définir une fonction utile pour définir des fonctions supplémentaires. Cette fonction « méta » s'appelle def . Elle s'écrit ainsi :
#<ds;def;<##<ds;name;<text>>;##<ss;name;subs>>> #<ss;def;name;subs;text>
Nous pouvons, par exemple, utiliser def pour définir la chaîne XX comme 12345 puis segmenter XX sur 34 en écrivant ceci.
#<def;XX;34;12345>
L'appel
#<XX;0000>
produira alors la chaîne « 1200005 ».
La fonction def fonctionne en appelant ds pour définir le nom de la fonction et le texte initial dans le dictionnaire TTM – XX dans notre exemple.
Ensuite, le texte de l'entrée du dictionnaire de XX est segmenté par rapport aux arguments spécifiés : « 34 » dans ce cas.
Lorsque XX est invoqué, son argument est substitué à la marque de segment.
Exemple 2 : Factorielle
La fonction factorielle peut être définie (en utilisant la fonction ##<def> ci-dessus ) comme suit.
#<def;n!;N;<#<lt;N;2;1;<#<mu;N;#<n!;#<su;N;1>>>>>>>
Notez que le calcul interne (#<mu...) est échappé, il ne sera donc évalué qu'après l'exécution des fonctions #<lt... et renverra ce calcul imbriqué comme résultat.
Un exemple d’appel ressemblerait à ceci.
#<n!;3>
et renverrait la chaîne 6.