BCPL

BCPL

BCPL signifie Basic Combined Programming Language :
une version simplifiée de CPL, conçue pour écrire des compilateurs
et des logiciels système plus faciles à transporter d’une machine à l’autre.

Le langage portable qui a ouvert la voie à B et C

Au milieu des années 1960, les langages de programmation deviennent plus expressifs, mais leurs compilateurs restent souvent longs et difficiles à adapter. Un langage peut être élégant sur le papier et pourtant se révéler peu pratique lorsqu’il faut le faire fonctionner sur les ordinateurs très différents de l’époque. C’est précisément le problème rencontré par Martin Richards. À Cambridge, il participe au développement d’un compilateur pour CPL, le Combined Programming Language. Ce projet commun aux universités de Cambridge et de Londres veut réunir plusieurs idées modernes issues notamment d’ALGOL. Le langage est ambitieux, mais cette ambition se paie : le compilateur devient complexe, volumineux et lent à mettre au point. Richards choisit alors une autre voie. Il conserve les idées de CPL qu’il juge utiles, supprime les mécanismes les plus difficiles à compiler et ajoute quelques solutions destinées à la programmation des systèmes. Le résultat est BCPL, un langage volontairement petit, sans types déclarés et conçu dès l’origine pour être porté sur des machines différentes.

Date d’apparition : 1967

  • 1962–1966 : les universités de Cambridge et de Londres travaillent sur CPL et sur ses compilateurs.
  • 1966 : Martin Richards rédige une première description de BCPL, essentiellement en retirant de CPL les éléments les plus difficiles à mettre en œuvre.
  • Début de 1967 : au Project MAC du MIT, Richards réalise le premier compilateur BCPL pour l’IBM 7094 fonctionnant sous CTSS.
  • 21 juillet 1967 : le premier manuel de référence connu, BCPL Reference Manual, est diffusé au MIT.
  • Mai 1967 : le langage est déjà utilisé au MIT et à l’Oxford Programming Research Group.
  • Octobre 1968 : BCPL fonctionne sur le calculateur Titan de Cambridge.
  • Années 1970 : le langage est employé pour des systèmes d’exploitation, des compilateurs et des logiciels de recherche, notamment à Oxford, Cambridge, au MIT et au Xerox PARC.
  • 1977 : les coroutines sont ajoutées à la bibliothèque BCPL et servent au développement du système portable Tripos.

Il faut donc distinguer deux dates. 1966 correspond à la première conception du langage ; 1967 à son premier compilateur opérationnel et à son premier manuel. C’est cette seconde date qui est généralement retenue comme celle de l’apparition de BCPL.

À quel besoin répond BCPL ?

BCPL répond d’abord à un problème de portabilité. Dans les années 1960, changer de machine signifie souvent changer de représentation des caractères, de taille de mot, de jeu d’instructions et de système d’exploitation. Réécrire entièrement un compilateur pour chaque ordinateur demande un travail considérable.

Martin Richards veut réduire cette dépendance. Le langage doit être assez petit pour que son compilateur soit compréhensible et puisse se transporter plus facilement. Il doit aussi convenir à la création d’autres compilateurs, d’éditeurs, de systèmes d’exploitation et d’utilitaires.

Cette recherche de simplicité explique plusieurs choix fondamentaux :

  • un modèle de données sans types déclarés ;
  • des valeurs occupant toutes un mot machine ;
  • des pointeurs et des vecteurs permettant de représenter librement les données ;
  • un langage intermédiaire, appelé OCODE, séparant l’analyse du programme de la production du code machine ;
  • un mécanisme de compilation séparée permettant de réunir plusieurs parties d’un programme.

Le but n’est pas de cacher entièrement la machine. BCPL cherche plutôt à fournir un modèle commun, suffisamment simple pour être reproduit sur de nombreux ordinateurs.

OCODE : rendre le compilateur transportable

