home *** CD-ROM | disk | FTP | other *** search
- /*---------------------------------------------------------------------*\
- ! !
- ! fc.c Compiler for FOOGOL IV -- version 4.2 Last change:1985-12-02 !
- ! Translates FOOGOL IV into VAX/UNIX assembler !
- ! !
- ! Written by Per Lindberg, QZ, Box 27322, 10254 Stockholm, Sweden. !
- ! !
- ! This software is in the public domain. The Hacker Ethic applies. !
- ! (A postcard from anyone who ports it would be appreciated.) !
- ! !
- \*---------------------------------the-mad-programmer-strikes-again----*/
-
- #define UNIX
-
- #ifdef SARG10 /* Sargasso C (under TOPS10/20) peculiarities */
- #strings low
- #define _UNIXCON
- #endif
-
- #include <stdio.h>
-
- #define isupper(c) ((c) >= 'A' && (c) <= 'Z')
- #define tolower(c) ((c) - 'A' + 'a')
-
- #define MAXTAB 25 /* Tweak these to your own liking */
- #define MAXTOKEN 80
-
- #define WHITESPACE 0 /* These could be turned into enum */
- #define NUMBER 1
- #define LETTER 2
- #define QUOTE 3
- #define SEMICOLON 4
- #define RANDOM 5
-
- FILE *inf, *outf;
-
- int labelcount = 0,
- linecount = 0,
- debug = 0;
-
- char token[MAXTOKEN],
- pending[MAXTOKEN],
- keytab[MAXTAB][MAXTOKEN],
- symtab[MAXTAB][MAXTOKEN],
- *usage =
- #ifdef SARG10
- "usage: '.run fc- [-debug] infile [outfile]'";
- #endif
- #ifdef UNIX
- "usage: 'fc [-debug] infile [outfile]'";
- #endif
-
- main(argc,argv) int argc; char *argv[]; {
- if (argc < 2) error(usage);
- if (*argv[1] == '-') { debug = 1; --argc; ++argv; }
- if (argc < 2) error(usage);
- openinfile(argv[1]);
- openoutfile(argv[argc == 2 ? 1 : 2]);
- init();
- if (!PROGRAM()) error("Syntax error");
- fclose(inf);
- fclose(outf);
- }
-
- char *defaultext(fname,ext,force) char *fname, *ext; int force; {
- static char result[255];
- char c, *point, *s = result;
- strcpy(result,fname);
- while (*s) ++s;
- point = s;
- while (c = *s, s > result && c != '.') --s;
- if (c == '.') { /* some extention exists */
- point = s;
- if (!force) return result; /* don't worry about what it is */
- }
- strcpy(point,ext); /* put default extention after point */
- return result;
- }
-
- openinfile(fname) char *fname; {
- char *defaultext();
- d("openinfile",defaultext(fname,".foo",0),"");
- if ((inf = fopen(defaultext(fname,".foo",0),"r")) == NULL)
- error2("Can't open infile", defaultext(fname,".foo",0));
- }
-
- openoutfile(fname) char *fname; {
- char *defaultext();
- d("openoutfile",defaultext(fname,".s",1),"");
- if ((outf = fopen(defaultext(fname,".s",1),"w")) == NULL)
- error2("Can't open outfile", defaultext(fname,".s",1));
- }
-
- init() {
- int i;
- d("init","","");
- get2();
- gettoken();
- for (i = 0; i < MAXTAB; i++) keytab[i][0] = '\0';
- }
-
- error(msg) char *msg; {
- printf("\n\nFoo: %s", msg);
- if (linecount) printf(" at line %d",linecount + 1);
- printf("\n");
- exit(1);
- }
-
- error2(s1,s2) char *s1,*s2; {
- static char msg[80];
- sprintf(msg,"%s\"%s\"",s1,s2);
- error(msg);
- }
-
- lowcase(s) char *s; {
- char c;
- for (c = *s; c = *s; ++s) if (isupper(c)) *s = tolower(c);
- }
-
- /* Basic I/O functions */
-
- int out(line) char *line; {
- char c, symb[MAXTOKEN], *subst(), *s = symb;
- int printmode = 1, chmode = 1;
- while(c = *line++) {
- if (c == ' ') { if (chmode) putc('\t',outf);
- chmode = 0;
- } else {
- chmode = 1;
- if (c != 39) { if (printmode) putc(c,outf);
- else *s++ = c;
- } else if (!printmode) {
- *s = '\0';
- if (*symb) fprintf(outf,"%s",subst(symb));
- printmode = 1;
- } else {
- printmode = 0;
- s = symb;
- }
- }
- }
- putc('\n',outf);
- return 1;
- }
-
- gettoken() {
- strcpy(token,pending); get2();
- if (!strcmp("/",token) && !strcmp("*",pending)) {
- d("comment:",token,pending);
- while (strcmp("*",token) || strcmp("/",pending)) {
- strcpy(token,pending); get2();
- d(" ",token,"");
- }
- strcpy(token,pending); get2();
- strcpy(token,pending); get2();
- }
- d("gettoken returning",token,pending);
- }
-
- get2() {
- int c0, c, typ, count = 1;
- char *p = pending;
- while((typ=type(c0=getc(inf))) == WHITESPACE) if (c0 == '\n') ++linecount;
- if (c0 != EOF) *p++ = c0;
- if (typ == QUOTE) {
- while ((c = getc(inf)) != EOF && type(c) != QUOTE) {
- if (++count == MAXTOKEN) error("String too long");
- *p++ = c;
- }
- *p++ = '"';
- }
- else {
- while ((type(c=getc(inf)) == typ
- || typ == LETTER && type(c) == NUMBER)
- && typ != RANDOM
- && c != EOF) {
- *p++ = c;
- typ = type(c);
- if (++count == MAXTOKEN) error("Too long input token");
- }
- ungetc(c,inf);
- }
- *p = '\0';
- }
-
- int type(c) int c; {
- if (c == EOF) return -1;
- if (c >= '0' && c <= '9') return(NUMBER);
- if (c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z') return(LETTER);
- if (c == ' ' || c == '\t' || c == '\n') return(WHITESPACE); /* */
- if (c == '"') return (QUOTE);
- if (c == ';') return (SEMICOLON);
- return(RANDOM);
- }
-
- /* Basic input matching functions */
-
- int match(s) char *s; {
- d("match",token,s);
- lowcase(token);
- if (strcmp(s,token)) return 0;
- gettoken(); return 1;
- }
-
- int id(name) char *name; {
- int t;
- char c, *p = token;
- d("id",token,name);
- if (type(*p++) != LETTER) return 0;
- while (c = *p++) {
- t = type(c);
- if (t != NUMBER && t != LETTER) return(0);
- }
- lowcase(token);
- enter(name,token);
- gettoken();
- return(1);
- }
-
- int number(name) char *name; {
- char c, *p = token;
- d("number",token,name);
- while (c = *p++) if (type(c) != NUMBER) return(0);
- enter(name,token);
- gettoken();
- return(1);
- }
-
- int string(name) char *name; {
- d("string",token,name);
- if (*token != '"') return 0;
- enter(name,token);
- gettoken();
- return 1;
- }
-
- label(name) char *name; {
- char result[6];
- d("label ",name,"");
- sprintf(result,"L%d",labelcount++);
- enter(name,result);
- }
-
- /* Internal symbol table */
-
- enter(key,val) char *key, *val; {
- int i;
- d("enter ",val,key);
- for (i = 0; i < MAXTAB; i++) {
- if (keytab[i][0] == '\0') {
- strcpy(keytab[i],key);
- strcpy(symtab[i],val);
- return;
- }
- }
- error2("INTERNAL SYMTAB ENTER ERROR, can't enter ", val);
- }
-
- int lookup(key) char *key; {
- int i;
- for (i = MAXTAB-1; i >= 0 ; i--) {
- if (!strcmp(key,keytab[i])) {
- d("lookup ",symtab[i],key);
- return i;
- }
- }
- error2("INTERNAL SYMTAB LOOKUP ERROR, can't find ", key);
- }
-
- char *subst(key) char *key; {
- return symtab[lookup(key)];
- }
-
- remove(key) char *key; {
- keytab[lookup(key)][0] = '\0';
- }
-
- /* Syntax definition. This is the neat part! */
-
- int PROGRAM() { d("PROGRAM",token,pending);
- if (!match("begin")) return 0; out(" .text # # begin");
- out(" .align 1");
- out(" .globl _main");
- out("_main:");
- out(" .word 0");
- if (!OPT_DECLARATION()) return 0;
- if (!STATEMENT()) return 0;
- while (match(";"))
- if (!STATEMENT()) return 0;
- if (!match("end")) return 0; out(" ret # # end");
- return 1;
- }
-
- int OPT_DECLARATION() { d("OPT_DECLARATION",token,pending);
- if (DECLARATION()
- && !match(";")) return 0;
- return 1;
- }
-
- int DECLARATION() { d("DECLARATION",token,pending);
- if (!match("integer")) return 0; out(" .data 1 # integer");
- if (!ID_SEQUENCE()) return 0; out(" .text");
- return 1;
- }
-
- int ID_SEQUENCE() { d("ID_SEQUENCE",token,pending);
- if (!IDENTIFIER()) return 0;
- while (match(","))
- if (!IDENTIFIER()) return 0;
- return 1;
- }
-
- int IDENTIFIER() { d("IDENTIFIER",token,pending);
- if (!id("X")) return 0; out("'X': .long 0");
- remove("X");
- return 1;
- }
-
- int STATEMENT() { d("STATEMENT",token,pending);
- return
- IO_STATEMENT()
- ||
- WHILE_STATEMENT()
- ||
- COND_STATEMENT()
- ||
- BLOCK()
- || /* the order is important here */
- ASSIGN_STATEMENT();
- }
-
- int BLOCK() { d("BLOCK",token,pending);
- if (!match("begin")) return 0; out(" # # # begin");
- if (DECL_OR_ST())
- while(match(";"))
- if (!STATEMENT()) return 0;
- if (!match("end")) return 0; out(" # # # end");
- return 1;
- }
-
- int DECL_OR_ST() { d("DECL_OR_ST",token,pending);
- return
- DECLARATION()
- ||
- STATEMENT();
- }
-
- int IO_STATEMENT() { d("IO_STATEMENT",token,pending);
- return
- PRINTS_STATEMENT()
- ||
- PRINTN_STATEMENT()
- ||
- PRINT_STATEMENT();
- }
-
- int PRINTS_STATEMENT() { d("PRINTS_STATEMENT",token,pending);
- if (!match("prints")) return 0;
- if (!match("(")) return 0;
- if (!string("S")) return 0; label("Ls");
- out(" .data 1 # prints");
- out("'Ls': .asciz 'S'");
- out(" .text");
- out(" pushal 'Ls'");
- out(" calls $1,_PRS");
- remove("S"); remove("Ls");
- if (!match(")")) return 0;
- return 1;
- }
-
- int PRINTN_STATEMENT() { d("PRINTN_STATEMENT",token,pending);
- if (!match("printn")) return 0;
- if (!match("(")) return 0;
- if (!EXPRESSION()) return 0; out(" pushl r0 # printn");
- out(" calls $1,_PRN");
- if (!match(")")) return 0;
- return 1;
- }
-
- int PRINT_STATEMENT() { d("PRINT_STATEMENT",token,pending);
- if (!match("print")) return 0; out(" calls $0,_PR # print");
- return 1;
- }
-
- int COND_STATEMENT() { d("COND_STATEMENT",token,pending);
- if (!match("if")) return 0; label("Lt"); label("Le"); label("Lq");
- if (!EXPRESSION()) return 0; out(" tstl r0 # if");
- if (!match("then")) return 0; out(" bneq 'Lq' # then");
- out(" jmp 'Le'");
- out("'Lq':");
- if (!STATEMENT()) return 0; out(" jmp 'Lt'");
- out("'Le': # # # else");
- if (match("else"))
- if (!STATEMENT()) return 0; out("'Lt': # # # endif");
- remove("Lt");remove("Le");remove("Lq");
- return 1;
- }
-
- int WHILE_STATEMENT() { d("WHILE_STATEMENT",token,pending);
- if (!match("while")) return 0; label("Lw"); label("Lx"); label("Lv");
- out("'Lw': # # # while");
- if (!EXPRESSION()) return 0; out(" tstl r0");
- if (!match("do")) return 0; out(" bneq 'Lv'");
- out(" jmp 'Lx'");
- out("'Lv': # # # do");
- if(!STATEMENT()) return 0; out(" jmp 'Lw'");
- out("'Lx': # # # endwhile");
- remove("Lw");remove("Lx");remove("Lv");
- return 1;
- }
-
- int ASSIGN_STATEMENT() { d("ASSIGN_STATEMENT",token,pending);
- if (!id("Var")) return 0;
- if (!match(":")) return 0;
- if (!match("=")) return 0;
- if (!EXPRESSION()) return 0; out(" movl r0,'Var' # 'Var':=");
- remove("Var");
- return 1;
- }
-
- int EXPRESSION() { d("EXPRESSION",token,pending);
- if (!EXPR1()) return 0;
- if (!OPT_RHS()) return 0;
- return 1;
- }
-
- int OPT_RHS() { d("OPT_RHS",token,pending);
- return
- RHS_EQ()
- ||
- RHS_NEQ()
- ||
- 1;
- }
-
- int RHS_EQ() { d("RHS_EQ",token,pending);
- if (!match("=")) return 0; label("L="); label("Ly");
- out(" pushl r0 # =");
- if (!EXPR1()) return 0; out(" cmpl (sp)+,r0");
- out(" beql 'L='");
- out(" movl $0,r0");
- out(" jmp 'Ly'");
- out("'L=': movl $1,r0");
- out("'Ly':");
- remove("L="); remove("Ly");
- return 1;
- }
-
- int RHS_NEQ() { d("RHS_NEQ",token,pending);
- if (!match("#")) return 0; label("L#"); label("Lz");
- out(" pushl r0 # <>");
- if (!EXPR1()) return 0; out(" cmpl (sp)+,r0");
- out(" beql 'L#'");
- out(" movl $1,r0");
- out(" jmp 'Lz'");
- out("'L#': movl $0,r0");
- out("'Lz':");
- remove("L#"); remove("Lz");
- return 1;
- }
-
- int SIGNED_TERM() { d("SIGNED_TERM",token,pending);
- return
- PLUS_TERM()
- ||
- MINUS_TERM();
- }
-
- int PLUS_TERM() { d("PLUS_TERM",token,pending);
- if (!match("+")) return 0; out(" pushl r0 # +term");
- if (!TERM()) return 0; out(" addl2 (sp)+,r0");
- return 1;
- }
-
- int MINUS_TERM() { d("MINUS_TERM",token,pending);
- if (!match("-")) return 0; out(" pushl r0 # -term");
- if (!TERM()) return 0; out(" subl3 r0,(sp)+,r0");
- return 1;
- }
-
- int TERM() { d("TERM",token,pending);
- if (!PRIMARY()) return 0;
- while (match("*")) { out(" pushl r0 # *");
- if (!PRIMARY()) return 0; out(" mull2 (sp)+,r0");
- }
- return 1;
- }
-
- int PRIMARY() { d("PRIMARY",token,pending);
- if (id("Z")) { out(" movl 'Z',r0");
- remove("Z");
- return 1;
- }
- if (number("Z")) { out(" movl $'Z',r0");
- remove("Z");
- return 1;
- }
- if (match("(")) {
- if (!EXPRESSION()) return 0;
- if (!match(")")) return 0;
- return 1;
- }
- return 0;
- }
-
- int EXPR1() { d("EXPR1",token,pending);
- if (!TERM()) return 0;
- while(SIGNED_TERM());
- return 1;
- }
-
- /* And finally, the debug function... */
-
- int d(s1,s2,s3) char *s1,*s2,*s3; {
- if (debug) {
- printf("%s",s1);
- if (*s2) printf(" \"%s\"",s2);
- if (*s3) printf(" \"%s\"",s3);
- putchar('\n');
- }
- return 1;
- }
-