├── README.md └── tinyc.c /README.md: -------------------------------------------------------------------------------- 1 | # MarcFeeleyTinyc 2 | A file I found that Marc Feeley does not have a repo for on github 3 | -------------------------------------------------------------------------------- /tinyc.c: -------------------------------------------------------------------------------- 1 | /* file: "tinyc.c" */ 2 | 3 | /* Copyright (C) 2001 by Marc Feeley, All Rights Reserved. */ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | /* 10 | * This is a compiler for the Tiny-C language. Tiny-C is a 11 | * considerably stripped down version of C and it is meant as a 12 | * pedagogical tool for learning about compilers. The integer global 13 | * variables "a" to "z" are predefined and initialized to zero, and it 14 | * is not possible to declare new variables. The compiler reads the 15 | * program from standard input and prints out the value of the 16 | * variables that are not zero. The grammar of Tiny-C in EBNF is: 17 | * 18 | * ::= 19 | * ::= "if" | 20 | * "if" "else" | 21 | * "while" | 22 | * "do" "while" ";" | 23 | * "{" { } "}" | 24 | * ";" | 25 | * ";" 26 | * ::= "(" ")" 27 | * ::= | "=" 28 | * ::= | "<" 29 | * ::= | "+" | "-" 30 | * ::= [ "-" ] ( | | ) 31 | * ::= "a" | "b" | "c" | "d" | ... | "z" 32 | * ::= <0..2147483647> 33 | * 34 | * Here are a few invocations of the compiler: 35 | * 36 | * % echo "a=b=c=2<3;" | ./a.out 37 | * a = 1 38 | * b = 1 39 | * c = 1 40 | * % echo "{ i=1; while (i<100) i=i+1; }" | ./a.out 41 | * i = 100 42 | * % echo "{ i=125; j=100; while (i-j) if (i= '0' && ch <= '9') 95 | { int_val = int_val*10 + (ch - '0'); next_ch(); } 96 | if (int_val < 0) syntax_error(); 97 | sym = UINT; 98 | } 99 | else if (ch >= 'a' && ch <= 'z') 100 | { int i = 0; /* missing overflow check */ 101 | while ((ch >= 'a' && ch <= 'z') || ch == '_') 102 | { id_name[i++] = ch; next_ch(); } 103 | id_name[i] = '\0'; 104 | sym = 0; 105 | while (words[sym] != NULL && strcmp(words[sym], id_name) != 0) 106 | sym++; 107 | if (words[sym] == NULL) 108 | if (id_name[1] == '\0') sym = ID; else syntax_error(); 109 | } 110 | else 111 | syntax_error(); 112 | } 113 | } 114 | 115 | /*---------------------------------------------------------------------------*/ 116 | 117 | /***********/ 118 | /* Parser. */ 119 | /***********/ 120 | 121 | enum { VAR, CST, ADD, SUB, LT, SET, 122 | IF1, IF2, WHILE, DO, EMPTY, SEQ, EXPR, PROG }; 123 | 124 | struct node { int kind; struct node *o1, *o2, *o3; int val; }; 125 | typedef struct node node; 126 | 127 | node *new_node(int k) 128 | { node *x = (node*)malloc(sizeof(node)); x->kind = k; return x; } 129 | 130 | node *paren_expr(); /* forward declaration */ 131 | 132 | node *term() /* ::= [ "-" ] ( | | ) */ 133 | { node *x; 134 | if (sym == MINUS) { x=new_node(SUB); x->o1=new_node(CST); x->o1->val=0; 135 | next_sym(); x->o2=term(); } 136 | else if (sym == ID) { x=new_node(VAR); x->val=id_name[0]-'a'; next_sym(); } 137 | else if (sym == UINT) { x=new_node(CST); x->val=int_val; next_sym(); } 138 | else x = paren_expr(); 139 | return x; 140 | } 141 | 142 | node *sum() /* ::= | "+" | "-" */ 143 | { node *t, *x = term(); 144 | while (sym == PLUS || sym == MINUS) 145 | { t=x; x=new_node(sym==PLUS?ADD:SUB); next_sym(); x->o1=t; x->o2=term(); } 146 | return x; 147 | } 148 | 149 | node *test() /* ::= | "<" */ 150 | { node *t, *x = sum(); 151 | if (sym == LESS) 152 | { t=x; x=new_node(LT); next_sym(); x->o1=t; x->o2=sum(); } 153 | return x; 154 | } 155 | 156 | node *expr() /* ::= | "=" */ 157 | { node *t, *x; 158 | if (sym != ID) return test(); 159 | x = test(); 160 | if (x->kind == VAR && sym == EQUAL) 161 | { t=x; x=new_node(SET); next_sym(); x->o1=t; x->o2=expr(); } 162 | return x; 163 | } 164 | 165 | node *paren_expr() /* ::= "(" ")" */ 166 | { node *x; 167 | if (sym == LPAR) next_sym(); else syntax_error(); 168 | x = expr(); 169 | if (sym == RPAR) next_sym(); else syntax_error(); 170 | return x; 171 | } 172 | 173 | node *statement() 174 | { node *t, *x; 175 | if (sym == IF_SYM) /* "if" */ 176 | { x = new_node(IF1); 177 | next_sym(); 178 | x->o1 = paren_expr(); 179 | x->o2 = statement(); 180 | if (sym == ELSE_SYM) /* ... "else" */ 181 | { x->kind = IF2; 182 | next_sym(); 183 | x->o3 = statement(); 184 | } 185 | } 186 | else if (sym == WHILE_SYM) /* "while" */ 187 | { x = new_node(WHILE); 188 | next_sym(); 189 | x->o1 = paren_expr(); 190 | x->o2 = statement(); 191 | } 192 | else if (sym == DO_SYM) /* "do" "while" ";" */ 193 | { x = new_node(DO); 194 | next_sym(); 195 | x->o1 = statement(); 196 | if (sym == WHILE_SYM) next_sym(); else syntax_error(); 197 | x->o2 = paren_expr(); 198 | if (sym == SEMI) next_sym(); else syntax_error(); 199 | } 200 | else if (sym == SEMI) /* ";" */ 201 | { x = new_node(EMPTY); next_sym(); } 202 | else if (sym == LBRA) /* "{" { } "}" */ 203 | { x = new_node(EMPTY); 204 | next_sym(); 205 | while (sym != RBRA) 206 | { t=x; x=new_node(SEQ); x->o1=t; x->o2=statement(); } 207 | next_sym(); 208 | } 209 | else /* ";" */ 210 | { x = new_node(EXPR); 211 | x->o1 = expr(); 212 | if (sym == SEMI) next_sym(); else syntax_error(); 213 | } 214 | return x; 215 | } 216 | 217 | node *program() /* ::= */ 218 | { node *x = new_node(PROG); 219 | next_sym(); /* prime lexer */ 220 | x->o1 = statement(); if (sym != EOI) syntax_error(); 221 | return x; 222 | } 223 | 224 | /*---------------------------------------------------------------------------*/ 225 | 226 | /*******************/ 227 | /* Code generator. */ 228 | /*******************/ 229 | 230 | enum { IFETCH=-1, ISTORE=-2, IPUSH=-3, IPOP=-4, IADD=-5, 231 | ISUB=-6, ILT=-7, JZ=-8, JNZ=-9, JMP=-10, HALT=-11 }; 232 | const char *opName[] = { "IFETCH", "ISTORE", "IPUSH", "IPOP", "IADD", 233 | "ISUB", "ILT", "JZ", "JNZ", "JMP", "HALT" }; 234 | 235 | typedef signed char code; 236 | code object[1000], *here = object; /* Instruction memory */ 237 | 238 | void g(code c) { *here++ = c; } /* missing overflow check */ 239 | code *hole() { return here++; } 240 | void fix(code *src, code *dst) { *src = dst-src; } /* missing overflow check */ 241 | 242 | /***********************************************/ 243 | /* generate assembly language (IR) for backend */ 244 | /***********************************************/ 245 | 246 | void c(node *x) 247 | { code *p1, *p2; 248 | switch (x->kind) 249 | { case VAR : g(IFETCH); g(x->val); break; 250 | case CST : g(IPUSH); g(x->val); break; 251 | case ADD : c(x->o1); c(x->o2); g(IADD); break; 252 | case SUB : c(x->o1); c(x->o2); g(ISUB); break; 253 | case LT : c(x->o1); c(x->o2); g(ILT); break; 254 | case SET : c(x->o2); g(ISTORE); g(x->o1->val); break; 255 | case IF1 : c(x->o1); g(JZ); p1=hole(); c(x->o2); fix(p1,here); break; 256 | case IF2 : c(x->o1); g(JZ); p1=hole(); c(x->o2); g(JMP); p2=hole(); 257 | fix(p1,here); c(x->o3); fix(p2,here); break; 258 | case WHILE: p1=here; c(x->o1); g(JZ); p2=hole(); c(x->o2); 259 | g(JMP); fix(hole(),p1); fix(p2,here); break; 260 | case DO : p1=here; c(x->o1); c(x->o2); g(JNZ); fix(hole(),p1); break; 261 | case EMPTY: break; 262 | case SEQ : c(x->o1); c(x->o2); break; 263 | case EXPR : c(x->o1); g(IPOP); break; 264 | case PROG : c(x->o1); g(HALT); break; 265 | } 266 | } 267 | 268 | /*---------------------------------------------------------------------------*/ 269 | 270 | /* Virtual machine. */ 271 | 272 | /* Data memory */ 273 | int globals[26]; 274 | int stack[1000]; 275 | 276 | /*************************************/ 277 | /* execute assembled code (IR) on VM */ 278 | /*************************************/ 279 | 280 | void run() 281 | { 282 | int *sp = stack; 283 | code *pc = object; 284 | again: switch (*pc++) 285 | { case IFETCH: *sp++ = globals[*pc++]; goto again; 286 | case ISTORE: globals[*pc++] = sp[-1]; goto again; 287 | case IPUSH : *sp++ = *pc++; goto again; 288 | case IPOP : --sp; goto again; 289 | case IADD : sp[-2] = sp[-2] + sp[-1]; --sp; goto again; 290 | case ISUB : sp[-2] = sp[-2] - sp[-1]; --sp; goto again; 291 | case ILT : sp[-2] = sp[-2] < sp[-1]; --sp; goto again; 292 | case JMP : pc += *pc; goto again; 293 | case JZ : if (*--sp == 0) pc += *pc; else pc++; goto again; 294 | case JNZ : if (*--sp != 0) pc += *pc; else pc++; goto again; 295 | case HALT : break; 296 | } 297 | } 298 | 299 | /*---------------------------------------------------------------------------*/ 300 | 301 | /* Main program. */ 302 | 303 | int main() 304 | { int i; 305 | 306 | c(program()); 307 | 308 | printf("Intermediate Representation of program:\n"); 309 | for (code *pc = object; pc= HALT)) { 312 | printf("%s\n", opName[-*pc-1]) ; 313 | } 314 | else { 315 | printf("%d\n", *pc) ; 316 | } 317 | } 318 | printf("\n"); 319 | 320 | for (i=0; i<26; i++) 321 | globals[i] = 0; 322 | run(); 323 | for (i=0; i<26; i++) 324 | if (globals[i] != 0) 325 | printf("%c = %d\n", 'a'+i, globals[i]); 326 | 327 | return 0; 328 | } 329 | --------------------------------------------------------------------------------