L’une des idées les plus importantes de BCPL concerne l’organisation de son compilateur. Au lieu de traduire directement chaque programme vers les instructions d’une machine précise, le compilateur produit d’abord un code intermédiaire nommé OCODE.

Le processus peut être résumé ainsi :

Programme BCPL
      ↓
Partie commune du compilateur
      ↓
    OCODE
      ↓
Générateur propre à la machine
      ↓
Code exécutable

La première partie comprend le langage BCPL et produit une suite relativement simple d’opérations intermédiaires. Seule la dernière étape doit connaître précisément la machine cible.

Pour porter BCPL sur un nouvel ordinateur, il n’est donc pas nécessaire de réécrire tout le compilateur. Il faut surtout fournir un générateur capable de transformer OCODE en instructions adaptées au nouveau processeur. Cette séparation réduit le travail nécessaire et offre également un endroit commun où effectuer certaines optimisations.

Ce principe annonce, dans une certaine mesure, celui que l’on retrouvera avec les machines virtuelles. Toutefois, OCODE sert principalement d’étape intermédiaire avant la production d’un programme natif. Avec Java, le bytecode constitue au contraire un format portable distribué avec l’application, puis exécuté ou compilé à la volée par une JVM propre à chaque plateforme. La parenté est donc conceptuelle, sans impliquer une filiation directe entre BCPL et Java.

Richards approfondit ensuite cette approche avec des représentations intermédiaires plus compactes. Une version moderne du système, appelée Cintcode, exécute un code intermédiaire à l’aide d’une petite machine virtuelle. L’objectif reste fidèle au projet initial : préserver le même environnement BCPL sur des matériels et des systèmes différents.

Un langage sans types déclarés

La caractéristique technique la plus frappante de BCPL est son absence de types. Une variable n’est pas déclarée comme entier, caractère, booléen ou pointeur. Toutes les valeurs ont la même taille : celle d’un mot de la machine abstraite utilisée par le langage.

Le contenu d’un mot peut représenter :

  • un nombre entier ;
  • un caractère ou plusieurs caractères regroupés ;
  • une valeur vraie ou fausse ;
  • l’adresse d’une donnée ;
  • l’adresse d’une fonction ou d’une routine.

Ce n’est pas la variable qui indique la nature de la valeur, mais l’opération que le programme lui applique. Une addition interprète les mots comme des nombres ; une indirection les traite comme des adresses ; un appel peut considérer une valeur comme l’entrée d’une fonction.

Ce modèle simplifie le compilateur. Il convient aussi aux ordinateurs de l’époque, sur lesquels de nombreuses informations tiennent naturellement dans un mot. Mais il supprime une protection importante : le compilateur ne peut pas toujours détecter qu’un programme additionne une adresse à une valeur absurde ou tente d’appeler une donnée comme s’il s’agissait d’une fonction.

À quoi ressemble un programme BCPL ?

Voici un petit exemple écrit dans la syntaxe moderne de BCPL :

GET "libhdr"

LET carre(n) = n*n

LET start() = VALOF
{
    FOR i = 1 TO 5 DO
        writef("%n au carre vaut %n*n", i, carre(i))

    RESULTIS 0
}

Ce programme affiche le carré des nombres de 1 à 5.

Quelques éléments permettent d’en comprendre la structure :

  • GET "libhdr" ajoute les déclarations de la bibliothèque courante ;
  • LET carre(n) = n*n définit une fonction ;
  • start constitue le point d’entrée du programme ;
  • FOR i = 1 TO 5 DO décrit une boucle ;
  • writef affiche du texte et des nombres, tandis que *n représente ici un retour à la ligne ;
  • VALOF ouvre un bloc produisant une valeur et RESULTIS 0 fournit cette valeur.

BCPL propose des fonctions, des routines, la récursion, des tests et plusieurs formes de boucles. Ses arguments sont transmis par valeur. Lorsqu’une fonction doit agir sur une donnée extérieure, le programme lui transmet généralement un pointeur.

Pointeurs, mémoire et vecteurs

