3 #define TEXT_SIZE 20000
5 #define SYM_TABLE_SIZE 10000
6 #define VAR_TABLE_SIZE 4096
8 /* vac: offset of variables
10 loc : local variable index
11 glo : global variable index
12 parm : parameter variable index
14 lsym: loop symbol stack
17 astk: arg position stack
19 int tok
, *vac
, *vat
, *lsym
, rsym
,
20 prog
, ind
, loc
, glo
, file
, vt
,
21 vc
, *macro_stack
, *macro_stack_ptr
;
22 char *idtable
, *idptr
, *idlast
;
24 /* The current value can be: */
25 #define VT_CONST 0x0002 /* constant in vc */
26 #define VT_VAR 0x0004 /* value is in eax */
27 #define VT_LOCAL 0x0008 /* offset on stack */
29 #define VT_LVAL 0x0010 /* const or var is an lvalue */
30 #define VT_CMP 0x0020 /* the value is stored in processor flags (in vc) */
31 #define VT_FORWARD 0x0040 /* value is forward reference (only used for functions) */
32 #define VT_JMP 0x0080 /* value is the consequence of jmp. bit 0 is set if inv */
34 #define VT_LVALN -17 /* ~VT_LVAL */
38 * VT_FUNC indicates a function. The return type is the stored type. A
39 * function pointer is stored as a 'char' pointer.
41 * If VT_PTRMASK is non nul, then it indicates the number of pointer
42 * iterations to reach the basic type.
46 * VT_BYTE indicate a char
49 * otherwise integer type is assumed.
52 #define VT_BYTE 0x00001 /* byte pointer. HARDCODED VALUE */
53 #define VT_PTRMASK 0x00f00 /* pointer mask */
54 #define VT_PTRINC 0x00100 /* pointer increment */
55 #define VT_FUNC 0x01000 /* function type */
56 #define VT_TYPE 0x01f01 /* type mask */
58 #define VT_TYPEN 0xffffe0fe /* ~VT_TYPE */
59 #define VT_FUNCN -4097
62 #define VT_DEFINE 0x02000 /* special value for #defined symbols */
72 #define TOK_RETURN 263
73 #define TOK_DEFINE 264
76 #define TOK_EQ 0x94 /* warning: depend on asm code */
77 #define TOK_NE 0x95 /* warning: depend on asm code */
78 #define TOK_LT 0x9c /* warning: depend on asm code */
79 #define TOK_GE 0x9d /* warning: depend on asm code */
80 #define TOK_LE 0x9e /* warning: depend on asm code */
81 #define TOK_GT 0x9f /* warning: depend on asm code */
87 #define TOK_MID 0xa3 /* inc/dec, to void constant */
90 #define TOK_SHL 0xe0 /* warning: depend on asm code */
91 #define TOK_SHR 0xf8 /* warning: depend on asm code */
96 printf("%d: %s\n", ftell(file
), msg
);
99 void warning(char *msg
)
101 printf("%d: warning: %s\n", ftell(file
), msg
);
119 return (c
>= 'a' & c
<= 'z') |
120 (c
>= 'A' & c
<= 'Z') |
126 return c
>= '0' & c
<= '9';
133 fprintf(stderr
, "%d: '%c' expected\n", ftell(file
), c
);
139 #define skip(c) next()
150 /* preprocessor: we handle only define */
152 if (tok
== TOK_DEFINE
) {
154 /* now tok is the macro symbol */
155 vat
[tok
] = VT_DEFINE
;
156 vac
[tok
] = ftell(file
);
158 /* ignore preprocessor or shell */
161 } else if (c
== '\n') {
162 /* end of line : check if we are in macro state. if so,
163 pop new file position */
164 if (macro_stack_ptr
> macro_stack
)
165 fseek(file
, *--macro_stack_ptr
, 0);
166 } else if (c
!= ' ' & c
!= 9)
172 while(isid(c
) | isnum(c
)) {
181 if (strcmp(p
, idptr
) == 0)
186 /* if not found, add symbol */
190 if (vat
[tok
] & VT_DEFINE
) {
191 *macro_stack_ptr
++ = ftell(file
);
192 fseek(file
, vac
[tok
], 0);
196 q
= "<=\236>=\235!=\225&&\240||\241++\244--\242==\224<<\340>>\370";
200 if (*q
== c
& q
[1] == v
) {
207 /* single char substitutions */
230 /* output a symbol and patch all calls to it */
235 n
= *(int *)t
; /* next value */
236 *(int *)t
= ind
- t
- 4;
241 /* psym is used to put an instruction with a data field which is a
242 reference to a symbol. It is in fact the same as oad ! */
245 /* instruction + 4 bytes data. Return the address of the data */
255 /* push to value stack */
262 /* generate a value in eax from vt and vc */
269 if ((vt
& VT_TYPE
) == VT_BYTE
)
270 o(0xbe0f); /* movsbl x, %eax */
272 o(0x8b); /* movl x,%eax */
275 else if (vt
& VT_LOCAL
)
281 oad(0xb8, vc
); /* mov $xx, %eax */
282 } else if (vt
& VT_LOCAL
) {
283 oad(0x858d, vc
); /* lea xxx(%ebp), %eax */
284 } else if (vt
& VT_CMP
) {
285 oad(0xb8, 0); /* mov $0, %eax */
286 o(0x0f); /* setxx %al */
291 else if (vt
& VT_JMP
) {
293 oad(0xb8, t
); /* mov $1, %eax */
294 oad(0xe9, 5); /* jmp after */
296 oad(0xb8, t
^ 1); /* mov $0, %eax */
300 vt
= (vt
& VT_TYPE
) | VT_VAR
;
303 /* generate a test. set 'inv' to invert test */
304 /* XXX: handle constant */
308 /* fast case : can jump directly since flags are set */
310 t
= psym((vc
- 16) ^ inv
, t
);
314 /* && or || optimization */
322 if ((vt
& (VT_CONST
| VT_LVAL
)) == VT_CONST
) {
323 /* constant jmp optimization */
324 if ((vc
!= 0) != inv
)
330 o(0xc085); /* test %eax, %eax */
332 t
= psym(0x85 ^ inv
, t
);
337 /* return the size (in bytes) of a given type */
340 if ((t
& VT_PTRMASK
) > VT_PTRINC
| (t
& VT_TYPE
) == VT_PTRINC
)
346 #define POST_ADD 0x1000
349 /* a defines POST/PRE add. c is the token ++ or -- */
354 error("lvalue expected\n");
358 o(0x018bc189); /* movl %eax, %ecx ; mov (%ecx), %eax */
359 o(0x408d | a
); /* leal x(%eax), %eax/%edx */
360 g((c
- TOK_MID
) * type_size(vt
));
361 o(0x0189 | a
); /* mov %eax/%edx, (%ecx) */
364 /* op is '-' or '+' (or 0) */
365 /* t is the type of the first operand */
366 /* XXX: handle ptr sub and 'int + ptr' case (only 'ptr + int' handled) */
370 o(0x59); /* pop %ecx */
371 if (op
== '+' | op
== '-') {
372 /* XXX: incorrect for short (futur!) */
373 if (type_size(t
) != 1)
374 o(0x02e0c1); /* shl $2, %eax */
376 o(0xd8f7); /* neg %eax */
377 o(0xc801); /* add %ecx, %eax */
379 } else if (op
== '&')
386 o(0xc1af0f); /* imul %ecx, %eax */
387 else if (op
== TOK_SHL
| op
== TOK_SHR
) {
388 o(0xd391); /* xchg %ecx, %eax, shl/sar %cl, %eax */
390 } else if (op
== '/' | op
== '%') {
391 o(0xd231); /* xor %edx, %edx */
392 o(0xf9f791); /* xchg %ecx, %eax, idiv %ecx, %eax */
394 o(0x92); /* xchg %edx, %eax */
396 o(0xc139); /* cmp %eax,%ecx */
401 /* return 0 if no type declaration. otherwise, return the basic type
403 XXX: A '2' is ored to ensure non zero return if int type.
409 if (tok
== TOK_INT
| tok
== TOK_CHAR
| tok
== TOK_VOID
) {
412 return (t
!= TOK_INT
) | 2;
418 /* Read a type declaration (except basic type), and return the
419 type. If v is true, then also put variable name in 'vc' */
424 t
= t
& -3; /* suppress the ored '2' */
431 /* XXX: incorrect if abstract type for functions (e.g. 'int ()') */
438 /* type identifier */
444 /* function declaration */
448 n
= vc
; /* must save vc there */
450 /* read param name and compute offset */
452 t
= typ(1, t
); /* XXX: should accept both arg/non arg if v == 0 */
459 vat
[vc
] = VT_LOCAL
| VT_LVAL
| t
;
464 next(); /* skip ')' */
502 n
= n
* 10 + tok
- '0';
506 } else if (tok
== '\'') {
507 vset(VT_CONST
, getq(inp()));
508 next(); /* skip char */
510 } else if (tok
== '\"') {
511 vset(VT_CONST
| VT_PTRINC
| VT_BYTE
, glo
);
512 while((n
= inp()) != 34) {
513 *(char *)glo
= getq(n
);
517 glo
= (glo
+ 4) & -4; /* align heap */
528 vt
= (vt
& VT_TYPEN
) | ft
;
533 } else if (t
== '*') {
538 if (!(vt
& VT_PTRMASK
))
539 error("pointer expected");
541 vt
= (vt
- VT_PTRINC
) | VT_LVAL
;
542 } else if (t
== '&') {
546 error("lvalue expected");
557 vset(VT_JMP
, gtst(1, 0));
561 if ((vt
& (VT_CONST
| VT_LVAL
)) == VT_CONST
)
569 if (t
== TOK_INC
| t
== TOK_DEC
) {
572 } else if (t
== '-') {
574 if ((vt
& (VT_CONST
| VT_LVAL
)) == VT_CONST
)
578 o(0xd8f7); /* neg %eax */
580 } else if (t
== '+') {
583 vset(vat
[t
], vac
[t
]);
584 /* forward reference or external reference ? */
586 n
= dlsym(0, idlast
);
588 vset(VT_CONST
| VT_FORWARD
| VT_LVAL
, vac
+ t
);
590 vset(VT_CONST
| VT_LVAL
, n
);
595 /* post operations */
596 if (tok
== TOK_INC
| tok
== TOK_DEC
) {
602 if (!(vt
& VT_PTRMASK
))
603 error("pointer expected");
609 o(0x50); /* push %eax */
612 /* dereference pointer */
613 vt
= (ft
- VT_PTRINC
) | VT_LVAL
;
619 /* lvalue is implied */
621 if ((vt
& VT_CONST
) == 0) {
622 /* evaluate function address */
624 o(0x50); /* push %eax */
635 o(0x50); /* push %eax */
640 /* horrible, but needed : convert to native ordering (could
641 parse parameters in reverse order, but would cost more
646 oad(0x24848b, p
); /* mov x(%esp,1), %eax */
647 oad(0x248487, n
); /* xchg x(%esp,1), %eax */
648 oad(0x248489, p
); /* mov %eax, x(%esp,1) */
653 /* forward reference */
655 *(int *)fc
= psym(0xe8, *(int *)fc
);
657 oad(0xe8, fc
- ind
- 5);
659 oad(0x2494ff, t
); /* call *xxx(%esp) */
664 /* return value is variable */
677 error("lvalue expected");
682 b
= (vt
& VT_TYPE
) == VT_BYTE
;
684 o(0x50); /* push %eax */
687 if ((vt
& VT_PTRMASK
) != (ft
& VT_PTRMASK
))
688 warning("incompatible type");
690 gv(); /* generate value */
693 o(0x59); /* pop %ecx */
694 o(0x0189 - b
); /* mov %eax/%al, (%ecx) */
697 oad(0x8589 - b
, fc
); /* mov %eax/%al,xxx(%ebp) */
699 oad(0xa3 - b
, fc
); /* mov %eax/%al,xxx */
714 if ((l
== 0 & op
!= '*' & op
!= '/' & op
!= '%') |
715 (l
== 1 & op
!= '+' & op
!= '-') |
716 (l
== 2 & op
!= TOK_SHL
& op
!= TOK_SHR
) |
717 (l
== 3 & (op
< TOK_LT
| op
> TOK_GT
)) |
718 (l
== 4 & op
!= TOK_EQ
& op
!= TOK_NE
) |
719 (l
== 5 & op
!= '&') |
720 (l
== 6 & op
!= '^') |
721 (l
== 7 & op
!= '|'))
725 o(0x50); /* push %eax */
746 if (tok
!= TOK_LAND
) {
766 if (tok
!= TOK_LOR
) {
795 d
= psym(0xe9, 0); /* jmp */
798 gsym(d
); /* patch else jmp */
801 } else if (tok
== TOK_WHILE
) {
807 *++lsym
= gtst(1, 0);
809 oad(0xe9, d
- ind
- 5); /* jmp */
811 } else if (tok
== '{') {
818 } else if (tok
== TOK_RETURN
) {
825 rsym
= psym(0xe9, rsym
); /* jmp */
826 } else if (tok
== TOK_BREAK
) {
828 *lsym
= psym(0xe9, *lsym
);
838 /* 'l' is true if local declarations */
844 while (1) { /* iterate thru each declaration */
847 /* patch forward references (XXX: does not work for
848 function pointers) */
851 /* put function address */
852 vat
[vc
] = VT_CONST
| VT_LVAL
| vt
;
855 o(0xe58955); /* push %ebp, mov %esp, %ebp */
856 a
= oad(0xec81, 0); /* sub $xxx, %esp */
860 o(0xc3c9); /* leave, ret */
861 *a
= loc
; /* save local variables */
865 vat
[vc
] = l
| VT_LVAL
| vt
;
883 int main(int c
, char **v
)
888 printf("usage: tc src\n");
892 file
= fopen(*v
, "r");
894 idtable
= malloc(SYM_TABLE_SIZE
);
896 "int\0void\0char\0if\0else\0while\0break\0return\0define\0main", 53);
897 idptr
= idtable
+ 53;
898 glo
= malloc(DATA_SIZE
);
899 prog
= malloc(TEXT_SIZE
);
900 vac
= malloc(VAR_TABLE_SIZE
);
901 vat
= malloc(VAR_TABLE_SIZE
);
903 macro_stack
= malloc(256);
904 macro_stack_ptr
= macro_stack
;
911 f
= fopen(v
[1], "w");
912 fwrite((void *)prog
, 1, ind
- prog
, f
);
918 return (*t
)(c
- 1, v
);