Annexe Unix 72

Voici le premier compilateur écrit en C en 1972 : il s’agit du compilateur C pour UNIX V2. Il fait autorité quant à la première grammaire de ce langage.

Vous en trouverez des archives de plusieurs versions à cette adresse : https://www.tuhs.org/Archive/Distributions/Research/ 🌍⤴

Ainsi que ici : https://www.tuhs.org/cgi-bin/utree.pl 🌍⤴

Cette version comprenait la distinction entre int et char et supportait les nombres flottants en simple et double précision (float et double). Sont absents les entiers short et long, les entiers unsigned et les char signed.

Trois classes de stockage sont gérés : auto, extern et static.

Tout le reste sont des instructions de saut : goto, return, if, while, else, switch, case, break, continue, do, default.

La boucle for n’existe pas.

Les tableaux et les pointeurs sont présents mais pas les structures.

La déclaration de pointeurs ne se fait pas avec une astérisque mais une paire de crochets vide : int p[]. L’aspect général du code ressemble au B. Il est probable que certaines parties du code aient été portées directement depuis le B. Le mot clé extern et auto y tiennent une place plus importante que dans des programmes en C ultérieurs.

L’initialisation en meme temps que la déclaration n’est possible que pour les variables externes, avec une syntaxe qui a disparu depuis : par exemple line 1;.

Ce n’est valable que pour les variables globales non automatiques : Il n’est pas possible d’initialiser et déclarer en meme temps des variables locales (automatiques) comme pour les variables externes.