BCPL représente la mémoire comme une suite de mots numérotés. Un pointeur est simplement la valeur numérique désignant l’un de ces mots. Ajouter 1 à un pointeur conduit au mot suivant, quelle que soit la taille physique choisie par l’ordinateur réel.

Dans la notation moderne :

LET x = 10
LET p = @x
LET y = !p

L’opérateur @ donne l’adresse de x. L’opérateur ! lit le mot situé à l’adresse contenue dans p. La variable y reçoit donc la valeur 10.

Les tableaux sont appelés vecteurs. Ils sont eux aussi manipulés au moyen d’un pointeur :

LET table = VEC 9

FOR i = 0 TO 9 DO
    table!i := i*i

L’expression VEC 9 réserve ici les éléments numérotés de 0 à 9. L’écriture table!i est équivalente à !(table+i) : le programme calcule l’adresse du mot voulu, puis accède à son contenu.

Cette relation très directe entre adresse, pointeur et tableau annonce une idée que le langage C rendra célèbre. La différence essentielle est que le C associera un type aux pointeurs et pourra tenir compte de la taille des objets pointés. En BCPL, tout reste fondé sur le mot unique.

Des structures construites par convention

BCPL ne possède pas à l’origine de mécanisme comparable aux struct du C. Un programme représente une structure en réservant un vecteur, puis en attribuant une signification précise à chaque position.

Par exemple, un programme peut décider que :

  • le mot 0 contient un numéro ;
  • le mot 1 contient un pointeur vers un nom ;
  • le mot 2 contient une taille ;
  • le mot 3 contient un état.

Des constantes déclarées avec MANIFEST permettent de donner des noms à ces positions et d’éviter de disperser des nombres mystérieux dans le programme. Ce procédé est économique et flexible, mais le compilateur ne vérifie ni la forme de la structure ni la nature des valeurs placées dans ses champs.

BCPL fait ainsi confiance au programmeur. Le langage fournit quelques mécanismes généraux ; les conventions du programme donnent un sens aux données.

Une syntaxe marquée par les claviers de l’époque

La première version de BCPL est développée sur l’IBM 7094 du MIT. Son environnement CTSS utilise alors un jeu de caractères limité. Plusieurs signes aujourd’hui ordinaires dans les langages de programmation ne sont pas disponibles.

Les premiers programmes BCPL n’emploient donc pas les accolades modernes. Ils utilisent notamment $( et $) pour délimiter les blocs. Lorsque BCPL est porté vers des machines possédant des jeux de caractères plus riches, les notations { et } deviennent possibles et finissent par s’imposer.

Ce détail rappelle que la syntaxe d’un langage n’est pas seulement une affaire de théorie. Elle dépend aussi des terminaux, des imprimantes, des codes de caractères et des claviers réellement accessibles à ses créateurs.

La compilation séparée et le vecteur global

Un logiciel système ne tient pas toujours dans un seul fichier. BCPL doit donc permettre de compiler séparément plusieurs modules, puis de les faire coopérer.

Le langage utilise pour cela un vecteur global. Les fonctions et les données partagées occupent des positions convenues dans ce vecteur. Un en-tête associe un nom lisible à chaque numéro de position, afin que différents modules puissent retrouver la même fonction.

Cette méthode présente un avantage important : un module compilé peut appeler une fonction extérieure sans connaître son adresse définitive en mémoire. Elle a servi efficacement pendant plusieurs décennies dans les environnements BCPL.

Mais elle impose aussi une discipline manuelle. Deux composants ne doivent pas employer la même position pour des usages incompatibles. Richards qualifie rétrospectivement ce mécanisme de simple et utile, mais peu élégant. Les éditeurs de liens modernes résolvent généralement les noms symboliques sans obliger le programmeur à gérer lui-même ces numéros globaux.

BCPL comme langage de systèmes

BCPL n’a jamais été destiné au même public que BASIC. Il s’adresse surtout aux personnes qui construisent l’environnement informatique lui-même : compilateurs, systèmes d’exploitation, éditeurs et bibliothèques.

