1 /* #!/usr/local/bin/otcc */ 2 /* 3 * Sample OTCC C example. You can uncomment the first line and install 4 * otcc in /usr/local/bin to make otcc scripts ! 5 */ 6 7 /* Any preprocessor directive except #define are ignored. We put this 8 include so that a standard C compiler can compile this code too. */ 9 #include <stdio.h> 10 11 /* defines are handled, but macro arguments cannot be given. No 12 recursive defines are tolerated */ 13 #define DEFAULT_BASE 10 14 15 /* 16 * Only old style K&R prototypes are parsed. Only int arguments are 17 * allowed (implicit types). 18 * 19 * By benchmarking the execution time of this function (for example 20 * for fib(35)), you'll notice that OTCC is quite fast because it 21 * generates native i386 machine code. 22 */ 23 fib(n) 24 { 25 if (n <= 2) 26 return 1; 27 else 28 return fib(n-1) + fib(n-2); 29 } 30 31 /* Identifiers are parsed the same way as C: begins with letter or 32 '_', and then letters, '_' or digits */ 33 fact(n) 34 { 35 /* local variables can be declared. Only 'int' type is supported */ 36 int i, r; 37 r = 1; 38 /* 'while' and 'for' loops are supported */ 39 for(i=2;i<=n;i++) 40 r = r * i; 41 return r; 42 } 43 44 /* Well, we could use printf, but it would be too easy */ 45 print_num(n, b) 46 { 47 int tab, p, c; 48 /* Numbers can be entered in decimal, hexadecimal ('0x' prefix) and 49 octal ('0' prefix) */ 50 /* more complex programs use malloc */ 51 tab = malloc(0x100); 52 p = tab; 53 while (1) { 54 c = n % b; 55 /* Character constants can be used */ 56 if (c >= 10) 57 c = c + 'a' - 10; 58 else 59 c = c + '0'; 60 *(char *)p = c; 61 p++; 62 n = n / b; 63 /* 'break' is supported */ 64 if (n == 0) 65 break; 66 } 67 while (p != tab) { 68 p--; 69 printf("%c", *(char *)p); 70 } 71 free(tab); 72 } 73 74 /* 'main' takes standard 'argc' and 'argv' parameters */ 75 main(argc, argv) 76 { 77 /* no local name space is supported, but local variables ARE 78 supported. As long as you do not use a globally defined 79 variable name as local variable (which is a bad habbit), you 80 won't have any problem */ 81 int s, n, f, base; 82 83 /* && and || operator have the same semantics as C (left to right 84 evaluation and early exit) */ 85 if (argc != 2 && argc != 3) { 86 /* '*' operator is supported with explicit casting to 'int *', 87 'char *' or 'int (*)()' (function pointer). Of course, 'int' 88 are supposed to be used as pointers too. */ 89 s = *(int *)argv; 90 help(s); 91 return 1; 92 } 93 /* Any libc function can be used because OTCC uses dynamic linking */ 94 n = atoi(*(int *)(argv + 4)); 95 base = DEFAULT_BASE; 96 if (argc >= 3) { 97 base = atoi(*(int *)(argv + 8)); 98 if (base < 2 || base > 36) { 99 /* external variables can be used too (here: 'stderr') */ 100 fprintf(stderr, "Invalid base\n"); 101 return 1; 102 } 103 } 104 printf("fib(%d) = ", n); 105 print_num(fib(n), base); 106 printf("\n"); 107 108 printf("fact(%d) = ", n); 109 if (n > 12) { 110 printf("Overflow"); 111 } else { 112 /* why not using a function pointer ? */ 113 f = &fact; 114 print_num((*(int (*)())f)(n), base); 115 } 116 printf("\n"); 117 return 0; 118 } 119 120 /* functions can be used before being defined */ 121 help(name) 122 { 123 printf("usage: %s n [base]\n", name); 124 printf("Compute fib(n) and fact(n) and output the result in base 'base'\n"); 125 } 126 127