# RESUME — TP3-comp : "AU COEUR DE TURBO PASCAL" (John Colibri, Éditions Mnémodyne) Analyse des 6 volumes OCRisés (`Resources/coeur-tp-ocr/coeur-tp-*-d.txt`) pour le projet TP3-comp (compilateur Turbo Pascal 3 → 8086 asm). OCR français (`tesseract -l fra --psm 3`), reconstruit à partir des colonnes opcode/adresse (OCR fréquemment faux : `:=`→`\:=`, `*`→`\`, instruction MOT). Ne vous fiez jamais au champ mnémonique seul — recalculez depuis les octets. --- ## 1. STRUCTURE DU LIVRE (plan confirmé) - **Vol. 1** (`coeur-tp-1-d.txt`, 19 p.) : couverture / plan. - **Vol. 2-3** (`-02` 26 p., `-03` 29 p.) : **ch.4 IMPLÉMENTATION DES TYPES**. - **Vol. 4** (`-04` 46 p.) : **ch.5 LE CODE COMPILE** (5.1-5.5). - **Vol. 5** (`-05` 42 p.) : **ch.5 suite** (5.5-5.7 + synthèse 5.A). - **Vol. 6** (`-06` 59 p.) : **ch.6 LES OPTIONS DE COMPILATION** + début ch.7 LA LIBRAIRIE. Total vérifié : 221 pages. Seuls les fichiers `*_d.txt` sont valides (les autres ont été supprimés). --- ## 2. CHAPITRE 4 — IMPLÉMENTATION DES TYPES ### Entiers (5.3.x / ch.4) - 16 bits, complément à deux, bornes -32768..32767. - Petits-boutistes (octet faible d'abord), convention 8086/8088. - Débordement = wrap : 50000 → -15536. - `READLN` d'un entier > MAXINT → erreur runtime 10. - Un littéral > MAXINT est rejeté à la compilation. - `CHAR` : 1 octet, ASCII étendu (0..255). - `BOOLEAN` : 1 octet, FALSE = 0, TRUE = bit 0. - Énumérations : 1 octet si < 256 valeurs, sinon 2 octets petits-boutistes. - Sous-intervalles : 1 octet si les 2 bornes dans 0..255. ### REAL (6 octets) - 1 octet d'exposant (complément-à-128 de l'exposant binaire, en premier), puis 1 bit de signe + mantisse 39 bits (octet le plus faible en premier en mémoire). ### REAL BCD (10 octets) - Bit 79 : signe ; bits 78-72 : exposant en complément-à-63 (puissances de 10) ; 72 bits de chiffres. - Mémoire : octet signe/exposant puis 9 octets de mantisse. - Exemple : 48.9375 → `$41 $00 $00 $00 $00 $75 $93 $48`. ### REAL 8087 (8 octets) - Bit 63 : signe ; bits 52-62 : exposant complément-à-$3FF ; mantisse 52 bits. ### Tableaux - Mémoire contiguë, pas de compactage de bits. - 2 dimensions : parcours ligne-major, **le dernier indice déclaré varie le plus vite**. - Tableaux de CHAR compatibles avec les constantes chaîne pour WRITE et affectation, mais PAS pour READLN. ### Chaines STRING - Longueur dans l'octet 0, puis les caractères ; taille mémoire = longueur_max + 1. - Maximum 255. - Option `V-` : désactive la vérification (débordement) des chaînes. ### Enregistrements - Champs juxtaposés, non compactés. - Variants : l'enregistrement occupe la taille du variant le plus grand. - Variants libres (sans sélecteur) : pas d'octet de sélecteur. ### Ensembles (SET) - 1 bit par élément. Plus grand ensemble 0..255 = 32 octets. - Ensembles hybrides (bornes non 0/255) : seuls les octets entiers couvrant le sous-intervalle sont utilisés (ex. 12..17 → octets 1-2). - En mémoire, l'octet de poids le plus fort vient en dernier. - Valeurs hors bornes : placées si codables, sinon ignorées/écrasées. ### Pointeurs - 4 octets : décalage (offset) en premier, puis segment. NIL = 0. - Tas : entre la fin des globales et le sommet de la pile Pascal. - Le tas grandit par blocs de 8 octets (décalage $0000/$0008). - `NEW` réserve la place + bourrage à un multiple de 8. - Variable dynamique : doit rester < 64K. - Variant-pointeur `NEW(n, selecteur)` : non implanté. ### Fichiers - Programmes .COM chargés à $0100. - Fichiers de données : enregistrements en continu les uns derrière les autres. - Fichiers `FILE` (blocs) : `BLOCKREAD`/`BLOCKWRITE`. - Fichiers texte : fins de ligne `$0D $0A` ; EOF = CTRL-Z `$1A` ; les fichiers TEXT n'ajoutent pas de `$1A` final. --- ## 3. CHAPITRE 5 — LE CODE COMPILÉ ### 3.1 Squelette de programme (5.2, 5.6, 5.7) ```ASM 2D4D E849DD call TU_PARAGRAPHS 2D50 0600 hex 0600 ; options 2D52 .... hex .... ; cs 2D54 .... hex .... ; ds 2D56 .... hex .... ; code 2D58 .... hex .... ; globales 2D5A .... hex .... ; min piles 2D5C .... hex .... ; max piles 2D5E .... hex .... ; fichiers 2D60 .... hex .... ; input 2D62 .... hex .... ; output 2D64 8BEC mov bp, sp 2D66 E814DF call TU_TAILLE_CODE 2D69 .... hex .... ; taille du code 2D6B .... adr SAUT_PRINCIPAL 2D6D E9xxxx SAUT_PRINCIPAL jmp PRINCIPAL ; ... ici : procédures + constantes typées ... PRINCIPAL: ; ... code du programme ... jmp FIN ; ... relais GOTO hors FOR : RELAI_GOTO_n: pop ax; jmp cible ... FIN: xor ax, ax call TU_HALT hex 0000 ``` - `l'adresse de retour PUSH du CALL` : octet faible poussé d'abord, SP diminue de 2. - `RET` dépile dans le compteur de programme (PC). ### 3.2 Arithmétique entière (5.3.1.1) | Pascal | 8086 généré | |---|---| | `a * b` | `mov ax,a ; mov cx,const ; imul cx` | | `a DIV b` | `... ; cwd ; idiv cx` | | `a MOD b` | `... ; idiv cx ; xchg dx,ax` | | `SQR(x)` | `mov ax,x ; imul ax` | | `SUCC(x)` | `inc ax` | | `PRED(x)` | `dec ax` | - Arbres d'expressions : les intermédiaires passent par la pile (`push ax` / `pop cx`). Exemple : ```ASM mov ax, $11 mov cx, $22 imul cx push ax mov ax, $33 push ax mov ax, $44 add ax, $55 pop cx imul cx pop cx add ax, cx ``` ### 3.3 Comparaisons booléennes (5.3.1.2) Résultat calculé dans AX (1 pour vrai, 0 pour faux) : ```ASM mov ax, $0001 Jcc saute ; Jcc = je/jg/jnle/jnl/jl/jle/jnz selon l'opérateur dec ax saute: ; avec R+ : mov cx, $0000 mov dx, $0001 call TU_RANGE_CHECK ; bornes dans CX,DX mov [var], al ; booléen = 1 octet ``` ### 3.4 Affectations / accès - Valeur globale : `mov ax,[$0262]` (première globale = $0262). - Écriture : `mov [addr], ax` / `mov [addr], al`. - Dans une affectation, le calcul d'adresse peut être séparé des instructions de stockage ; les adresses calculées sont sauvegardées sur la pile. - Accès par sélecteurs (tableaux/enregistrements/pointeurs) : - calcul direct si le compilateur connaît les valeurs, - sinon DI porte le décalage + une constante relative ; ES sert de segment. - WITH : l'adresse de base est poussée sur la pile puis récupérée dans ES:DI à l'aide de BP (`les di,[bp+$FC]`). ### 3.5 IF (5.6.1) ```ASM mov ax, var cmp ax, imm je THEN1 jmp FIN_IF1 THEN1: ; ... corps ... FIN_IF1: ``` IF/ELSE : ```ASM je THEN2 jmp ELSE2 THEN2: ; ... corps THEN ... jmp FIN_IF2 ELSE2: ; ... corps ELSE ... FIN_IF2: ``` - `IF TRUE THEN ;` → `mov ax,$0001 ; or ax,ax ; jnz ...`. - Pas d'optimisation du test booléen : les deux opérandes sont toujours évaluées. ### 3.6 CASE (5.6.2) - Cascade : `cmp ax,label ; je cas_n ; jmp test_suivant`. - Intervalles : `cmp ax,lo ; jl suivant ; cmp ax,hi ; jle cas_n`. - Étiquette hors bornes énorme : inoffensif `cmp ax,$AAAA ; je cas`. - Chaque corps de cas se termine par `jmp FIN_CASE`. - Éti localités dupliquées : le premier l'emporte. - Plus de 20 étiquettes : insertion d'un relais `JMP_S`. ### 3.7 REPEAT (5.6.3) ```ASM DEBUT_REPEAT: ; ... corps ... ; ... évaluation condition ... jxx FIN_REPEAT jmp DEBUT_REPEAT ; retour arrière toujours en JMP long FIN_REPEAT: ``` ### 3.8 WHILE (5.6.4) ```ASM teste_while: ; ... évaluation condition ... Jxx debut_while JMP fin_while debut_while: ; ... instruction ... JMP teste_while fin_while: ``` ### 3.9 FOR (5.6.5) Calcul des bornes (la 1re borne est `push ax` pour ne pas être écrasée par l'expression de la 2e ; `pop cx ; xchg cx,ax ; sub cx,ax`) : ```ASM jnl ENTRE_FOR jmp FIN_FOR ENTRE_FOR: inc cx mov [compteur], valeur_initiale boucle_for: push cx ; ... corps ... pop cx dec cx je FIN_FOR inc word [compteur] jmp boucle_for FIN_FOR: ``` - `DOWNTO` : miroir (décrément). - Si la boucle est entrée, le compteur est laissé à sa valeur finale. - Modifier le compteur dans le corps change le nombre d'itérations. - `GOTO` vers l'intérieur d'un corps de FOR : interdit (CX ne serait pas sauvegardé). - `GOTO`/`EXIT` hors d'un FOR : nécessite un relais spécial pour dépiler CX (`RELAI_GOTO_n: pop ax ; jmp cible`). ### 3.10 Procédures — prologue/épilogue (5.7) Procédure au premier niveau : ```ASM X: push bp ; BP de l'appelant mov bp, sp push bp ; "valeur de BP actuelle" jmp DEBUT_X DEBUT_X: sub sp, $03 ; zone variable(s) (3 octets ici) ... FIN_X: mov sp, bp pop bp ret ; (ret imm si paramètres, voir 3.11) ``` Procédure imbriquée (table des accès) : ```ASM T: push bp mov ax, sp push [bp+$FE] ; recopie la table de l'englobante (BP) mov bp, ax push bp jmp DEBUT_T ``` Imbrication à n niveaux : re-push des entrées `[bp+$FE]`, `[bp+$FC]`, ... (chaque niveau : sauter 2 octets de plus). `[bp+$FE]` pour la 1re visite ; +2 par niveau supplémentaire. Accès aux variables locales/paramètres : via BP (`mov [bp+$FC],ax`, etc.). Accès aux variables de l'englobante (intermédiaires) via la table : ```ASM mov bx, [bp+$FE] ; BP de la procédure englobante seg ss mov ax, [bx+$FC] ; variable de l'englobante ``` Pile d'une procédure (SP → adresses hautes) : ```TXT la dernière variable locale <--- SP la deuxième variable locale la première variable locale la valeur de BP actuelle la valeur de BP de la procédure englobante la valeur de BP de la première procédure la valeur de BP de l'appelant <--- BP l'adresse de retour <--- BP+2 dernier paramètre premier paramètre ``` ### 3.11 Paramètres (5.7.6) Appel (les params sont poussés dans l'ordre des déclarations) : ```ASM mov cx, $0012 ; 6 environnement + taille des paramètres call TU_STACK_CHECK ; TOUJOURS avant un appel avec zone mov ax, $AAAA push ax ; paramètre valeur mov di, $0264 push ds push di ; paramètre variable : SEG puis OFFSET call DEUX ``` Accès dans le callee : ```ASM mov ax, [bp+$0E] ; 1er paramètre valeur (après 2 var + 1 valeur = $0E) les di, [bp+$08] ; LES : ES:DI ← adresse segmentée du 1er paramètre variable seg es mov [di], ax ``` - Le 1er octet des paramètres est à BP+4. Le **dernier** paramètre déclaré est le plus proche (BP+4), le premier déclaré le plus loin (ex. +$0E, +$0C, +$08, +$04). - Épilogue : `mov sp,bp ; pop bp ; ret imm` — `ret imm` (c.-à-d. "intra") dégage les paramètres (2 octets par paramètre valeur, 4 par paramètre variable). ### 3.12 Fonctions (5.7.7) Fonction entière — résultat dans AX, zone résultat réservée par l'appelant : ```ASM ; appelant : mov cx, $0008 ; 6 environnement + 2 résultat call TU_STACK_CHECK dec sp ; réserve le résultat (2 octets) dec sp call F_FONCTION mov [$0262], ax ; entier := f_entier ; callee : mov ax, $0077 mov [bp+$04], ax ; affectation au nom de fonction → zone [BP+4] mov ax, [bp+$04] ; AX ← résultat mov sp, bp pop bp ret 0002 ; intra : dégage le résultat ``` Fonction chaîne — résultat laissé sur la pile, épilogue via la librairie : ```ASM DEBUT_F_CHAINE: lea di, [bp+$04] push ss push di call TU_POUSSE_K_ST ; pousse la constante chaîne (03 ; longueur asc 'ABC') mov cl, $0B ; taille max (STRING[11]) call TU_POP_STRING ... mov dx, $0000 mov cl, $0B mov sp, bp pop bp jmp TU_RESU_FCT_ST ; le résultat reste sur la pile ; appelant : mov di, $0262 push ds push di ; seg:off de chaine (dest) mov cx, $0012 ; 6 env + 12 résultat call TU_STACK_CHECK sub sp, $0C ; réserve le résultat (string) call F_CHAINE mov cl, $0B call TU_POP_STRING ``` Résumé : résultat **entier → AX** ; résultat **réel/chaîne → laissé sur la pile**. ### 3.13 Entrées-sorties / runtime (5.5) - WRITE/WRITELN → `call TU_DEB_RW_DEFAUT ; call TU_WRITELN ; call TU_IO_CHECK` (idem : `TU_READ_DEFAUT`, `TU_READ_ENTIER`, `TU_WRITE_ENTIER`, `TU_WRITE_FICHI`, `TU_READ_FICHI`, `TU_CLOSE`). - Fin de programme → `xor ax,ax ; call TU_HALT`. - Réels : passés sur la pile, 6 octets ; les comparaisons retournent AL. - Les fichiers utilisent systématiquement la librairie, qui fait appel au DOS. ### 3.14 Constantes typées (5.8) - Syntaxe : `CONST nom : type = valeur ;`. Modifiables comme des variables. - Stockées **au milieu du code**, valeur unique, accès par **CS**. - Comportement de variables statiques (gardent la valeur entre appels ; un appel récursif retient la dernière modification). - Jeu du compilateur : préfixe `seg cs` sur les MOV, et pousse `cs` au lieu de `ds` pour les routines de la librairie qui attendent un segment sur la pile. - Le programme saute par-dessus la zone des constantes via `jmp PRINCIPAL`. - Exemple données : `kt_entier $1711` → `hex 1111` ; `TRUE` → `01` ; `'A'` → `41` ; `1.75` → 6 octets. - Réels : `push cs / push di ; mov di,offset ; push ds ; call TU_POUSSE_REEL ; call TU_POP_REEL_DI`. - Constantes complexes (tableaux d'enregistrements) : calcul d'index normal puis `seg cs` sur le stockage ; WITH sur constante typée pousse CS. - Limitation notée par l'auteur : mélange de 3 propriétés (initialisation/statique/CS) qu'il aurait mieux valu séparer (initialisation sous VAR, attributs STATIQUE et CODE). ### 3.15 Variables absolues (5.9) Quatre cas : - `ABSOLUTE CSEG:$2D50` → traité comme constante typée. - `ABSOLUTE DSEG:$0242` → traité comme globale (offset fourni). - `ABSOLUTE autre_variable` → traité selon le segment de l'autre (DS ou SS); globale → DS, locale/paramètre → SS. - `ABSOLUTE $1234:$5678` → l'adresse (décalage puis segment, petits-boutistes) est stockée dans le code et l'accès se fait par LES : ```ASM 2D70 7856 hex 7856 ; décalage $5678 2D72 3412 hex 3412 ; segment $1234 ... les di, [$2D70] ; ES:DI ← $1234:$5678 seg es mov ax, [di] ``` ### 3.16 Synthèse (5.A) Deux catégories de données : 1. **registre** : arithmétique dans AX, intermédiaires sur la pile repris dans CX ; accès sélecteurs via DI + décalage constant, ES = segment ; WITH = base sur la pile reprise dans ES:DI via BP ; locales/params via BP ; intermédiaires via la table des BP englobants. 2. **volumineuses** (réels, chaînes, tableaux/enregistrements manipulés globalement, ensembles) : la pile stocke les valeurs ET le segment (DS/CS/SS/ES) ; DI porte le déplacement. Affectation : le calcul d'adresse peut être séparé du stockage ; adresses sauvegardées sur la pile. Fichiers : via librairie → DOS. --- ## 4. CHAPITRE 6 — LES OPTIONS DE COMPILATION - Syntaxe : `(*$...*)` ou `{ $... }` (pas d'espace entre l'ouvrant et `$`). - Effet **au point de lecture** (le compilateur lisant le fichier de gauche à droite). - Principales options : `I`/`R`/`K`/`V`/`U`/`C`/`B`/`D`/`F`/`G`/`P`. - `R-` : retire les contrôles d'intervalles (TU_RANGE_CHECK/TU_INDEX_CHECK non émis). - `I-` : supprime la levée d'erreur d'entrée-sortie jusqu'à `I+`. - `V-` : désactive la vérification des chaînes. - `(*$g512,p512,d-*)` : exemple fixant nombre de fichiers = 512 ? et périphériques par défaut. - R-options liées à la pile (`min piles`, `max piles` — mots du squelette §3.1). --- ## 5. CHAPITRE 7 — LA LIBRAIRIE (début) - Adresses `TU_*` des routines runtime (TU_PARAGRAPHS, TU_TAILLE_CODE, TU_HALT, TU_STACK_CHECK, TU_RANGE_CHECK, TU_INDEX_CHECK, TU_POUSSE_REEL, TU_POP_REEL_DI, TU_POUSSE_K_ST, TU_POP_STRING, TU_RESU_FCT_ST, TU_DEB_RW_DEFAUT, TU_WRITELN, TU_IO_CHECK, TU_READ_DEFAUT, TU_READ_ENTIER, TU_WRITE_ENTIER, TU_WRITE_FICHI, TU_READ_FICHI, TU_CLOSE, ...). Détails complets dans `coeur-tp-06-d.txt`. --- ## 6. PROTOCÔLE DES PASTES (FilePaste) — pour les sections de référence - Les sections de référence sont livrées en structure compatible FilePaste (simulée en chat ; l'utilisateur les rattache sous `File Paste: `). Ne pas créer de fichiers pour la référence elle-même. - Utiliser des marqueurs de bloc `ASM` pour le code ; les blocs `(*$...*)` sur des lignes simples avec en-têtes de section style INI ; les options en ligne (`(*$R-*)`) en italique. Marqueur "OPTIONS INFO" pour les bascules d'options. - Pas de tl;dr : contenu complet ; pas d'explication de ce que fait l'agent dans une section de référence (sections 100 % référence). - Autant que possible garder l'anglais (ex. `types`) ; le français pour les termes propres au livre. - Édition par pastes corrigés (`((o))` / `((c))`) : ré-émettre la section complète corrigée ; ne pas prétendre avoir appliqué la correction si l'on ne sait pas qu'elle a été appliquée (c'est l'utilisateur qui l'applique). `AM` + `END` = délimiteur de zone. --- ## 7. ÉTAT DES TRAVAUX DE SESSION (repère pour reprendre) - **Fini** : lecture complète des 6 volumes (`-1`, `-02`..`-06`), extraction de ch.4 (types), ch.5 (code), ch.6 (options), ch.7 (début librairie). - **Émis en pastes** : routage IF (5.3.1.2), template FOR/`INIT_FOR` avec constantes, template `UPTO`/`DOWNTO` (contenant TU_SEG + TU_SUB_ALIGN), paramètres/fonctions (5.7.6-5.7.7), constantes typées (5.8), variables absolues (5.9), synthèse 5.A. - **À faire** : livrer les sections de référence restantes en pastes complets (selon protocole §6) ; recouper les micro-détails incertains contre les sources TP3 (`Resources/turbopascal3source/TP3/`, TPSRC1-10) et le désassembleur `Resources/DESASS/` si besoin. ## 8. RESSOURCES DISPONIBLES DANS `Resources/` - `coeur-tp-ocr/` — les 6 volumes OCRisés (source de cette référence). - `turbopascal3source/TP3/` (TPSRC1-10, MAIN) — source du compilateur TP3 (vérité). - `DESASS/` — désassembleur ; `AS.COM` / `AS.PDF` — assembleur. - `TP3/` — distribution TP3. - `The_Turbo_Pascal_Tutor_1985.pdf`, `Turbo_Pascal_Version_3.0_Reference_Manual_1985.pdf`, `TURBO-LESSONS` (`Cours.md`), `Welsh_Hay` (Model Implementation of Standard Pascal), `Disassembly of old Turbo Pascal (V3) code` (Stack Overflow HTML), etc.