Il n’y a pas de “constantes” (ni #define, ni enum, ni const existent).

Le nombre de caractères maximal que peut avoir un mot clé ou une variable est de 8 (namsiz 8). Seul le mot-clé continue utilise tous les 8 caractères. Tous les noms de variables, de fonctions sont brefs.

Le mot clé void n’existe pas : une fonction ne peut retourner que un int donc on ne déclare pas le type de la valeur retournée par une fonction. Pas de distinction entre “routines” et “fonctions” comme dans Pascal, il n’y a qu’une seule convention d’appel est à implémenter en assembleur. Si on voulait qu’une fonction retourne un double, on passe soit par une variable externe (globale) ou un pointeur.

Il n’est pas possible ni utile de déclarer les fonctions vu qu’elles ont toutes la même signature : à savoir extern int fonction();.

Trois évolutions du langage ont été nécessaires pour éliminer la nécessité de déclarer dans chaque fonction les variables externes utilisées par celle-ci:

Pouvoir déclarer un symbole extern en dehors des fonctions, ce qui est l’équivalent de réécrire extern fonction, variable, etc; dans chaque fonction.


fun1() {
	extern fun;
}

fun2() {
	extern fun;
}

fun() {}

Peut se simplifier

extern fun;

fun1() {
}

fun2() {
}

fun() {}

Une syntaxe pour distinguer déclaration de variable et déclaration de fonction sera aussi introduite

fun();  /* declare une fonction, extern implicite, n'alloue pas d'espace */
var; /* declare une variable, alloue de l'espace et l'intialise à zero */

extern var2; /* declare une variable sans lui allouer d'espace et sans l'initialiser, 
utile dans les fichier en tetes qui arriveront plus tard,
pour signaler une variable partagée entee plusiers
unités de compilation */

extern fun2(); /* extern ici est optionnel, meme effet que la declaration de fonction precedente */
static fun3(); /* static permet de cacher une fonction à l'editeur de lien, 
le mot-clé static etait deja utilisé pour des variables locales, il est réutilisé 
car il n'y a pas d'ambiguité */

Une règle implicite vis à vis des déclarations de fonctions est que si il n’y en a pas, le compilateur considère que celle ci est de la forme extern int fonction();, c’est à dire une fonction retournant int et prenant un nombre quelconque d’aguments de type quelconque. C’est pour cela que le « hello wold » du premier livre de référence du langage C peut s’écrire ainsi.

main()
{
    printf("Hello, Wold!\n");
}

pas besoin d’importer stdio.h car printf a la signature implicite extern int printf();, et le compilateur lie implicitement la librairie C qui contient la définition de la fonction printf. L’éditeur de lien sera capable de lier l’appel à la fonction printf avec son emplacement effectif dans le programme final. Autrement dit la commande shell cc prog.c est synonyme de cc -lc prog.c.

Toutes les fonctions anciennes de la librairie C, retournent quasiment toutes une valeur int.

Depuis le C99, une telle syntaxe n’est plus valide car une fonction doit déclarer son type de retour, int n’est plus implicite pour main : gcc le tolère jusqu’au C23, où il devient obligatoire d’activer le mode -ansi et -w pour que ce programme compile : gcc -w -ansi prog.c.

Le mot clé void permettra de déclarer une fonction qui ne retourne rien de sorte à pouvoir émuler les “routines” du langage Pascal et faire l’économie d’une instruction assembleur plaçant une valeur de retour sur la pile ou un registre idoine. En sus de void une fonction pourra retourner une valeur de type scalaire quelconque (char, float, double): cela supposat d’implémenter plusieurs conventions d’appel de fonctions, ce qui était hors de propos pour le compilateur minimaliste des premières versions d’UNIX.

Et bien plus tard encore, le C++ a introduit la notion de prototype qui enrichit la notion de déclaration de fonction : non seulement on peut décider le type de valeur retournée par une fonction, ainsi que sa visibilité, mais également contraindre le type et le nombre des arguments acceptés par la fonction, et en introduisant une syntaxe nouvelle pour les fonctions a nombre variable d’arguments : int fontion(int, ...);.

Par pédantisme on peut considérer que la déclaration et le prototype d’une fonction sont deux choses différentes : si un prototype peut être considéré comme une déclaration, le contraire n’est pas forcément vrai.

extern fun; /* declaration "prehistorique" de fonction, locale  */
fun(); /* déclaration plus moderne, externe */
void fun2(); /* déclaration d'une procedure, externe */
int fun3(float, int); /* déclaration moderne, aussi appellée protoype, dans fichier entete si non statique */

C’est surtout avec l’introduction du préprocesseur que les déclarations de fonctions et de variables globales partagées est devenue pertinente.

On rappelle que si le mot clé extern est présent en dehors d’une fonction, celle-ci est valide pour toute l’unité de compilation qui suit. Au demeurant toutes les déclarations de fonction sont considérées comme extern par défaut, ce qui rend ce mot clé utile uniquement pour les variables globales partagées par plusieur unités de compilation qui sinon aloueraient chacune leur propre espace mémoire pour celle ci.

On regroupe donc toutes les déclarations de fonctions utiles dans un fichier* “entête” et on l’inclut via le préprocesseur.

/* entete.h */

int foo();
double bar();
static baz();
extern toto;

/* main.c */

#include "entete.h" 

toto = 1;

main() {
	foo();
	bar();
	/* etc. */
}

c00.c

/* C compiler

Copyright 1972 Bell Telephone Laboratories, Inc. 

*/

ossiz 250;
ospace() {}	/* fake */

init(s, t)
char s[]; {
	extern lookup, symbuf, namsiz;
	char symbuf[], sp[];
	int np[], i;

	i = namsiz;
	sp = symbuf;
	while(i--)
		if ((*sp++ = *s++)=='\0') --s;
	np = lookup();
	*np++ = 1;
	*np = t;
}

main(argc, argv)
int argv[]; {
	extern init, flush;
	extern extdef, eof, open, creat;
	extern fout, fin, error, exit, nerror, tmpfil;

	if(argc<4) {
		error("Arg count");
		exit(1);
	}
	if((fin=open(argv[1],0))<0) {
		error("Can't find %s", argv[1]);
		exit(1);
	}
	if((fout=creat(argv[2], 017))<0) {
		error("Can't create %s", argv[2]);
		exit(1);
	}
	tmpfil = argv[3];
	init("int", 0);
	init("char", 1);
	init("float", 2);
	init("double", 3);
/*	init("long", 4);  */
	init("auto", 5);
	init("extern", 6);
	init("static", 7);
	init("goto", 10);
	init("return", 11);
	init("if", 12);
	init("while", 13);
	init("else", 14);
	init("switch", 15);
	init("case", 16);
	init("break", 17);
	init("continue", 18);
	init("do", 19);
	init("default", 20);
	while(!eof) {
		extdef();
		blkend();
	}
	flush();
	flshw();
	exit(nerror!=0);
}

lookup() {
	extern hshtab[], hshsiz, pssiz, symbuf[];
	extern hshlen, hshused, exit, error, nwps;
	auto i, j, np[], sp[], rp[];

	i = 0;
	sp = symbuf;
	j = nwps;
	while(j--)
		i =+ *sp++;
	if (i<0) i = -i;
	i =% hshsiz;
	i =* pssiz;
	while(*(np = &hshtab[i+4])) {
		sp = symbuf;
		j = nwps;
		while(j--)
			if (*np++ != *sp++) goto no;
		return(&hshtab[i]);
no:		if ((i =+ pssiz) >= hshlen) i = 0;
	}
	if(hshused++ > hshsiz) {
		error("Symbol table overflow");
		exit(1);
	}
	rp = np = &hshtab[i];
	sp = symbuf;
	j = 4;
	while(j--)
		*np++ = 0;
	j = nwps;
	while(j--)
		*np++ = *sp++;
	return(rp);
}

symbol() {
	extern peeksym, peekc, eof, getchar, subseq, error, line;
	extern csym[], getstr, symbuf, namsiz, lookup[], ctab, cval;
	auto b, c;
	char symbuf[], sp[], ctab[];

	if (peeksym>=0) {
		c = peeksym;
		peeksym = -1;
		return(c);
	}
	if (peekc) {
		c = peekc;
		peekc = 0;
	} else
		if (eof)
			return(0); else
			c = getchar();
loop:
	switch(ctab[c]) {

	case 125:	/* newline */
		line++;

	case 126:	/* white space */
		c = getchar();
		goto loop;

	case 0:		/* EOF */
		eof++;
		return(0);

	case 40:	/* + */
		return(subseq(c,40,30));

	case 41:	/* - */
		return(subseq(c,41,31));

	case 80:	/* = */
		if (subseq(' ',0,1)) return(80);
		c = symbol();
		if (c>=40 & c<=49)
			return(c+30);
		if (c==80)
			return(60);
		peeksym = c;
		return(80);

	case 63:	/* < */
		if (subseq(c,0,1)) return(46);
		return(subseq('=',63,62));

	case 65:	/* > */
		if (subseq(c,0,1)) return(45);
		return(subseq('=',65,64));

	case 34:	/* ! */
		return(subseq('=',34,61));

	case 43:	/* / */
		if (subseq('*',1,0))
			return(43);
com:
		c = getchar();
com1:
		if (c=='\0') {
			eof++;
			error("Nonterminated comment");
			return(0);
		}
		if (c=='\n')
			line++;
		if (c!='*')
			goto com;
		c = getchar();
		if (c!='/')
			goto com1;
		c = getchar();
		goto loop;

	case 124:	/* number */
		cval = 0;
		if (c=='0')
			b = 8; else
			b = 10;
		while(ctab[c]==124) {
			cval = cval*b + c -'0';
			c = getchar();
		}
		peekc = c;
		return(21);

	case 122:	/* " */
		return(getstr());

	case 121:	/* ' */
		return(getcc());

	case 123:	/* letter */
		sp = symbuf;
		while(ctab[c]==123 | ctab[c]==124) {
			if (sp<symbuf+namsiz) *sp++ = c;
			c = getchar();
		}
		while(sp<symbuf+namsiz)
			*sp++ = '\0';
		peekc = c;
		csym = lookup();
		if (csym[0]==1) {	/* keyword */
			cval = csym[1];
			return(19);
		}
		return(20);

	case 127:	/* unknown */
		error("Unknown character");
		c = getchar();
		goto loop;

	}
	return(ctab[c]);
}

subseq(c,a,b) {
	extern getchar, peekc;

	if (!peekc)
		peekc = getchar();
	if (peekc != c)
		return(a);
	peekc = 0;
	return(b);
}
getstr() {
	extern isn, cval;
	auto c;

	printf(".data;L%d:.byte ", cval=isn++);
	while((c=mapch('"')) >= 0)
		printf("%o,", c);
	printf("0;.even;.text\n");
	return(22);
}

getcc()
{
	extern cval, ncpw;
	auto c, cc;
	char cp[];

	cval = 0;
	cp = &cval;
	cc = 0;
	while((c=mapch('\'')) >= 0)
		if(cc++ < ncpw)
			*cp++ = c;
	if(cc>ncpw)
		error("Long character constant");
	return(21);
}

mapch(c)
{
	extern peekc, line;
	auto a;

	if((a=getchar())==c)
		return(-1);
	switch(a) {

	case '\n':
	case 0:
		error("Nonterminated string");
		peekc = a;
		return(-1);

	case '\\':
		switch (a=getchar()) {

		case 't':
			return('\t');

		case 'n':
			return('\n');

		case '0':
			return('\0');

		case 'r':
			return('\r');

		case '\n':
			line++;
			return('\n');
		}

	}
	return(a);
}

tree() {
	extern symbol, block, csym[], ctyp, isn,
		peeksym, opdope[], build, error, cp[], cmst[],
		space, ospace, cval, ossiz, exit, errflush, cmsiz;

	auto op[], opst[20], pp[], prst[20], andflg, o,
		p, ps, os;

	space = ospace;
	op = opst;
	pp = prst;
	cp = cmst;
	*op = 200;		/* stack EOF */
	*pp = 06;
	andflg = 0;

advanc:
	switch (o=symbol()) {

	/* name */
	case 20:
		if (*csym==0)
			if((peeksym=symbol())==6)
				*csym = 6;	/* extern */
			else {
				if(csym[2]==0)	/* unseen so far */
					csym[2] = isn++;
			}
			if(*csym==6)	/* extern */
			    *cp++ = block(5,20,csym[1],0,*csym,
					csym[4],csym[5],csym[6],csym[7]);
			else
			    *cp++ = block(2,20,csym[1],0,*csym,csym[2]);
		goto tand;

	/* short constant */
	case 21:
	case21:
		*cp++ = block(1,21,ctyp,0,cval);
		goto tand;

	/* string constant */
	case 22:
		*cp++ = block(1,22,17,0,cval);

tand:
		if(cp>=cmst+cmsiz) {
			error("Expression overflow");
			exit(1);
		}
		if (andflg)
			goto syntax;
		andflg = 1;
		goto advanc;

	/* ++, -- */
	case 30:
	case 31:
		if (andflg)
			o =+ 2;
		goto oponst;

	/* ! */
	case 34:
		if (andflg)
			goto syntax;
		goto oponst;

	/* - */
	case 41:
		if (!andflg) {
			peeksym = symbol();
			if (peeksym==21) {
				peeksym = -1;
				cval = -cval;
				goto case21;
			}
			o = 37;
		}
		andflg = 0;
		goto oponst;

	/* & */
	/* * */
	case 47:
	case 42:
		if (andflg)
			andflg = 0; else
			if(o==47)
				o = 35;
			else
				o = 36;
		goto oponst;

	/* ( */
	case 6:
		if (andflg) {
			o = symbol();
			if (o==7)
				o = 101; else {
				peeksym = o;
				o = 100;
				andflg = 0;
			}
		}
	goto oponst;

	/* ) */
	/* ] */
	case 5:
	case 7:
		if (!andflg)
			goto syntax;
		goto oponst;
	}

	/* binaries */
	if (!andflg)
		goto syntax;
	andflg = 0;

oponst:
	p = (opdope[o]>>9) & 077;
opon1:
	ps = *pp;
	if (p>ps | p==ps & (opdope[o]&0200)!=0) { /* right-assoc */
putin:
		switch (o) {

		case 6: /* ( */
		case 4: /* [ */
		case 100: /* call */
			p = 04;
		}
		if(op>=opst+20) {		/* opstack size */
			error("expression overflow");
			exit(1);
		}
		*++op = o;
		*++pp = p;
		goto advanc;
	}
	--pp;
	switch (os = *op--) {

	/* EOF */
	case 200:
		peeksym = o;
		return(*--cp);

	/* call */
	case 100:
		if (o!=7)
			goto syntax;
		build(os);
		goto advanc;

	/* mcall */
	case 101:
		*cp++ = 0;		/* 0 arg call */
		os = 100;
		goto fbuild;

	/* ( */
	case 6:
		if (o!=7)
			goto syntax;
		goto advanc;

	/* [ */
	case 4:
		if (o!=5)
			goto syntax;
		build(4);
		goto advanc;
	}
fbuild:
	build(os);
	goto opon1;

syntax:
	error("Expression syntax");
	errflush(o);
	return(0);
}

declare(kw) {
	extern csym[], symbol, paraml[], parame[];
	extern error, cval, errflush, peeksym, exit;
	int t[], n, o;

	while((o=symbol())==20) {		/* name */
		if(kw>=5) {			/* type or sort? */
			if(*csym>0)
				error("%p redeclared", csym[4]);
			*csym = kw;
		} else {
			if ((csym[1]&017)!=0)
				error("%p redeclared", &csym[4]);
			csym[1] =| csym[1]&0760 | kw;
			if (*csym==0)
				*csym = -2;
		}
		while((o=symbol())==4) {	/* [ */
			if((o=symbol())==21) {	/* const */
				if(csym[1]>=020)
					error("Bad vector");
				csym[3] = cval;
				o = symbol();
			}
			if (o!=5)		/* ] */
				goto syntax;
			csym[1] =+ 020;
		}
		if(kw==8)  {		/* parameter */
			*csym = -1;
			if (paraml==0)
				paraml = csym;
			else
				*parame = csym;
			parame = csym;
		}
		if (o!=9)	/* , */
			break;
	}
	if(o==1 & kw!=8 | o==7 & kw==8)
		return;
syntax:
	error("Declaration syntax");
	errflush(o);
}

/* storage */

regtab 0;
efftab 1;
cctab 2;
sptab 3;
symbuf[4];
pssiz 8;
namsiz 8;
nwps 4;
hshused 0;
hshsiz 100;
hshlen 800;	/* 8*hshsiz */
hshtab[800];
space 0;
cp 0;
cmsiz 40;
cmst[40];
ctyp 0;
isn 1;
swsiz 120;
swtab[120];
swp 0;
contlab 0;
brklab 0;
deflab 0;
nreg 4;
maprel[] 60,61,64,65,62,63,68,69,66,67;
nauto 0;
stack 0;
peeksym 0177777;
peekc 0;
eof 0;
line 1;
csym 0;
cval 0;
ncpw 2;
nerror 0;
paraml;
parame;
tmpfil;

c01.c

build(op) {
	extern cp[], error, block, opdope[], maprel[], chklval;
	extern chkw, cvtab, lintyp, dcalc;
	auto p1[], t1, d1, p2[], t2, d2, p3[], t3, d3, t;
	auto d, dope, lr, cvn;
	char cvtab[];

	if (op==4)  {		/* [] */
		build(40);  /* + */
		op = 36;
	}
	dope = opdope[op];
	if ((dope&01)!=0) {
		p2 = *--cp;
		t2 = p2[1];
		d2 = p2[2];
	}
	p1 = *--cp;
	t1 = p1[1];
	d1 = p1[2];
	switch (op) {

	/* , */
	case 9:
		*cp++ = block(2, 9, 0, 0, p1, p2);
		return;

	/* ? */
	case 90:
		if (*p2!=8)
			error("Illegal conditional");
		goto goon;

	/* call */
	case 100:
		*cp++ = block(2,100,t1,24,p1,p2);
		return;

	/* * */
	case 36:
		if ((t1 =- 16)<0)  {
			error("Illegal indirection");
			t1 =+ 16;
		}
		if (*p1!=20 & d1==0)
			d1 = 1;
		*cp++ = block(1,36,t1,d1,p1);
		return;

	/* & unary */
	case 35:
		if (*p1 == 36) {	/* * */
			*cp++ = p1[3];
			return;
		}
		if (*p1 == 20) {
			*cp++ = block(1,p1[3]==5?29:35,t1+16,1,p1);
			return;
		}
		error("Illegal lvalue");
	}
goon:
	if ((dope&02)!=0)		/* lvalue needed on left? */
		chklval(p1);
	if ((dope&020)!=0)		/* word operand on left? */
		chkw(p1);
	if ((dope&040)!=0)		/* word operand on right? */
		chkw(p2);
	if ((dope&01)!=0) {		/* binary op? */
		cvn = cvtab[9*lintyp(t1)+lintyp(t2)];
 		if ((dope&010)!=0)  {	/* assignment? */
			t = t1;
			lr = 1;
			cvn =& 07;
		} else {
			t = (cvn&0100)!=0? t2:t1;
			lr = cvn&0200;
			cvn = (cvn>>3)&07;
		}
		if (cvn) {
			if (cvn==07) {
				error("Illegal conversion");
				goto nocv;
			}
			cvn =+ (dope&010)!=0? 83:93;
			if (lr) {
				t2 = t;
				 d2 = (p2=convert(p2, t, d2, cvn))[2];
			} else {
				t1 = t;
				d1 = (p1=convert(p1, t, d1, cvn))[2];
			}
nocv:;		}
		if (d2>d1 & (dope&0100)!=0) {	/* flip commutative? */
			if ((dope&04)!=0)	/* relational? */
				op = maprel[op-60];
			d = d1;
			d1 = d2;
			d2 = d;
			d = p1;
			p1 = p2;
			p2 = d;
			d = t1;
			t1 = t2;
			t2 = d;
		}
		if (d1==d2)
			d = d1+1; else
			d = max(d1,d2);
		if ((dope&04)!=0)
			t = 0;		/* relational is integer */
		*cp++ = block(2,op,t,d,p1,p2);
		return;
	}
	*cp++ = block(1,op,t1,d1==0?1:d1,p1);
}

convert(p, t, d, cvn)
int p[];
{
	auto c;
	if (*p==21) {		/* constant */
		c = p[3];
		switch(cvn) {

		case 99:		/* c18 */
			c =<< 1;

		case 98:		/* c14 */
			c =<< 1;

		case 97:		/* c12 */
			c =<< 1;

			p[3] = c;
		return(p);
		}
	}
	return(block(1, cvn, t, max(1,d), p));
}

chkw(p)
int p[]; {
	extern error;
	auto t;

	if ((t=p[1])>1 & t<16)
		error("Integer operand required");
	return;
}

lintyp(t) {
	return(t<16? t:(t<32? t-12: 8));
}

error(s, p1, p2) {
	extern printf, line, fout, flush, putchar, nerror;
	int f;

	nerror++;
	flush();
	f = fout;
	fout = 1;
	printf("%d: ", line);
	printf(s, p1, p2);
	putchar('\n');
	fout = f;
}

block(n, op, t, d, p1,p2,p3)
int p1[],p2[],p3[]; {
	extern space[], error, exit, ossiz, ospace[];
	auto p[], ap[];

	p = space;
	ap = &op;
	n =+ 3;
	if(space+n >= ospace+ossiz) {
		error("Expression overflow");
		exit(1);
	}
	while(n--)
		*space++ = *ap++;
	return(p);
}

chklval(p)
int p[]; {
	extern error;
	if (*p!=20)
		if (*p!=36)
			error("Lvalue required");
}

notcompat(at, st) {

	if (st==0)		/* word, byte */
		return(at>1 & at<16);
	if (st==1)		/* word */
		return(at>0 & at<16);
	return((st-2) != at);
}

max(a, b)
{
	if (a>b)
		return(a);
	return(b);
}

c02.c

function() {
	extern declare, blkhed, blkend;
	extern printf, statement, peeksym, cval, symbol, retseq;
	extern paraml;
	auto o;

	printf(".text; 1:mov r5,-(sp); mov sp,r5\n");
	declare(8);
	declist();
	statement(1);
	retseq();
}

extdef() {
	extern eof, function, cval;
	extern symbol, block, printf, pname, errflush, csym[];
	extern error;
	auto o, c, cs[];
	char s[];

	if(((o=symbol())==0) | o==1)	/* EOF */
		return;
	if(o!=20)
		goto syntax;
	csym[0] = 6;
	cs = &csym[4];
	printf(".globl	%p\n", cs);
	s = ".data; %p:1f\n";
	switch(o=symbol()) {

	case 6:				/* ( */
		printf(s, cs);
		function();
		return;

	case 21:			/* const */
		printf(".data; %p: %o\n", cs, cval);
		if((o=symbol())!=1)	/* ; */
			goto syntax;
		return;

	case 1:				/* ; */
		printf(".bss; %p: .=.+2\n", cs);
		return;

	case 4:				/* [ */
		c = 0;
		if((o=symbol())==21) {	/* const */
			c = cval<<1;
			o = symbol();
		}
		if(o!=5)		/* ] */
			goto syntax;
		printf(s, cs);
		if((o=symbol())==1) {	/* ; */
			printf(".bss; 1:.=.+%o\n", c);
			return;
		}
		printf("1:");
		while(o==21) {		/* const */
			printf("%o\n", cval);
			c =- 2;
			if((o=symbol())==1)	/* ; */
				goto done;
			if(o!=9)		/* , */
				goto syntax;
			else
				o = symbol();
		}
		goto syntax;
	done:
		if(c>0)
			printf(".=.+%o\n", c);
		return;

	case 0:				/* EOF */
		return;
	}

syntax:
	error("External definition syntax");
	errflush(o);
	statement(0);
}

statement(d) {
	extern symbol, error, blkhed, eof, peeksym;
	extern blkend, csym[], rcexpr, block[], tree[], regtab[];
	extern retseq, jumpc, jump, label, contlab, brklab, cval;
	extern swp[], isn, pswitch, peekc, slabel;
	extern efftab[], declare, deflab, errflush, swtab[], swsiz, branch;

	int o, o1, o2, o3, np[];

stmt:
	switch(o=symbol()) {

	/* EOF */
	case 0:
		error("Unexpected EOF");
	/* ; */
	case 1:
	/* } */
	case 3:
		return;

	/* { */
	case 2: {
		if(d)
			blkhed();
		while (!eof) {
			if ((o=symbol())==3)	/* } */
				goto bend;
			peeksym = o;
			statement(0);
		}
		error("Missing '}'");
	bend:
		return;
	}

	/* keyword */
	case 19:
		switch(cval) {

		/* goto */
		case 10:
			o1 = block(1,102,0,0,tree());
			rcexpr(o1, regtab);
			goto semi;

		/* return */
		case 11:
			if((peeksym=symbol())==6)	/* ( */
				rcexpr(pexpr(), regtab);
			retseq();
			goto semi;

		/* if */
		case 12:
			jumpc(pexpr(), o1=isn++, 0);
			statement(0);
			if ((o=symbol())==19 & cval==14) {  /* else */
				o2 = isn++;
				(easystmt()?branch:jump)(o2);
				label(o1);
				statement(0);
				label(o2);
				return;
			}
			peeksym = o;
			label(o1);
			return;

		/* while */
		case 13:
			o1 = contlab;
			o2 = brklab;
			label(contlab = isn++);
			jumpc(pexpr(), brklab=isn++, 0);
			o3 = easystmt();
			statement(0);
			(o3?branch:jump)(contlab);
			label(brklab);
			contlab = o1;
			brklab = o2;
			return;

		/* break */
		case 17:
			if(brklab==0)
				error("Nothing to break from");
			jump(brklab);
			goto semi;

		/* continue */
		case 18:
			if(contlab==0)
				error("Nothing to continue");
			jump(contlab);
			goto semi;

		/* do */
		case 19:
			o1 = contlab;
			o2 = brklab;
			contlab = isn++;
			brklab = isn++;
			label(o3 = isn++);
			statement(0);
			label(contlab);
			contlab = o1;
			if ((o=symbol())==19 & cval==13) { /* while */
				jumpc(tree(), o3, 1);
				label(brklab);
				brklab = o2;
				goto semi;
			}
			goto syntax;

		/* case */
		case 16:
			if ((o=symbol())!=21)	/* constant */
				goto syntax;
			if ((o=symbol())!=8)	/* : */
				goto syntax;
			if (swp==0) {
				error("Case not in switch");
				goto stmt;
			}
			if(swp>=swtab+swsiz) {
				error("Switch table overflow");
			} else {
				*swp++ = isn;
				*swp++ = cval;
				label(isn++);
			}
			goto stmt;

		/* switch */
		case 15:
			o1 = brklab;
			brklab = isn++;
			np = pexpr();
			if (np[1]>1 & np[1]<16)
				error("Integer required");
			rcexpr(np, regtab);
			pswitch();
			brklab = o1;
			return;

		/* default */
		case 20:
			if (swp==0)
				error("Default not in switch");
			if ((o=symbol())!=8)	/* : */
				goto syntax;
			deflab = isn++;
			label(deflab);
			goto stmt;
		}

		error("Unknown keyword");
		goto syntax;

	/* name */
	case 20:
		if (peekc==':') {
			peekc = 0;
			if (csym[0]>0) {
				error("Redefinition");
				goto stmt;
			}
			csym[0] = 2;
			csym[1] = 020;	/* int[] */
			if (csym[2]==0)
				csym[2] = isn++;
			slabel();
			goto stmt;
		}
	}

	peeksym = o;
	rcexpr(tree(), efftab);
	goto semi;

semi:
	if ((o=symbol())!=1)		/* ; */
		goto syntax;
	return;

syntax:
	error("Statement syntax");
	errflush(o);
	goto stmt;
}

pexpr()
{
	auto o, t;

	if ((o=symbol())!=6)	/* ( */
		goto syntax;
	t = tree();
	if ((o=symbol())!=7)	/* ) */
		goto syntax;
	return(t);
syntax:
	error("Statement syntax");
	errflush(o);
	return(0);
}

pswitch() {
	extern swp[], isn, swtab[], printf, deflab, statement, brklab;
	extern label;
	int sswp[], dl, cv, swlab;

	sswp = swp;
	if (swp==0)
		swp = swtab;
	swlab = isn++;
	printf("jsr	pc,bswitch; l%d\n", swlab);
	dl = deflab;
	deflab = 0;
	statement(0);
	if (!deflab) {
		deflab = isn++;
		label(deflab);
	}
	printf("L%d:.data;L%d:", brklab, swlab);
	while(swp>sswp & swp>swtab) {
		cv = *--swp;
		printf("%o; l%d\n", cv, *--swp);
	}
	printf("L%d; 0\n.text\n", deflab);
	deflab = dl;
	swp = sswp;
}

blkhed()
{
	extern symbol, cval, declare, peeksym, paraml[], parame[];
	extern error, length, rlength, setstk, defvec, isn, defstat;
	extern stack, hshtab[], hshsiz, pssiz;
	int o, al, pl, cs[], hl;

	declist();
	stack = al = -2;
	pl = 4;
	while(paraml) {
		*parame = 0;
		paraml = *(cs = paraml);
		cs[2] = pl;
		*cs = 10;
		pl =+ rlength(cs[1]);
	}
	cs = hshtab;
	hl = hshsiz;
	while(hl--) {
	    if (cs[4])
		switch(cs[0]) {

		/* sort unmentioned */
		case 0177776:	/* -2 */
			cs[0] = 5;		/* auto */

		/* auto */
		case 5:
			if (cs[3]) {	/* vector */
				al =- (cs[3]*length(cs[1]-020)+1) & 077776;
				setstk(al);
				defvec(al);
			}
			cs[2] = al;
			al =- rlength(cs[1]);
			goto loop;

		/* parameter */
		case 10:
			cs[0] = 5;
			goto loop;

		/* static */
		case 7:
			cs[2] = isn++;
			defstat(cs);
			goto loop;

		loop:;
		}
		cs = cs+pssiz;
	}
	setstk(al);
}

blkend() {
	extern hshtab[], hshsiz, pssiz, hshused;
	auto i, hl;

	i = 0;
	hl = hshsiz;
	while(hl--) {
		if(hshtab[i+4])
			if (hshtab[i]==0)
				error("%p undefined", &hshtab[i+4]);
			if(hshtab[i]!=1) {	/* not keyword */
				hshused--;
				hshtab[i+4] = 0;
			}
		i =+ pssiz;
	}
}

errflush(o) {
	extern symbol, peeksym, eof;

	while(o>3)	/* ; { } */
		o = symbol();
	peeksym  = o;
}

declist()
{
	extern peeksym, peekc, csym[], cval;
	auto o;

	while((o=symbol())==19 & cval<10)
		declare(cval);
	peeksym = o;
}

easystmt()
{
	extern peeksym, peekc, cval;

	if((peeksym=symbol())==20)	/* name */
		return(peekc!=':');	 /* not label */
	if (peeksym==19) {		/* keyword */
		switch(cval)

		case 10:	/* goto */
		case 11:	/* return */
		case 17:	/* break */
		case 18:	/* continue */
			return(1);
		return(0);
	}
	return(peeksym!=2);		/* { */
}

branch(lab)
{
	printf("br	L%d\n", lab);
}

c03.c

jumpc(tree, lbl, cond)
int tree[];
{
	extern cctab, block, rcexpr;

	rcexpr(block(1,easystmt()+103,tree,lbl,cond),cctab);
}

rcexpr(tree, table)
int tree[], table;
{
	extern space, ospace, putwrd, putchar, line;
	int c, sp[];

	putchar('#');
	c = space-ospace;
	c =/ 2;		/* # addresses per word */
	sp = ospace;

	putwrd(c);
	putwrd(tree);
	putwrd(table);
	putwrd(line);
	while(c--)
		putwrd(*sp++);
}

jump(lab) {
	extern printf;

	printf("jmp\tl%d\n", lab);
}

label(l) {
	extern printf;

	printf("l%d:", l);
}

retseq() {
	extern printf;

	printf("jmp\tretrn\n");
}

slabel() {
	extern csym[], printf;

	printf(".data; l%d: 1f; .text; 1:\n", csym[2]);
}

setstk(a) {
	extern printf, stack;
	auto ts;

	ts = a-stack;
	stack = a;
	switch(ts) {

	case 0:
		return;

	case 0177776:	/* -2 */
		printf("tst	-(sp)\n");
		return;

	case 0177774:	/* -4 */
		printf("cmp	-(sp),-(sp)\n");
		return;
	}
	printf("add	$%o,sp\n", ts);
}

defvec() {
	extern printf, stack;

	printf("mov\tsp,r0\nmov\tr0,-(sp)\n");
	stack =- 2;
}

defstat(s)
int s[]; {
	extern printf, length;
	int len;

	len = length(s[1]);
	if (s[3])
		printf(".data; l%d:1f; .bss; 1:.=.+%o; .even; .text\n", s[2],
			s[3]*len);
	else
		printf(".bss; l%d:.=.+%o; .even; .text\n", s[2], len);
}

length(t) {

	if (t<0)
		t =+ 020;
	if (t>=020)
		return(2);
	switch(t) {

	case 0:
		return(2);

	case 1:
		return(1);

	case 2:
		return(4);

	case 3:
		return(8);

	case 4:
		return(4);

	}
	return(1024);
}

rlength(c) {
	extern length;
	auto l;

	return((l=length(c))==1? 2: l);
}

printn(n,b) {
	extern putchar;
	auto a;

	if(a=n/b) /* assignment, not test for equality */
		printn(a, b); /* recursive */
	putchar(n%b + '0');
}

printf(fmt,x1,x2,x3,x4,x5,x6,x7,x8,x9)
char fmt[]; {
	extern printn, putchar, namsiz, ncpw;
	char s[];
	auto adx[], x, c, i[];

	adx = &x1; /* argument pointer */
loop:
	while((c = *fmt++) != '%') {
		if(c == '\0')
			return;
		putchar(c);
	}
	x = *adx++;
	switch (c = *fmt++) {

	case 'd': /* decimal */
	case 'o': /* octal */
		if(x < 0) {
			x = -x;
			if(x<0)  {	/* - infinity */
				if(c=='o')
					printf("100000");
				else
					printf("-32767");
				goto loop;
			}
			putchar('-');
		}
		printn(x, c=='o'?8:10);
		goto loop;

	case 's': /* string */
		s = x;
		while(c = *s++)
			putchar(c);
		goto loop;

	case 'p':
		s = x;
		putchar('_');
		c = namsiz;
		while(c--)
			if(*s)
				putchar(*s++);
		goto loop;
	}
	putchar('%');
	fmt--;
	adx--;
	goto loop;
}

c0t.s

/ word I/O

.globl	_putwrd

.globl	_tmpfil
.globl	putw
.globl	fcreat
.globl	flush

.data
_putwrd: 1f
.text
1:
	tst	buf
	bne	1f
	mov	_tmpfil,r0
	jsr	r5,fcreat; buf
	bec	1f
	mov	$1,r0
	sys	write; botch; ebotch-botch
	sys	exit
1:
	mov	2(sp),r0
	jsr	r5,putw; buf
	rts	pc
.globl	_flshw
.data
_flshw:	1f
.text
1:
	jsr	r5,flush; buf
	rts	pc

botch:	<Temp file?\n\0>; ebotch:
.even

.bss
buf:	.=.+518.
.text

/ C operator and conversion tables

.globl	_opdope
.globl	_cvtab

_opdope:.+2
	00000	/ EOF
	00000	/ ;
	00000	/ {
	00000	/ }
	36000	/ [
	02000	/ ]
	36000	/ (
	02000	/ )
	14201	/ :
	07001	/ ,
	00000	/ 10
	00000	/ 11
	00000	/ 12
	00000	/ 13
	00000	/ 14
	00000	/ 15
	00000	/ 16
	00000	/ 17
	00000	/ 18
	00000	/ 19
	00000	/ name
	00000	/ short constant
	00000	/ string
	00000	/ float
	00000	/ double
	00000	/ 25
	00000	/ 26
	00000	/ 27
	00000	/ 28
	00000	/ 29
	34202	/ ++pre
	34202	/ --pre
	34202	/ ++post
	34202	/ --post
	34220	/ !un
	34202	/ &un
	34220	/ *un
	34200	/ -un
	34220	/ ~un
	00000	/ 39
	30101	/ +
	30001	/ -
	32101	/ *
	32001	/ /
	32001	/ %
	26061	/ >>
	26061	/ <<
	20161	/ &
	16161	/ |
	16161	/ ^
	00000	/ 50
	00000	/ 51
	00000	/ 52
	00000	/ 53
	00000	/ 54
	00000	/ 55
	00000	/ 56
	00000	/ 57
	00000	/ 58
	00000	/ 59
	22105	/ ==
	22105	/ !=
	24105	/ <=
	24105	/ <
	24105	/ >=
	24105	/ >
	24105	/ <p
	24105	/ <=p
	24105	/ >p
	24105	/ >=p
	12213	/ =+
	12213	/ =-
	12213	/ =*
	12213	/ =/
	12213	/ =%
	12253	/ =>>
	12253	/ =<<
	12253	/ =&
	12253	/ =|
	12253	/ =^
	12213	/ =
	00000	/ 81
	00000	/ 82
	00000	/ 83
	00000	/ int -> float
	00000	/ int -> double
	00000	/ float -> int
	00000	/ float -> double
	00000	/ double -> int
	00000	/ double -> float
	14201	/ ?
	00000	/ 91
	00000	/ 92
	00000	/ 93
	00000	/ int -> float
	00000	/ int -> double
	00000	/ float -> double
	00000	/ int -> int[]
	00000	/ int -> float[]
	00000	/ int -> double[]
	36001	/ call
	36001	/ mcall

_cvtab:	.+2
	.byte	000	/ i:i
	.byte	000	/ i:c
	.byte	113	/ i:f
	.byte	125	/ i:d
	.byte	140	/ i:i[]
	.byte	100	/ i:c[]
	.byte	150	/ i:f[]
	.byte	160	/ i:d[]
	.byte	140	/ i:[][]

	.byte	100	/ c:i
	.byte	100	/ c:c
	.byte	113	/ c:f
	.byte	125	/ c:d
	.byte	140	/ c:i[]
	.byte	100	/ c:c[]
	.byte	150	/ c:f[]
	.byte	160	/ c:d[]
	.byte	140	/ c[][]

	.byte	211	/ f:i
	.byte	211	/ f:c
	.byte	000	/ f:f
	.byte	136	/ f:d
	.byte	211	/ f:i[]
	.byte	211	/ f:c[]
	.byte	211	/ f:f[]
	.byte	211	/ f:d[]
	.byte	211	/ f:[][]

	.byte	222	/ d:i
	.byte	222	/ d:c
	.byte	234	/ d:f
	.byte	000	/ d:d
	.byte	222	/ d:i[]
	.byte	222	/ d:c[]
	.byte	222	/ d:f[]
	.byte	222	/ d:d[]
	.byte	222	/ d:[][]

	.byte	240	/ i[]:i
	.byte	240	/ i[]:c
	.byte	113	/ i[]:f
	.byte	125	/ i[]:d
	.byte	000	/ i[]:i[]
	.byte	000	/ i[]:c[]
	.byte	100	/ i[]:f[]
	.byte	100	/ i[]:d[]
	.byte	100	/ i[]:[][]

	.byte	000	/ c[]:i
	.byte	000	/ c[]:c
	.byte	113	/ c[]:f
	.byte	125	/ c[]:d
	.byte	200	/ c[]:i[]
	.byte	000	/ c[]:c[]
	.byte	200	/ c[]:f[]
	.byte	200	/ c[]:d[]
	.byte	200	/ c[]:[][]

	.byte	250	/ f[]:i
	.byte	250	/ f[]:c
	.byte	113	/ f[]:f
	.byte	125	/ f[]:d
	.byte	000	/ f[]:i[]
	.byte	000	/ f[]:c[]
	.byte	000	/ f[]:f[]
	.byte	100	/ f[]:d[]
	.byte	000	/ f[]:[][]

	.byte	260	/ d[]:i
	.byte	260	/ d[]:c
	.byte	113	/ d[]:f
	.byte	125	/ d[]:d
	.byte	000	/ d[]:i[]
	.byte	000	/ d[]:c[]
	.byte	000	/ d[]:f[]
	.byte	000	/ d[]:d[]
	.byte	000	/ d[]:[][]

	.byte	240	/ [][]:i
	.byte	240	/ [][]:c
	.byte	113	/ [][]:f
	.byte	125	/ [][]:d
	.byte	000	/ [][]:i[]
	.byte	000	/ [][]:c[]
	.byte	100	/ [][]:f[]
	.byte	100	/ [][]:d[]
	.byte	000	/ [][]:[][]

.even

/ character type table

.globl	_ctab

_ctab: .+2
	.byte 000.,127.,127.,127.,127.,127.,127.,127.
	.byte 127.,126.,125.,127.,127.,127.,127.,127.
	.byte 127.,127.,127.,127.,127.,127.,127.,127.
	.byte 127.,127.,127.,127.,127.,127.,127.,127.
	.byte 126.,034.,122.,127.,127.,044.,047.,121.
	.byte 006.,007.,042.,040.,009.,041.,127.,043.
	.byte 124.,124.,124.,124.,124.,124.,124.,124.
	.byte 124.,124.,008.,001.,063.,080.,065.,090.
	.byte 127.,123.,123.,123.,123.,123.,123.,123.
	.byte 123.,123.,123.,123.,123.,123.,123.,123.
	.byte 123.,123.,123.,123.,123.,123.,123.,123.
	.byte 123.,123.,123.,004.,127.,005.,049.,127.
	.byte 127.,123.,123.,123.,123.,123.,123.,123.
	.byte 123.,123.,123.,123.,123.,123.,123.,123.
	.byte 123.,123.,123.,123.,123.,123.,123.,123.
	.byte 123.,123.,123.,002.,048.,003.,127.,127.

c10.c

/*

	    	C compiler, part 2

	Copyright 1972 Bell Telephone Laboratories, Inc.

*/

ospace() {}	/* fake */

waste()		/* waste space */
{
	waste(waste(waste),waste(waste),waste(waste));
	waste(waste(waste),waste(waste),waste(waste));
	waste(waste(waste),waste(waste),waste(waste));
	waste(waste(waste),waste(waste),waste(waste));
	waste(waste(waste),waste(waste),waste(waste));
	waste(waste(waste),waste(waste),waste(waste));
	waste(waste(waste),waste(waste),waste(waste));
	waste(waste(waste),waste(waste),waste(waste));
}
main(argc, argv)
char argv[][];
{
	extern fout, fin, nerror, line;
	extern getwrd, rcexpr, ospace, tmpfil;
	extern cctab[], regtab[], efftab[], sptab[];
	int sp[], c, table[], tabtab[3][], tree;

	if (argc<4) {
		error("Arg count");
		exit(1);
	}
	if((fin=open(argv[1],0))<0) {
		error("Cant't find %s", argv[1]);
		exit(1);
	}
	if((fout=creat(argv[3],017))<0) {
		error("Can't create %s", argv[3]);
		exit(1);
	}
	tmpfil = argv[2];

	tabtab[0] = regtab;
	tabtab[1] = efftab;
	tabtab[2] = cctab;
	tabtab[3] = sptab;
	while(c=getchar()) {
		if(c=='#') {
			sp = ospace;
			c = getwrd();
			tree = getwrd();
			table = tabtab[getwrd()];
			line = getwrd();
			while(c--)
				*sp++ = getwrd();
			rcexpr(tree, table, 0);
		} else
			putchar(c);
	}
	flush();
	exit(nerror!=0);
}

match(tree, table, nreg)
int tree[], table[]; {
	extern opdope[], dcalc, notcompat;
	int op, d1, d2, t1, t2, p1[], p2[];
	char mp[];

	if (tree==0)
		return(0);
	op = *tree;
	if (op>=29)			/* if not leaf */
		p1 = tree[3];
	else
		p1 = tree;
	t1 = p1[1];
	d1 = dcalc(p1, nreg);
	if ((opdope[op]&01)!=0) {	/* binary? */
		p2 = tree[4];
		t2 = p2[1];
		d2 = dcalc(p2, nreg);
	}
	while(*table) {
		if (*table++ == op) goto foundop;
		table++;
	}
	return(0);
foundop:
	table = *table;
nxtry:
	mp = table;
	if (*mp == 0)
		return(0);
	if (d1 > (*mp&077) | (*mp>=0100)&(*p1!=36))
		goto notyet;
	if (notcompat(t1, mp[1]))
		goto notyet;
	if ((opdope[op]&01)!=0 & p2!=0) {
		if (d2 > (mp[2]&077) | (mp[2]>=0100)&(*p2!=36))
			goto notyet;
		if (notcompat(t2,mp[3]))
			goto notyet;
	}
now:
	return(table[2]);
notyet:
	table = table+3;
	goto nxtry;
}

rcexpr(tree, table, reg)
int tree[]; {
	extern cexpr, regtab, cctab, sptab, printf, error;
	extern jumpc, cbranch;

	if(tree==0)
		return;
	if(*tree >= 103) {
		(*tree==103?jumpc:cbranch)(tree[1],tree[2],tree[3],0);
		return;
	}
	if (cexpr(tree, table, reg))
		return;
	if (table!=regtab) 
		if(cexpr(tree, regtab, reg)) {
			if (table==sptab)
				printf("mov	r%d,-(sp)\n", reg);
			if (table==cctab)
				printf("tst	r%d\n", reg);
			return;
		}
	error("No match for op %d", *tree);
}

cexpr(tree, table, reg)
int tree[][], table[]; {
	extern match, nreg, printf, pname, putchar, regtab;
	extern sptab, cctab, rcexpr, prins, rlength, popstk;
	extern collcon, isn, label, branch, cbranch, fltmod;
	int p1[], p2[], c, r, p[], otable[], ctable[], regtab[], cctab[];
	char string[], match[];

	if ((c = *tree)==100) {		/* call */
		p1 = tree[3];
		p2 = tree[4];
		r = 0;
		if(p2) {
			while (*p2==9) { /* comma */
				rcexpr(p2[4], sptab, 0);
				r =+ rlength((p=p2[4])[1]);
				p2 = p2[3];
			}
			rcexpr(p2, sptab, 0);
			r =+ rlength(p2[1]);
		}
		*tree = 101;
		tree[2] = r;		/* save arg length */
	}
	if(c==90) {		/* ? */
		cbranch(tree[3], c=isn++, 0, reg);
		rcexpr(tree[4][3], table, reg);
		branch(r=isn++, 0);
		label(c);
		rcexpr(tree[4][4], table, reg);
		label(r);
		return(1);
	}
	if ((string=match(tree, table, nreg-reg))==0) 
		return(0);
	p1 = tree[3];
	p2 = tree[4];
loop:
	switch(c = *string++) {

	case '\0':
		p = tree;
		if (*p==101 & p[2]>0) {
			popstk(p[2]);
		}
		return(1);

	/* A1 */
	case 'A':
		p = tree[3];
		goto adr;

	/* A2 */
	case 'B':
		p = tree[4];
		goto adr;

	/* A */
	case 'O':
		p = tree;
	adr:
		pname(p);
		goto loop;

	/* I */
	case 'M':
		if ((c = *string)=='\'')
			string++; else
			c = 0;
		prins(*tree, c);
		goto loop;

	/* B1 */
	case 'C':
		p = tree[3];
		goto pbyte;

	/* BF */
	case 'P':
		p = tree;
		goto pb1;

	/* B2 */
	case 'D':
		p = tree[4];
	pbyte:
		if (p[1]==1)	/* char type? */
			putchar('b');
pb1:
		if (isfloat(p))
			putchar('f');
		goto loop;

	/* BE */
	case 'L':
		if (tree[3][1]==1 | tree[4][1]==1)
			putchar('b');
		goto loop;

	/* C1 */
	case 'E':
		p = p1[3];
		goto const;

	/* C2 */
	case 'F':
		p = p2[3];
	const:
		printf("%o", p);
		goto loop;

	/* F */
	case 'G':
		p = p1;
		goto subtre;

	/* S */
	case 'K':
		p = p2;
		goto subtre;

	/* H */
	case 'H':
		p = tree;

	subtre:
		ctable = regtab;
		r = reg;
		c = *string++ - 'A';
		if ((c&02)!=0)
			ctable = sptab;
		if ((c&04)!=0)
			ctable = cctab;
		if((c&010)!=0)
			r = reg+1;
		if((c&01)!=0)
			if(*p==36) {
				p = p[3];
				if(collcon(p) & ctable!=sptab)
					p = p[3];
			}
		rcexpr(p, ctable, r);
		goto loop;

	/* R */
	case 'I':
		r = reg;
		goto preg;

	/* R1 */
	case 'J':
		r = reg+1;
	preg:
		printf("r%d", r);
		goto loop;

	case '#':
		p = p1[3];
		goto nmbr;

	case '"':
		p = p2[3];
		goto nmbr;
	case '~':
		p = tree[3];

	nmbr:
		if(collcon(p)) {
			c = *p;
			if(r = (p=p[4])[3])
				printf("%o", c==40?r:-r);
		}
		goto loop;

	/* M */
	case 'N':
		if ((c=isfloat(tree, &string))==fltmod)
			goto loop;
		printf((fltmod=c)==2?"setf\n":"setd\n");
		goto loop;

	/* Z */
	case 'Z':
		printf("$%o", p1[4]);
		goto loop;
	}
	putchar(c);
	goto loop;
}

pname(p)
int p[][][]; {
	extern putchar, printf, error;
	char np[];
	int i;

loop:
	switch(*p) {

	case 21:		/* const */
		printf("$%o", p[3]);
		return;

	case 22:		/* string */
		printf("$l%d", p[3]);
		return;

	case 20:		/* name */
		switch(p[3]) {

		case 5:		/* auto, param */
			printf("%o(r5)", p[4]);
			return;

		/* extern */
		case 6:
			printf("%p", &p[4]);
			return;

		}
		printf("L%d", p[4]);
		return;

	case 35:		/* & */
		putchar('$');
		p = p[3];
		goto loop;

	case 36:		/* * */
		putchar('*');
		p = p[3];
		goto loop;
	}
	error("pname called illegally");
}

dcalc(p, nreg)
int p[]; {
	int op, t;

	if (p==0)
		return(0);
	op = *p;
	switch (op) {

	case 20:		/* name */
	case 22:		/* string */
	case 23:		/* float */
	case 24:		/* double */
		return(12);

	case 21:		/* short constant */
		return(p[3]==0? 4:8);

	case 35:		/* & */
		return(12);

	case 36:		/* * */
		if ((op=dcalc(p[3], nreg))<16)
			return(16);
	}

def:
	return(p[2]<=nreg? 20: 24);
}

notcompat(at, st) {

	if (st==0)		/* word, byte */
		return(at>1 & at<16);
	if (st==1)		/* word */
		return(at>0 & at<16);
	st =- 2;
	if (st==2 & at==3)
		at = 2;
	return(st != at);
}

prins(op, c) {
	extern instab[], printf;
	int insp[];

	insp = instab;
	while(*insp) {
		if (*insp++ == op) {
			if ((c = insp[c!=0])==0)
				goto err;
			printf("%s", c);
			return;
		} else
			insp = insp + 2;
	}
err:
	error("No match' for op %d", op);
}

collcon(p)
int p[]; {
	int p1[];

	if(*p==40 | *p==41)
		if(*(p1=p[4])==21)
			return(1);
	return(0);
}

isfloat(t, s)
int t[];
char s[][];
{
	extern opdope[];
	int rt;

	rt = **s - '0';
	if (rt==2 | rt==4) {
		(*s)++;
		return(rt>2?3:2);
	}
	if ((opdope[t[0]]&010)!=0)	/* relational */
		t = t[3];
	if ((rt=t[1])>=2 & rt<=3)
		return(rt);
	return(0);
}

nreg 4;
isn 10000;
namsiz 8;
line;
tmpfil;
nerror;
fltmod;

c11.c

jumpc(tree, lbl, cond)
int tree[]; {
	extern jump, cctab[], rcexpr, isn, label, branch, cbranch;
	int l1, l2;

	if (tree==0)
		return;
	switch(*tree) {

	/* & */
	case 47:
		if (cond) {
			cbranch(tree[3], l1=isn++, 0, 0);
			cbranch(tree[4], l1, 0, 0);
			jump(lbl);
			label(l1);
		} else {
			cbranch(tree[3], l1=isn++, 0, 0);
			cbranch(tree[4], l2=isn++, 1, 0);
			label(l1);
			jump(lbl);
			label(l2);
		}
		return;

	/* | */
	case 48:
		if (cond) {
			cbranch(tree[3], l1=isn++, 1, 0);
			cbranch(tree[4], l2=isn++, 0, 0);
			label(l1);
			jump(lbl);
			label(l2);
		} else {
			cbranch(tree[3], l1=isn++, 1, 0);
			cbranch(tree[4], l1, 1, 0);
			jump(lbl);
			label(l1);
		}
		return;

	/* ! */
	case 34:
		jumpc(tree[3], lbl, !cond);
		return;
	}
	rcexpr(tree, cctab, 0);
	branch(l1=isn++, *tree, cond);
	jump(lbl);
	label(l1);
	return;
}

cbranch(tree, lbl, cond, reg)
int tree[]; {
	extern branch, cctab[], rcexpr, isn, label;
	int l1;

	if (tree==0)
		return;
	switch(*tree) {

	/* & */
	case 47:
		if (cond) {
			cbranch(tree[3], l1=isn++, 0, reg);
			cbranch(tree[4], lbl, 1, reg);
			label(l1);
		} else {
			cbranch(tree[3], lbl, 0, reg);
			cbranch(tree[4], lbl, 0, reg);
		}
		return;

	/* | */
	case 48:
		if (cond) {
			cbranch(tree[3], lbl, 1, reg);
			cbranch(tree[4], lbl, 1, reg);
		} else {
			cbranch(tree[3], l1=isn++, 1, reg);
			cbranch(tree[4], lbl, 0, reg);
			label(l1);
		}
		return;

	/* ! */
	case 34:
		cbranch(tree[3], lbl, !cond, reg);
		return;
	}
	rcexpr(tree, cctab, reg);
	branch(lbl, *tree, !cond);
	return;
}


branch(lbl, op, c) {
	extern printf, prins, opdope[];

	if(op) {
		if((opdope[op]&04)==0)
			op = 61;
		prins(op,c);
	} else
		printf("br");
	printf("\tl%d\n", lbl);
}

jump(lab) {
	extern printf;

	printf("jmp\tl%d\n", lab);
}

label(l) {
	extern printf;

	printf("l%d:", l);
}


popstk(a) {
	extern printf;

	switch(a) {

	case 0:
		return;

	case 2:
		printf("tst	(sp)+\n");
		return;

	case 4:
		printf("cmp	(sp)+,(sp)+\n");
		return;
	}
	printf("add	$%o,sp\n", a);
}

length(t) {

	if (t<0)
		t =+ 020;
	if (t>=020)
		return(2);
	switch(t) {

	case 0:
		return(2);

	case 1:
		return(1);

	case 2:
		return(4);

	case 3:
		return(8);

	case 4:
		return(4);

	}
	return(1024);
}

rlength(c) {
	extern length;
	auto l;

	return((l=length(c))==1? 2: l);
}

printn(n,b) {
	extern putchar;
	auto a;

	if(a=n/b) /* assignment, not test for equality */
		printn(a, b); /* recursive */
	putchar(n%b + '0');
}

printf(fmt,x1,x2,x3,x4,x5,x6,x7,x8,x9)
char fmt[]; {
	extern printn, putchar, namsiz, ncpw;
	char s[];
	auto adx[], x, c, i[];

	adx = &x1; /* argument pointer */
loop:
	while((c = *fmt++) != '%') {
		if(c == '\0')
			return;
		putchar(c);
	}
	x = *adx++;
	switch (c = *fmt++) {

	case 'd': /* decimal */
	case 'o': /* octal */
		if(x < 0) {
			x = -x;
			if(x<0)  {	/* - infinity */
				if(c=='o')
					printf("100000");
				else
					printf("-32767");
				goto loop;
			}
			putchar('-');
		}
		printn(x, c=='o'?8:10);
		goto loop;

	case 's': /* string */
		s = x;
		while(c = *s++)
			putchar(c);
		goto loop;

	case 'p':
		s = x;
		putchar('_');
		c = namsiz;
		while(c--)
			if(*s)
				putchar(*s++);
		goto loop;
	}
	putchar('%');
	fmt--;
	adx--;
	goto loop;
}

error(s, p1, p2) {
	extern printf, line, fout, flush, putchar, nerror;
	int f;

	nerror++;
	flush();
	f = fout;
	fout = 1;
	printf("%d: ", line);
	printf(s, p1, p2);
	putchar('\n');
	fout = f;
}

c1t.s

/ C operator tables

.globl	_getwrd

.globl	getw
.globl	fopen
.globl	_tmpfil

.data
_getwrd: 1f
.text
1:
	tst	buf
	bne	1f
	mov	_tmpfil,r0
	jsr	r5,fopen; buf
	bes	botchp
1:
	jsr	r5,getw; buf
	bes	botchp
	rts	pc
botchp:
	mov	$1,r0
	sys	write; botch; ebotch-botch
	sys	exit
botch:
	<Temp file botch.\n>; ebotch:
.even
.bss
buf:	.=.+518.
.text
.globl	_opdope
.globl	_instab

_instab:.+2
	40.; 1f; 1f; .data; 1:<add\0>; .text
	70.; 1b; 1b
	41.; 2f; 2f; .data; 2:<sub\0>; .text
	71.; 2b; 2b
	30.; 3f; 1b; .data; 3:<inc\0>; .text
	31.; 4f; 2b; .data; 4:<dec\0>; .text
	32.; 3b; 1b
	33.; 4b; 2b

	45.; 2b; 5f; .data; 5:<ac\0>; .text
	46.; 6f; 7f; .data; 6:<mov\0>; 7:<(r4)\0>; .text
	75.; 2b; 5b
	76.; 6b; 7b
	43.; 7b; 1f; .data; 1:<divf\0>; .text
	44.; 5b; 0
	73.; 7b; 1b
	74.; 5b; 0

	60.; 0f; 1f; .data; 0:<beq\0>; 1:<bne\0>; .text
	61.; 1b; 0b
	62.; 2f; 5f; .data; 2:<ble\0>; 5:<bgt\0>; .text
	63.; 3f; 4f; .data; 3:<blt\0>; 4:<bge\0>; .text
	64.; 4b; 3b
	65.; 5b; 2b
	66.; 6f; 9f; .data; 6:<blos\0>; 9:<bhi\0>; .text
	67.; 7f; 8f; .data; 7:<blo\0>; 8:<bhis\0>; .text
	68.; 8b; 7b
	69.; 9b; 6b
	0
	.data
	.even
	.text

_opdope:.+2
	00000	/ EOF
	00000	/ ;
	00000	/ {
	00000	/ }
	36000	/ [
	02000	/ ]
	36000	/ (
	02000	/ )
	02000	/ :
	07001	/ ,
	00000	/ 10
	00000	/ 11
	00000	/ 12
	00000	/ 13
	00000	/ 14
	00000	/ 15
	00000	/ 16
	00000	/ 17
	00000	/ 18
	00000	/ 19
	00000	/ name
	00000	/ short constant
	00000	/ string
	00000	/ float
	00000	/ double
	00000	/ 25
	00000	/ 26
	00000	/ 27
	00000	/ 28
	00000	/ 29
	34002	/ ++pre
	34002	/ --pre
	34002	/ ++post
	34002	/ --post
	34020	/ !un
	34002	/ &un
	34020	/ *un
	34000	/ -un
	34020	/ ~un
	00000	/ 39
	30101	/ +
	30001	/ -
	32101	/ *
	32001	/ /
	32001	/ %
	26061	/ >>
	26061	/ <<
	20161	/ &
	16161	/ |
	16161	/ ^
	00000	/ 50
	00000	/ 51
	00000	/ 52
	00000	/ 53
	00000	/ 54
	00000	/ 55
	00000	/ 56
	00000	/ 57
	00000	/ 58
	00000	/ 59
	22105	/ ==
	22105	/ !=
	24105	/ <=
	24105	/ <
	24105	/ >=
	24105	/ >
	24105	/ <p
	24105	/ <=p
	24105	/ >p
	24105	/ >=p
	12013	/ =+
	12013	/ =-
	12013	/ =*
	12013	/ =/
	12013	/ =%
	12053	/ =>>
	12053	/ =<<
	12053	/ =&
	12053	/ =|
	12053	/ =^
	12013	/ =
	00000	/ 81
	00000	/ 82
	00000	/ 83
	00000	/ int -> float
	00000	/ int -> double
	00000	/ float -> int
	00000	/ float -> double
	00000	/ double -> int
	00000	/ double -> float
	14001	/ ?
	00000	/ 91
	00000	/ 92
	00000	/ 93
	00000	/ int -> float
	00000	/ int -> double
	00000	/ float -> double
	00000	/ int -> int[]
	00000	/ int -> float[]
	00000	/ int -> double[]
	36001	/ call
	36001	/ mcall

t.c

main() {
	extern a, b, c, i;
	float a, b;
	double c;
	int i;

	a = b;
	a = b*c;
	a = b*c/a;
	a = c;
	c = a;
	a = c*c+a;
	a = 1;
	a = a+1;
	i = a;
	i = c;
	a++;
	c++;
}