À Oxford, le système expérimental OS6 est écrit presque entièrement en BCPL. Ses auteurs montrent ainsi qu’un système d’exploitation peut être développé en grande partie dans un langage de haut niveau, tout en conservant quelques fragments d’assembleur lorsque le matériel l’exige.

Au Xerox PARC, BCPL est employé pour certains travaux pionniers autour de l’ordinateur Alto. À Cambridge, il sert de terrain d’expérimentation pour les compilateurs et la programmation système.

Sa portabilité favorise ces usages. Le même langage peut suivre les projets d’une machine à l’autre, alors que l’assembleur doit être réécrit pour chaque processeur.

Du MIT aux Bell Labs : la naissance de B

À la fin de 1967, un compilateur BCPL est porté vers les grands systèmes utilisés aux Bell Laboratories, notamment GECOS puis Multics. BCPL devient l’un des langages familiers du groupe dans lequel travaillent Ken Thompson et Dennis Ritchie.

Lorsque Thompson travaille ensuite sur le petit PDP-7 qui accueille les débuts d’Unix, les ressources sont extrêmement limitées. Il adapte les idées de BCPL dans un langage encore plus compact, nommé B. Dennis Ritchie fera ensuite évoluer B en ajoutant notamment des types adaptés au PDP-11. Cette transformation donnera naissance au C.

La filiation principale peut donc être résumée ainsi :

CPL  →  BCPL  →  B  →  C

BCPL ne contient pas à lui seul tout ce qui caractérisera le C. Il transmet néanmoins plusieurs idées : un langage compact destiné aux systèmes, des fonctions et des blocs, une mémoire vue comme une suite d’emplacements, une relation étroite entre pointeurs et vecteurs, et une syntaxe conçue pour produire un code efficace.

Même certains détails ont une longue postérité. Le commentaire commençant par // existe en BCPL. Il disparaît des premières versions de B et de C, qui utilisent surtout /* ... */, puis réapparaît en C++ avant d’être intégré à la norme C99.

Coroutines, Tripos et AmigaDOS

En 1977, Richards ajoute à BCPL une bibliothèque de coroutines. Une coroutine ressemble à une fonction capable de suspendre son exécution, de laisser une autre tâche travailler, puis de reprendre plus tard avec son propre contexte.

Ces coroutines sont largement utilisées dans Tripos, un système d’exploitation portable développé à Cambridge à partir de 1977. Tripos est écrit principalement en BCPL, avec les parties directement liées au matériel réalisées en assembleur. Il fonctionne sur plusieurs familles de mini-ordinateurs.

L’histoire de Tripos prolonge celle de BCPL jusque dans la micro-informatique grand public. Tripos sert en effet de base à AmigaDOS, la partie de l’Amiga chargée notamment des fichiers et de l’interface en ligne de commande. Les premières versions de ce composant conservent ainsi un héritage direct de BCPL, près de vingt ans après la naissance du langage.

Les qualités de BCPL

BCPL apporte plusieurs réponses très efficaces aux contraintes de son époque :

  • un compilateur relativement simple, plus facile à comprendre et à adapter que celui de CPL ;
  • une représentation uniforme des valeurs, qui réduit le nombre de cas que le compilateur doit traiter ;
  • un code intermédiaire portable, qui sépare une grande partie du compilateur de la machine cible ;
  • un accès direct à la mémoire, utile pour les systèmes d’exploitation et les compilateurs ;
  • des fonctions, des routines et la récursion, permettant d’organiser des programmes importants ;
  • la compilation séparée, indispensable à la construction de grands logiciels.

Le langage atteint ainsi son objectif principal. Il n’essaie pas de tout prévoir, mais offre un petit ensemble de mécanismes qui peuvent être combinés pour construire des outils complexes.

Les limites : la simplicité au prix de la sécurité

