/ c4.c
c4.c
  1  // c4.c - C in four functions
  2  
  3  // char, int, and pointer types
  4  // if, while, return, and expression statements
  5  // just enough features to allow self-compilation and a bit more
  6  
  7  // Written by Robert Swierczek
  8  
  9  #include <stdio.h>
 10  #include <stdlib.h>
 11  #include <memory.h>
 12  #include <unistd.h>
 13  #include <fcntl.h>
 14  
 15  char *p, *lp, // current position in source code
 16       *data;   // data/bss pointer
 17  
 18  int *e, *le,  // current position in emitted code
 19      *id,      // currently parsed identifier
 20      *sym,     // symbol table (simple list of identifiers)
 21      tk,       // current token
 22      ival,     // current token value
 23      ty,       // current expression type
 24      loc,      // local variable offset
 25      line,     // current line number
 26      src,      // print source and assembly flag
 27      debug;    // print executed instructions
 28  
 29  // tokens and classes (operators last and in precedence order)
 30  enum {
 31    Num = 128, Fun, Sys, Glo, Loc, Id,
 32    Char, Else, Enum, If, Int, Return, Sizeof, While,
 33    Assign, Cond, Lor, Lan, Or, Xor, And, Eq, Ne, Lt, Gt, Le, Ge, Shl, Shr, Add, Sub, Mul, Div, Mod, Inc, Dec, Brak
 34  };
 35  
 36  // opcodes
 37  enum { LEA ,IMM ,JMP ,JSR ,BZ  ,BNZ ,ENT ,ADJ ,LEV ,LI  ,LC  ,SI  ,SC  ,PSH ,
 38         OR  ,XOR ,AND ,EQ  ,NE  ,LT  ,GT  ,LE  ,GE  ,SHL ,SHR ,ADD ,SUB ,MUL ,DIV ,MOD ,
 39         OPEN,READ,CLOS,PRTF,MALC,FREE,MSET,MCMP,EXIT };
 40  
 41  // types
 42  enum { CHAR, INT, PTR };
 43  
 44  // identifier offsets (since we can't create an ident struct)
 45  enum { Tk, Hash, Name, Class, Type, Val, HClass, HType, HVal, Idsz };
 46  
 47  void next()
 48  {
 49    char *pp;
 50  
 51    while (tk = *p) {
 52      ++p;
 53      if (tk == '\n') {
 54        if (src) {
 55          printf("%d: %.*s", line, p - lp, lp);
 56          lp = p;
 57          while (le < e) {
 58            printf("%8.4s", &"LEA ,IMM ,JMP ,JSR ,BZ  ,BNZ ,ENT ,ADJ ,LEV ,LI  ,LC  ,SI  ,SC  ,PSH ,"
 59                             "OR  ,XOR ,AND ,EQ  ,NE  ,LT  ,GT  ,LE  ,GE  ,SHL ,SHR ,ADD ,SUB ,MUL ,DIV ,MOD ,"
 60                             "OPEN,READ,CLOS,PRTF,MALC,FREE,MSET,MCMP,EXIT,"[*++le * 5]);
 61            if (*le <= ADJ) printf(" %d\n", *++le); else printf("\n");
 62          }
 63        }
 64        ++line;
 65      }
 66      else if (tk == '#') {
 67        while (*p != 0 && *p != '\n') ++p;
 68      }
 69      else if ((tk >= 'a' && tk <= 'z') || (tk >= 'A' && tk <= 'Z') || tk == '_') {
 70        pp = p - 1;
 71        while ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') || (*p >= '0' && *p <= '9') || *p == '_')
 72          tk = tk * 147 + *p++;
 73        tk = (tk << 6) + (p - pp);
 74        id = sym;
 75        while (id[Tk]) {
 76          if (tk == id[Hash] && !memcmp((char *)id[Name], pp, p - pp)) { tk = id[Tk]; return; }
 77          id = id + Idsz;
 78        }
 79        id[Name] = (int)pp;
 80        id[Hash] = tk;
 81        tk = id[Tk] = Id;
 82        return;
 83      }
 84      else if (tk >= '0' && tk <= '9') {
 85        if (ival = tk - '0') { while (*p >= '0' && *p <= '9') ival = ival * 10 + *p++ - '0'; }
 86        else if (*p == 'x' || *p == 'X') {
 87          while ((tk = *++p) && ((tk >= '0' && tk <= '9') || (tk >= 'a' && tk <= 'f') || (tk >= 'A' && tk <= 'F')))
 88            ival = ival * 16 + (tk & 15) + (tk >= 'A' ? 9 : 0);
 89        }
 90        else { while (*p >= '0' && *p <= '7') ival = ival * 8 + *p++ - '0'; }
 91        tk = Num;
 92        return;
 93      }
 94      else if (tk == '/') {
 95        if (*p == '/') {
 96          ++p;
 97          while (*p != 0 && *p != '\n') ++p;
 98        }
 99        else {
100          tk = Div;
101          return;
102        }
103      }
104      else if (tk == '\'' || tk == '"') {
105        pp = data;
106        while (*p != 0 && *p != tk) {
107          if ((ival = *p++) == '\\') {
108            if ((ival = *p++) == 'n') ival = '\n';
109          }
110          if (tk == '"') *data++ = ival;
111        }
112        ++p;
113        if (tk == '"') ival = (int)pp; else tk = Num;
114        return;
115      }
116      else if (tk == '=') { if (*p == '=') { ++p; tk = Eq; } else tk = Assign; return; }
117      else if (tk == '+') { if (*p == '+') { ++p; tk = Inc; } else tk = Add; return; }
118      else if (tk == '-') { if (*p == '-') { ++p; tk = Dec; } else tk = Sub; return; }
119      else if (tk == '!') { if (*p == '=') { ++p; tk = Ne; } return; }
120      else if (tk == '<') { if (*p == '=') { ++p; tk = Le; } else if (*p == '<') { ++p; tk = Shl; } else tk = Lt; return; }
121      else if (tk == '>') { if (*p == '=') { ++p; tk = Ge; } else if (*p == '>') { ++p; tk = Shr; } else tk = Gt; return; }
122      else if (tk == '|') { if (*p == '|') { ++p; tk = Lor; } else tk = Or; return; }
123      else if (tk == '&') { if (*p == '&') { ++p; tk = Lan; } else tk = And; return; }
124      else if (tk == '^') { tk = Xor; return; }
125      else if (tk == '%') { tk = Mod; return; }
126      else if (tk == '*') { tk = Mul; return; }
127      else if (tk == '[') { tk = Brak; return; }
128      else if (tk == '?') { tk = Cond; return; }
129      else if (tk == '~' || tk == ';' || tk == '{' || tk == '}' || tk == '(' || tk == ')' || tk == ']' || tk == ',' || tk == ':') return;
130    }
131  }
132  
133  void expr(int lev)
134  {
135    int t, *d;
136  
137    if (!tk) { printf("%d: unexpected eof in expression\n", line); exit(-1); }
138    else if (tk == Num) { *++e = IMM; *++e = ival; next(); ty = INT; }
139    else if (tk == '"') {
140      *++e = IMM; *++e = ival; next();
141      while (tk == '"') next();
142      data = (char *)((int)data + sizeof(int) & -sizeof(int)); ty = PTR;
143    }
144    else if (tk == Sizeof) {
145      next(); if (tk == '(') next(); else { printf("%d: open paren expected in sizeof\n", line); exit(-1); }
146      ty = INT; if (tk == Int) next(); else if (tk == Char) { next(); ty = CHAR; }
147      while (tk == Mul) { next(); ty = ty + PTR; }
148      if (tk == ')') next(); else { printf("%d: close paren expected in sizeof\n", line); exit(-1); }
149      *++e = IMM; *++e = (ty == CHAR) ? sizeof(char) : sizeof(int);
150      ty = INT;
151    }
152    else if (tk == Id) {
153      d = id; next();
154      if (tk == '(') {
155        next();
156        t = 0;
157        while (tk != ')') { expr(Assign); *++e = PSH; ++t; if (tk == ',') next(); }
158        next();
159        if (d[Class] == Sys) *++e = d[Val];
160        else if (d[Class] == Fun) { *++e = JSR; *++e = d[Val]; }
161        else { printf("%d: bad function call\n", line); exit(-1); }
162        if (t) { *++e = ADJ; *++e = t; }
163        ty = d[Type];
164      }
165      else if (d[Class] == Num) { *++e = IMM; *++e = d[Val]; ty = INT; }
166      else {
167        if (d[Class] == Loc) { *++e = LEA; *++e = loc - d[Val]; }
168        else if (d[Class] == Glo) { *++e = IMM; *++e = d[Val]; }
169        else { printf("%d: undefined variable\n", line); exit(-1); }
170        *++e = ((ty = d[Type]) == CHAR) ? LC : LI;
171      }
172    }
173    else if (tk == '(') {
174      next();
175      if (tk == Int || tk == Char) {
176        t = (tk == Int) ? INT : CHAR; next();
177        while (tk == Mul) { next(); t = t + PTR; }
178        if (tk == ')') next(); else { printf("%d: bad cast\n", line); exit(-1); }
179        expr(Inc);
180        ty = t;
181      }
182      else {
183        expr(Assign);
184        if (tk == ')') next(); else { printf("%d: close paren expected\n", line); exit(-1); }
185      }
186    }
187    else if (tk == Mul) {
188      next(); expr(Inc);
189      if (ty > INT) ty = ty - PTR; else { printf("%d: bad dereference\n", line); exit(-1); }
190      *++e = (ty == CHAR) ? LC : LI;
191    }
192    else if (tk == And) {
193      next(); expr(Inc);
194      if (*e == LC || *e == LI) --e; else { printf("%d: bad address-of\n", line); exit(-1); }
195      ty = ty + PTR;
196    }
197    else if (tk == '!') { next(); expr(Inc); *++e = PSH; *++e = IMM; *++e = 0; *++e = EQ; ty = INT; }
198    else if (tk == '~') { next(); expr(Inc); *++e = PSH; *++e = IMM; *++e = -1; *++e = XOR; ty = INT; }
199    else if (tk == Add) { next(); expr(Inc); ty = INT; }
200    else if (tk == Sub) {
201      next(); *++e = IMM;
202      if (tk == Num) { *++e = -ival; next(); } else { *++e = -1; *++e = PSH; expr(Inc); *++e = MUL; }
203      ty = INT;
204    }
205    else if (tk == Inc || tk == Dec) {
206      t = tk; next(); expr(Inc);
207      if (*e == LC) { *e = PSH; *++e = LC; }
208      else if (*e == LI) { *e = PSH; *++e = LI; }
209      else { printf("%d: bad lvalue in pre-increment\n", line); exit(-1); }
210      *++e = PSH;
211      *++e = IMM; *++e = (ty > PTR) ? sizeof(int) : sizeof(char);
212      *++e = (t == Inc) ? ADD : SUB;
213      *++e = (ty == CHAR) ? SC : SI;
214    }
215    else { printf("%d: bad expression\n", line); exit(-1); }
216  
217    while (tk >= lev) { // "precedence climbing" or "Top Down Operator Precedence" method
218      t = ty;
219      if (tk == Assign) {
220        next();
221        if (*e == LC || *e == LI) *e = PSH; else { printf("%d: bad lvalue in assignment\n", line); exit(-1); }
222        expr(Assign); *++e = ((ty = t) == CHAR) ? SC : SI;
223      }
224      else if (tk == Cond) {
225        next();
226        *++e = BZ; d = ++e;
227        expr(Assign);
228        if (tk == ':') next(); else { printf("%d: conditional missing colon\n", line); exit(-1); }
229        *d = (int)(e + 3); *++e = JMP; d = ++e;
230        expr(Cond);
231        *d = (int)(e + 1);
232      }
233      else if (tk == Lor) { next(); *++e = BNZ; d = ++e; expr(Lan); *d = (int)(e + 1); ty = INT; }
234      else if (tk == Lan) { next(); *++e = BZ;  d = ++e; expr(Or);  *d = (int)(e + 1); ty = INT; }
235      else if (tk == Or)  { next(); *++e = PSH; expr(Xor); *++e = OR;  ty = INT; }
236      else if (tk == Xor) { next(); *++e = PSH; expr(And); *++e = XOR; ty = INT; }
237      else if (tk == And) { next(); *++e = PSH; expr(Eq);  *++e = AND; ty = INT; }
238      else if (tk == Eq)  { next(); *++e = PSH; expr(Lt);  *++e = EQ;  ty = INT; }
239      else if (tk == Ne)  { next(); *++e = PSH; expr(Lt);  *++e = NE;  ty = INT; }
240      else if (tk == Lt)  { next(); *++e = PSH; expr(Shl); *++e = LT;  ty = INT; }
241      else if (tk == Gt)  { next(); *++e = PSH; expr(Shl); *++e = GT;  ty = INT; }
242      else if (tk == Le)  { next(); *++e = PSH; expr(Shl); *++e = LE;  ty = INT; }
243      else if (tk == Ge)  { next(); *++e = PSH; expr(Shl); *++e = GE;  ty = INT; }
244      else if (tk == Shl) { next(); *++e = PSH; expr(Add); *++e = SHL; ty = INT; }
245      else if (tk == Shr) { next(); *++e = PSH; expr(Add); *++e = SHR; ty = INT; }
246      else if (tk == Add) {
247        next(); *++e = PSH; expr(Mul);
248        if ((ty = t) > PTR) { *++e = PSH; *++e = IMM; *++e = sizeof(int); *++e = MUL;  }
249        *++e = ADD;
250      }
251      else if (tk == Sub) {
252        next(); *++e = PSH; expr(Mul);
253        if (t > PTR && t == ty) { *++e = SUB; *++e = PSH; *++e = IMM; *++e = sizeof(int); *++e = DIV; ty = INT; }
254        else if ((ty = t) > PTR) { *++e = PSH; *++e = IMM; *++e = sizeof(int); *++e = MUL; *++e = SUB; }
255        else *++e = SUB;
256      }
257      else if (tk == Mul) { next(); *++e = PSH; expr(Inc); *++e = MUL; ty = INT; }
258      else if (tk == Div) { next(); *++e = PSH; expr(Inc); *++e = DIV; ty = INT; }
259      else if (tk == Mod) { next(); *++e = PSH; expr(Inc); *++e = MOD; ty = INT; }
260      else if (tk == Inc || tk == Dec) {
261        if (*e == LC) { *e = PSH; *++e = LC; }
262        else if (*e == LI) { *e = PSH; *++e = LI; }
263        else { printf("%d: bad lvalue in post-increment\n", line); exit(-1); }
264        *++e = PSH; *++e = IMM; *++e = (ty > PTR) ? sizeof(int) : sizeof(char);
265        *++e = (tk == Inc) ? ADD : SUB;
266        *++e = (ty == CHAR) ? SC : SI;
267        *++e = PSH; *++e = IMM; *++e = (ty > PTR) ? sizeof(int) : sizeof(char);
268        *++e = (tk == Inc) ? SUB : ADD;
269        next();
270      }
271      else if (tk == Brak) {
272        next(); *++e = PSH; expr(Assign);
273        if (tk == ']') next(); else { printf("%d: close bracket expected\n", line); exit(-1); }
274        if (t > PTR) { *++e = PSH; *++e = IMM; *++e = sizeof(int); *++e = MUL;  }
275        else if (t < PTR) { printf("%d: pointer type expected\n", line); exit(-1); }
276        *++e = ADD;
277        *++e = ((ty = t - PTR) == CHAR) ? LC : LI;
278      }
279      else { printf("%d: compiler error tk=%d\n", line, tk); exit(-1); }
280    }
281  }
282  
283  void stmt()
284  {
285    int *a, *b;
286  
287    if (tk == If) {
288      next();
289      if (tk == '(') next(); else { printf("%d: open paren expected\n", line); exit(-1); }
290      expr(Assign);
291      if (tk == ')') next(); else { printf("%d: close paren expected\n", line); exit(-1); }
292      *++e = BZ; b = ++e;
293      stmt();
294      if (tk == Else) {
295        *b = (int)(e + 3); *++e = JMP; b = ++e;
296        next();
297        stmt();
298      }
299      *b = (int)(e + 1);
300    }
301    else if (tk == While) {
302      next();
303      a = e + 1;
304      if (tk == '(') next(); else { printf("%d: open paren expected\n", line); exit(-1); }
305      expr(Assign);
306      if (tk == ')') next(); else { printf("%d: close paren expected\n", line); exit(-1); }
307      *++e = BZ; b = ++e;
308      stmt();
309      *++e = JMP; *++e = (int)a;
310      *b = (int)(e + 1);
311    }
312    else if (tk == Return) {
313      next();
314      if (tk != ';') expr(Assign);
315      *++e = LEV;
316      if (tk == ';') next(); else { printf("%d: semicolon expected\n", line); exit(-1); }
317    }
318    else if (tk == '{') {
319      next();
320      while (tk != '}') stmt();
321      next();
322    }
323    else if (tk == ';') {
324      next();
325    }
326    else {
327      expr(Assign);
328      if (tk == ';') next(); else { printf("%d: semicolon expected\n", line); exit(-1); }
329    }
330  }
331  
332  int main(int argc, char **argv)
333  {
334    int fd, bt, ty, poolsz, *idmain;
335    int *pc, *sp, *bp, a, cycle; // vm registers
336    int i, *t; // temps
337  
338    --argc; ++argv;
339    if (argc > 0 && **argv == '-' && (*argv)[1] == 's') { src = 1; --argc; ++argv; }
340    if (argc > 0 && **argv == '-' && (*argv)[1] == 'd') { debug = 1; --argc; ++argv; }
341    if (argc < 1) { printf("usage: c4 [-s] [-d] file ...\n"); return -1; }
342  
343    if ((fd = open(*argv, 0)) < 0) { printf("could not open(%s)\n", *argv); return -1; }
344  
345    poolsz = 256*1024; // arbitrary size
346    if (!(sym = malloc(poolsz))) { printf("could not malloc(%d) symbol area\n", poolsz); return -1; }
347    if (!(le = e = malloc(poolsz))) { printf("could not malloc(%d) text area\n", poolsz); return -1; }
348    if (!(data = malloc(poolsz))) { printf("could not malloc(%d) data area\n", poolsz); return -1; }
349    if (!(sp = malloc(poolsz))) { printf("could not malloc(%d) stack area\n", poolsz); return -1; }
350  
351    memset(sym,  0, poolsz);
352    memset(e,    0, poolsz);
353    memset(data, 0, poolsz);
354  
355    p = "char else enum if int return sizeof while "
356        "open read close printf malloc free memset memcmp exit void main";
357    i = Char; while (i <= While) { next(); id[Tk] = i++; } // add keywords to symbol table
358    i = OPEN; while (i <= EXIT) { next(); id[Class] = Sys; id[Type] = INT; id[Val] = i++; } // add library to symbol table
359    next(); id[Tk] = Char; // handle void type
360    next(); idmain = id; // keep track of main
361  
362    if (!(lp = p = malloc(poolsz))) { printf("could not malloc(%d) source area\n", poolsz); return -1; }
363    if ((i = read(fd, p, poolsz-1)) <= 0) { printf("read() returned %d\n", i); return -1; }
364    p[i] = 0;
365    close(fd);
366  
367    // parse declarations
368    line = 1;
369    next();
370    while (tk) {
371      bt = INT; // basetype
372      if (tk == Int) next();
373      else if (tk == Char) { next(); bt = CHAR; }
374      else if (tk == Enum) {
375        next();
376        if (tk != '{') next();
377        if (tk == '{') {
378          next();
379          i = 0;
380          while (tk != '}') {
381            if (tk != Id) { printf("%d: bad enum identifier %d\n", line, tk); return -1; }
382            next();
383            if (tk == Assign) {
384              next();
385              if (tk != Num) { printf("%d: bad enum initializer\n", line); return -1; }
386              i = ival;
387              next();
388            }
389            id[Class] = Num; id[Type] = INT; id[Val] = i++;
390            if (tk == ',') next();
391          }
392          next();
393        }
394      }
395      while (tk != ';' && tk != '}') {
396        ty = bt;
397        while (tk == Mul) { next(); ty = ty + PTR; }
398        if (tk != Id) { printf("%d: bad global declaration\n", line); return -1; }
399        if (id[Class]) { printf("%d: duplicate global definition\n", line); return -1; }
400        next();
401        id[Type] = ty;
402        if (tk == '(') { // function
403          id[Class] = Fun;
404          id[Val] = (int)(e + 1);
405          next(); i = 0;
406          while (tk != ')') {
407            ty = INT;
408            if (tk == Int) next();
409            else if (tk == Char) { next(); ty = CHAR; }
410            while (tk == Mul) { next(); ty = ty + PTR; }
411            if (tk != Id) { printf("%d: bad parameter declaration\n", line); return -1; }
412            if (id[Class] == Loc) { printf("%d: duplicate parameter definition\n", line); return -1; }
413            id[HClass] = id[Class]; id[Class] = Loc;
414            id[HType]  = id[Type];  id[Type] = ty;
415            id[HVal]   = id[Val];   id[Val] = i++;
416            next();
417            if (tk == ',') next();
418          }
419          next();
420          if (tk != '{') { printf("%d: bad function definition\n", line); return -1; }
421          loc = ++i;
422          next();
423          while (tk == Int || tk == Char) {
424            bt = (tk == Int) ? INT : CHAR;
425            next();
426            while (tk != ';') {
427              ty = bt;
428              while (tk == Mul) { next(); ty = ty + PTR; }
429              if (tk != Id) { printf("%d: bad local declaration\n", line); return -1; }
430              if (id[Class] == Loc) { printf("%d: duplicate local definition\n", line); return -1; }
431              id[HClass] = id[Class]; id[Class] = Loc;
432              id[HType]  = id[Type];  id[Type] = ty;
433              id[HVal]   = id[Val];   id[Val] = ++i;
434              next();
435              if (tk == ',') next();
436            }
437            next();
438          }
439          *++e = ENT; *++e = i - loc;
440          while (tk != '}') stmt();
441          *++e = LEV;
442          id = sym; // unwind symbol table locals
443          while (id[Tk]) {
444            if (id[Class] == Loc) {
445              id[Class] = id[HClass];
446              id[Type] = id[HType];
447              id[Val] = id[HVal];
448            }
449            id = id + Idsz;
450          }
451        }
452        else {
453          id[Class] = Glo;
454          id[Val] = (int)data;
455          data = data + sizeof(int);
456        }
457        if (tk == ',') next();
458      }
459      next();
460    }
461  
462    if (!(pc = (int *)idmain[Val])) { printf("main() not defined\n"); return -1; }
463    if (src) return 0;
464  
465    // setup stack
466    bp = sp = (int *)((int)sp + poolsz);
467    *--sp = EXIT; // call exit if main returns
468    *--sp = PSH; t = sp;
469    *--sp = argc;
470    *--sp = (int)argv;
471    *--sp = (int)t;
472  
473    // run...
474    cycle = 0;
475    while (1) {
476      i = *pc++; ++cycle;
477      if (debug) {
478        printf("%d> %.4s", cycle,
479          &"LEA ,IMM ,JMP ,JSR ,BZ  ,BNZ ,ENT ,ADJ ,LEV ,LI  ,LC  ,SI  ,SC  ,PSH ,"
480           "OR  ,XOR ,AND ,EQ  ,NE  ,LT  ,GT  ,LE  ,GE  ,SHL ,SHR ,ADD ,SUB ,MUL ,DIV ,MOD ,"
481           "OPEN,READ,CLOS,PRTF,MALC,FREE,MSET,MCMP,EXIT,"[i * 5]);
482        if (i <= ADJ) printf(" %d\n", *pc); else printf("\n");
483      }
484      if      (i == LEA) a = (int)(bp + *pc++);                             // load local address
485      else if (i == IMM) a = *pc++;                                         // load global address or immediate
486      else if (i == JMP) pc = (int *)*pc;                                   // jump
487      else if (i == JSR) { *--sp = (int)(pc + 1); pc = (int *)*pc; }        // jump to subroutine
488      else if (i == BZ)  pc = a ? pc + 1 : (int *)*pc;                      // branch if zero
489      else if (i == BNZ) pc = a ? (int *)*pc : pc + 1;                      // branch if not zero
490      else if (i == ENT) { *--sp = (int)bp; bp = sp; sp = sp - *pc++; }     // enter subroutine
491      else if (i == ADJ) sp = sp + *pc++;                                   // stack adjust
492      else if (i == LEV) { sp = bp; bp = (int *)*sp++; pc = (int *)*sp++; } // leave subroutine
493      else if (i == LI)  a = *(int *)a;                                     // load int
494      else if (i == LC)  a = *(char *)a;                                    // load char
495      else if (i == SI)  *(int *)*sp++ = a;                                 // store int
496      else if (i == SC)  a = *(char *)*sp++ = a;                            // store char
497      else if (i == PSH) *--sp = a;                                         // push
498  
499      else if (i == OR)  a = *sp++ |  a;
500      else if (i == XOR) a = *sp++ ^  a;
501      else if (i == AND) a = *sp++ &  a;
502      else if (i == EQ)  a = *sp++ == a;
503      else if (i == NE)  a = *sp++ != a;
504      else if (i == LT)  a = *sp++ <  a;
505      else if (i == GT)  a = *sp++ >  a;
506      else if (i == LE)  a = *sp++ <= a;
507      else if (i == GE)  a = *sp++ >= a;
508      else if (i == SHL) a = *sp++ << a;
509      else if (i == SHR) a = *sp++ >> a;
510      else if (i == ADD) a = *sp++ +  a;
511      else if (i == SUB) a = *sp++ -  a;
512      else if (i == MUL) a = *sp++ *  a;
513      else if (i == DIV) a = *sp++ /  a;
514      else if (i == MOD) a = *sp++ %  a;
515  
516      else if (i == OPEN) a = open((char *)sp[1], *sp);
517      else if (i == READ) a = read(sp[2], (char *)sp[1], *sp);
518      else if (i == CLOS) a = close(*sp);
519      else if (i == PRTF) { t = sp + pc[1]; a = printf((char *)t[-1], t[-2], t[-3], t[-4], t[-5], t[-6]); }
520      else if (i == MALC) a = (int)malloc(*sp);
521      else if (i == FREE) free((void *)*sp);
522      else if (i == MSET) a = (int)memset((char *)sp[2], sp[1], *sp);
523      else if (i == MCMP) a = memcmp((char *)sp[2], (char *)sp[1], *sp);
524      else if (i == EXIT) { printf("exit(%d) cycle = %d\n", *sp, cycle); return *sp; }
525      else { printf("unknown instruction = %d! cycle = %d\n", i, cycle); return -1; }
526    }
527  }