La simplicité de BCPL possède une contrepartie. Puisque toutes les valeurs ont la même forme, le compilateur dispose de peu d’informations pour repérer les erreurs.

Le programmeur doit notamment :

  • se souvenir de ce que représente chaque mot ;
  • ne pas confondre un entier avec une adresse ou une fonction ;
  • respecter lui-même les limites des vecteurs ;
  • organiser les structures de données par convention ;
  • coordonner correctement les positions du vecteur global ;
  • adapter avec soin les programmes lorsque la taille des mots ou la représentation des caractères change.

Une opération syntaxiquement correcte peut donc être dépourvue de sens. BCPL laisse passer des erreurs qu’un langage typé pourrait signaler avant l’exécution.

Cette faiblesse devient particulièrement visible lorsque les machines commencent à traiter naturellement des objets de tailles différentes. Sur le PDP-11, par exemple, les caractères occupent des octets tandis que les entiers et les adresses utilisent des mots. C’est l’une des raisons pour lesquelles Dennis Ritchie ajoute des types à B lors de la création du C.

Pourquoi BCPL reste-t-il important ?

BCPL est aujourd’hui beaucoup moins utilisé que C, mais son influence historique est profonde. Il démontre qu’un langage de programmation système peut être à la fois proche de la machine et conçu pour la portabilité. Il montre aussi l’intérêt de séparer la traduction d’un langage de la production du code propre à chaque processeur.

Son héritage tient principalement à quatre idées :

  • simplifier le langage pour simplifier son implantation ;
  • utiliser une représentation intermédiaire afin de faciliter le portage du compilateur ;
  • écrire des logiciels système dans un langage de haut niveau plutôt qu’entièrement en assembleur ;
  • offrir au programmeur des pointeurs et une représentation directe de la mémoire.

Le langage n’a pas connu la diffusion massive de son descendant C, mais il a fourni une étape décisive. Sans BCPL, B aurait été différent ; sans B, le C n’aurait pas pris la même forme. Derrière une partie de la syntaxe et de la philosophie des langages système modernes se trouve donc un projet né en 1966 et rendu opérationnel au MIT en 1967.

Sources principales

Publications similaires

  • Fortran

    FORTRAN, contraction de FORmula TRANslation (« traduction de formules »), est l’un des langages les plus importants de l’histoire de l’informatique. Développé chez IBM sous la direction de John Backus, il permet aux scientifiques et aux ingénieurs d’écrire leurs calculs sous une forme beaucoup plus proche des mathématiques que des instructions d’une machine.Lorsque le premier…

  • Le langage C

    Le nom C n’est pas un sigle. Il succède au langage B, lui-même issu de BCPL. Le langage qui a rendu Unix portable Au début des années 1970, programmer un système d’exploitation signifie encore travailler presque entièrement en assembleur. Cette méthode permet de contrôler précisément la machine, mais elle exige beaucoup de temps et lie…

  • BASIC

    Le nom BASIC vient de Beginner’s All-purpose Symbolic Instruction Code : un langage pensé pour que des débutants puissent enfin dialoguer avec l’ordinateur. Le langage qui a fait entrer la programmation dans les salles de classe Au début des années 1960, l’ordinateur reste encore une machine distante, coûteuse et intimidante. Dans beaucoup d’universités ou de…

  • ADA

    Ada est un langage de programmation créé à la demande du département de la Défense des États-Unis (DoD) à la fin des années 1970. Son objectif est inhabituel : il ne s’agit pas seulement de faciliter l’écriture des programmes, mais de rendre plus fiables des logiciels complexes destinés à fonctionner pendant de nombreuses années. Ada…

  • Speedcoding

    Speedcoding : le premier langage scientifique moderne oublié de l’histoire de l’informatique En 1953, alors que l’informatique n’en est encore qu’à ses débuts, IBM introduit un système de programmation qui va profondément transformer la manière d’utiliser les ordinateurs scientifiques : Speedcoding. Conçu sous la direction de John W. Backus, ce système ne cherche pas d’abord…