2 #include "../cparser.h"
4 #define IS_CONST(tok) (IS_LITERAL(tok, "const") || IS_LITERAL(tok, "__const") \
5 || IS_LITERAL(tok, "__const__"))
6 #define IS_VOLATILE(tok) (IS_LITERAL(tok, "volatile") || \
7 IS_LITERAL(tok, "__volatile") || \
8 IS_LITERAL(tok, "__volatile__"))
9 #define IS_RESTRICT(tok) (IS_LITERAL(tok, "restrict") || \
10 IS_LITERAL(tok, "__restrict") || \
11 IS_LITERAL(tok, "__restrict__"))
13 #define max(a,b) ((a) < (b) ? (b) : (a))
14 #define min(a,b) ((a) < (b) ? (a) : (b))
24 /* the order of these values must match the token strings in lex.c */
32 TOK_LEFT_SHIFT, TOK_RIGHT_SHIFT, TOK_LOGICAL_AND, TOK_LOGICAL_OR,
33 TOK_LESS_EQUAL, TOK_GREATER_EQUAL, TOK_EQUAL, TOK_NOT_EQUAL,
37 TOK_OPEN_CURLY, TOK_CLOSE_CURLY, TOK_SEMICOLON, TOK_COMMA, TOK_COLON,
39 TOK_ASSIGN, TOK_OPEN_PAREN, TOK_CLOSE_PAREN, TOK_OPEN_SQUARE, TOK_CLOSE_SQUARE,
40 TOK_DOT, TOK_AMPERSAND, TOK_LOGICAL_NOT, TOK_BITWISE_NOT, TOK_MINUS,
42 TOK_PLUS, TOK_STAR, TOK_DIVIDE, TOK_MODULUS, TOK_LESS,
43 TOK_GREATER, TOK_BITWISE_XOR, TOK_BITWISE_OR, TOK_QUESTION, TOK_POUND,
46 TOK_REFERENCE = TOK_AMPERSAND,
47 TOK_MULTIPLY = TOK_STAR,
48 TOK_BITWISE_AND = TOK_AMPERSAND,
58 #define IS_LITERAL(TOK, STR) \
59 (((TOK).size == sizeof(STR) - 1) && \
60 0 == memcmp((TOK).str, STR, sizeof(STR) - 1))
63 static int parse_type_name(struct parser *P, char *type_name);
64 static void parse_argument(struct parser *P, struct cp_ctype *ct,
65 struct token *pname, struct parser *asmname);
66 static int parse_attribute(struct parser *P, struct token *tok,
67 struct cp_ctype *ct, struct parser *asmname);
68 static int parse_record(struct parser *P, struct cp_ctype *ct);
69 static void instantiate_typedef(struct parser *P, struct cp_ctype *tt,
70 const struct cp_ctype *ft);
73 /* the order of tokens _must_ match the order of the enum etoken enum */
75 static char tok3[][4] = {
76 "...", /* unused ">>=", "<<=", */
79 static char tok2[][3] = {
80 "<<", ">>", "&&", "||", "<=",
82 /* unused "+=", "-=", "*=", "/=", "%=", "&=", "^=",
83 * "|=", "++", "--", "->", "::", */
86 static char tok1[] = {
87 '{', '}', ';', ',', ':',
88 '=', '(', ')', '[', ']',
89 '.', '&', '!', '~', '-',
90 '+', '*', '/', '%', '<',
91 '>', '^', '|', '?', '#'
95 /* this function never returns, but it's an idiom to use it in C functions
96 * as return cp_error */
97 void cp_error(const char *err_msg_fmt, ...)
101 fprintf(stderr, "cparser error:\n");
103 va_start(ap, err_msg_fmt);
104 vfprintf(stderr, err_msg_fmt, ap);
110 static int set_struct_type_name(char *dst, const char *src, int len)
112 int prefix_len = sizeof("struct ");
114 if (len + prefix_len > MAX_TYPE_NAME_LEN)
117 memset(dst, 0, MAX_TYPE_NAME_LEN);
118 strcpy(dst, "struct ");
119 strncat(dst, src, len);
124 static void increase_ptr_deref_level(struct parser *P, struct cp_ctype *ct)
126 if (ct->pointers == POINTER_MAX) {
127 cp_error("maximum number of pointer derefs reached - use a "
128 "struct to break up the pointers on line %d", P->line);
131 ct->const_mask <<= 1;
135 static int next_token(struct parser *P, struct token *tok)
138 const char *s = P->next;
141 if (s[0] == '\xEF' && s[1] == '\xBB' && s[2] == '\xBF') {
145 /* consume whitespace and comments */
147 /* consume whitespace */
148 while (*s == '\t' || *s == '\n' || *s == ' '
149 || *s == '\v' || *s == '\r') {
156 /* consume comments */
157 if (*s == '/' && *(s+1) == '/') {
161 cp_error("non-terminated comment");
164 } else if (*s == '/' && *(s+1) == '*') {
169 cp_error("non-terminated comment");
170 } else if (s[0] == '*' && s[1] == '/') {
173 } else if (s[0] == '\n') {
179 } else if (*s == '\0') {
190 for (i = 0; i < sizeof(tok3) / sizeof(tok3[0]); i++) {
191 if (s[0] == tok3[i][0] && s[1] == tok3[i][1] && s[2] == tok3[i][2]) {
192 tok->type = (enum etoken) (TOK_3_BEGIN + 1 + i);
198 for (i = 0; i < sizeof(tok2) / sizeof(tok2[0]); i++) {
199 if (s[0] == tok2[i][0] && s[1] == tok2[i][1]) {
200 tok->type = (enum etoken) (TOK_2_BEGIN + 1 + i);
206 for (i = 0; i < sizeof(tok1) / sizeof(tok1[0]); i++) {
207 if (s[0] == tok1[i]) {
208 tok->type = (enum etoken) (TOK_1_BEGIN + 1 + i);
214 if (*s == '.' || *s == '-' || ('0' <= *s && *s <= '9')) {
216 tok->type = TOK_NUMBER;
218 /* split out the negative case so we get the full range of
219 * bits for unsigned (eg to support 0xFFFFFFFF where
220 * sizeof(long) == 4 */
222 tok->integer = strtol(s, (char**) &s, 0);
224 tok->integer = strtoul(s, (char**) &s, 0);
227 while (*s == 'u' || *s == 'U' || *s == 'l' || *s == 'L') {
234 } else if (*s == '\'' || *s == '\"') {
237 s++; /* jump over " */
239 tok->type = TOK_STRING;
242 while (*s != quote) {
243 if (*s == '\0' || (*s == '\\' && *(s+1) == '\0')) {
244 cp_error("string not finished\n");
252 tok->size = s - tok->str;
253 s++; /* jump over " */
257 } else if (('a' <= *s && *s <= 'z') || ('A' <= *s && *s <= 'Z')
260 tok->type = TOK_TOKEN;
263 while (('a' <= *s && *s <= 'z') || ('A' <= *s && *s <= 'Z')
264 || *s == '_' || ('0' <= *s && *s <= '9')) {
268 tok->size = s - tok->str;
272 cp_error("invalid character %d", P->line);
279 static void require_token(struct parser *P, struct token *tok)
281 if (!next_token(P, tok)) {
282 cp_error("unexpected end");
286 static void check_token(struct parser *P, int type, const char *str,
287 const char *err, ...)
291 if (!next_token(P, &tok) || tok.type != type
292 || (tok.type == TOK_TOKEN && (tok.size != strlen(str)
293 || memcmp(tok.str, str, tok.size) != 0))) {
296 vfprintf(stderr, err, ap);
303 static void put_back(struct parser *P) {
307 int64_t calculate_constant(struct parser *P);
309 /* parses out the base type of a type expression in a function declaration,
310 * struct definition, typedef etc
312 * leaves the usr value of the type on the stack
314 int parse_type(struct parser *P, struct cp_ctype *ct)
318 memset(ct, 0, sizeof(*ct));
320 require_token(P, &tok);
322 /* get function attributes before the return type */
323 while (parse_attribute(P, &tok, ct, NULL)) {
324 require_token(P, &tok);
327 /* get const/volatile before the base type */
329 if (tok.type != TOK_TOKEN) {
330 cp_error("unexpected value before type name on line %d",
333 } else if (IS_CONST(tok)) {
335 require_token(P, &tok);
336 } else if (IS_VOLATILE(tok) || IS_RESTRICT(tok)) {
337 /* ignored for now */
338 require_token(P, &tok);
345 if (tok.type != TOK_TOKEN) {
346 cp_error("unexpected value before type name on line %d", P->line);
348 } else if (IS_LITERAL(tok, "struct")) {
349 ct->type = STRUCT_TYPE;
351 } else if (IS_LITERAL(tok, "union")) {
352 ct->type = UNION_TYPE;
354 } else if (IS_LITERAL(tok, "enum")) {
355 ct->type = ENUM_TYPE;
361 struct cp_ctype *lct;
362 char cur_type_name[MAX_TYPE_NAME_LEN];
364 memset(cur_type_name, 0, MAX_TYPE_NAME_LEN);
365 parse_type_name(P, cur_type_name);
366 lct = ctype_lookup_type(cur_type_name);
368 cp_error("unknow type: \"%s\"\n", cur_type_name);
370 instantiate_typedef(P, ct, lct);
373 while (next_token(P, &tok)) {
374 if (tok.type != TOK_TOKEN) {
377 } else if (IS_CONST(tok) || IS_VOLATILE(tok)) {
390 /* Parses an enum definition from after the open curly through to the close
391 * curly. Expects the user table to be on the top of the stack
393 static int parse_enum(struct parser *P, struct cp_ctype *type)
398 /*@TODO clean up this function when enum support is added*/
399 cp_error("TODO: enum not supported!\n");
402 require_token(P, &tok);
404 if (tok.type == TOK_CLOSE_CURLY) {
406 } else if (tok.type != TOK_TOKEN) {
407 cp_error("unexpected token in enum at line %d", P->line);
410 require_token(P, &tok);
412 if (tok.type == TOK_COMMA || tok.type == TOK_CLOSE_CURLY) {
413 /* we have an auto calculated enum value */
415 } else if (tok.type == TOK_ASSIGN) {
416 /* we have an explicit enum value */
417 value = (int) calculate_constant(P);
418 require_token(P, &tok);
420 cp_error("unexpected token in enum at line %d", P->line);
424 if (tok.type == TOK_CLOSE_CURLY) {
426 } else if (tok.type != TOK_COMMA) {
427 cp_error("unexpected token in enum at line %d", P->line);
432 type->base_size = sizeof(enum test);
433 type->align_mask = sizeof(enum test) - 1;
438 /* Parses a struct from after the open curly through to the close curly. */
439 static int parse_struct(struct parser *P, const struct cp_ctype *ct)
445 struct cp_ctype mbase;
447 /* see if we're at the end of the struct */
448 require_token(P, &tok);
449 if (tok.type == TOK_CLOSE_CURLY) {
451 } else if (ct->is_variable_struct) {
452 cp_error("can't have members after a variable sized "
453 "member on line %d", P->line);
459 /* members are of the form
460 * <base type> <arg>, <arg>, <arg>;
461 * eg struct foo bar, *bar2[2];
462 * mbase is 'struct foo'
463 * mtype is '' then '*[2]'
464 * mname is 'bar' then 'bar2'
467 parse_type(P, &mbase);
471 struct cp_ctype mt = mbase;
473 memset(&mname, 0, sizeof(mname));
475 if (ct->is_variable_struct) {
476 cp_error("can't have members after a variable "
477 "sized member on line %d", P->line);
481 parse_argument(P, &mt, &mname, NULL);
483 if (!mt.is_defined && (mt.pointers - mt.is_array) == 0) {
484 cp_error("member type is undefined on line %d",
489 if (mt.type == VOID_TYPE
490 && (mt.pointers - mt.is_array) == 0) {
491 cp_error("member type can not be void on line %d",
496 mt.has_member_name = (mname.size > 0);
497 if (mt.has_member_name) {
498 cp_push_ctype_with_name(&mt,
499 mname.str, mname.size);
501 /* @TODO handle unnamed member (houqp) */
502 cp_error("TODO: unnamed member not supported.");
506 require_token(P, &tok);
507 if (tok.type == TOK_SEMICOLON) {
509 } else if (tok.type != TOK_COMMA) {
510 cp_error("unexpected token in struct "
511 "definition on line %d", P->line);
519 /* copy over attributes that could be specified before the typedef eg
520 * __attribute__(packed) const type_t */
521 static void instantiate_typedef(struct parser *P, struct cp_ctype *tt,
522 const struct cp_ctype *ft)
524 struct cp_ctype pt = *tt;
527 tt->const_mask |= pt.const_mask;
528 tt->is_packed = pt.is_packed;
533 /* Instantiate the typedef in the current packing. This may be
534 * further updated if a pointer is added or another alignment
535 * attribute is applied. If pt.align_mask is already non-zero
536 * than an increased alignment via __declspec(aligned(#)) has
538 tt->align_mask = max(min(P->align_mask, tt->align_mask),
543 /* this parses a struct or union starting with the optional
544 * name before the opening brace
545 * leaves the type usr value on the stack */
546 static int parse_record(struct parser *P, struct cp_ctype *ct)
549 char cur_type_name[MAX_TYPE_NAME_LEN];
551 require_token(P, &tok);
553 /* name is optional */
554 if (tok.type == TOK_TOKEN) {
556 struct cp_ctype *lct;
558 memset(cur_type_name, 0, MAX_TYPE_NAME_LEN);
559 set_struct_type_name(cur_type_name, tok.str, tok.size);
561 /* lookup the name to see if we've seen this type before */
562 lct = ctype_lookup_type(cur_type_name);
565 /* new type, delay type registration to the end
566 * of this function */
568 /* get the exsting declared type */
569 if (lct->type != ct->type) {
570 cp_error("type '%s' previously declared as '%s'",
572 csym_name(ct_ffi_cs(lct)));
575 instantiate_typedef(P, ct, lct);
578 /* if a name is given then we may be at the end of the string
579 * eg for ffi.new('struct foo') */
580 if (!next_token(P, &tok)) {
584 /* create a new unnamed record */
586 /*@TODO clean this up after unnamed record support is added */
587 cp_error("TODO: support unnamed record.\n");
590 if (tok.type != TOK_OPEN_CURLY) {
591 /* this may just be a declaration or use of the type as an
592 * argument or member */
597 if (ct->is_defined) {
598 cp_error("redefinition in line %d", P->line);
602 if (ct->type == ENUM_TYPE) {
605 /* we do a two stage parse, where we parse the content first
606 * and build up the temp user table. We then iterate over that
607 * to calculate the offsets and fill out ct_usr. This is so we
608 * can handle out of order members (eg vtable) and attributes
609 * specified at the end of the struct. */
611 /* build symbol for vm */
612 ct->ffi_cs_id = cp_symbol_build_struct(cur_type_name);
613 /* save cp_ctype for parser */
614 cp_ctype_reg_type(cur_type_name, ct);
621 /* parses single or multi work built in types, and pushes it onto the stack */
622 static int parse_type_name(struct parser *P, char *type_name)
641 require_token(P, &tok);
643 /* we have to manually decode the builtin types since they can take up
644 * more then one token */
646 if (tok.type != TOK_TOKEN) {
648 } else if (IS_LITERAL(tok, "unsigned")) {
650 } else if (IS_LITERAL(tok, "signed")) {
652 } else if (IS_LITERAL(tok, "short")) {
654 } else if (IS_LITERAL(tok, "char")) {
656 } else if (IS_LITERAL(tok, "long")) {
657 flags |= (flags & LONG) ? LONG_LONG : LONG;
658 } else if (IS_LITERAL(tok, "int")) {
660 } else if (IS_LITERAL(tok, "__int8")) {
662 } else if (IS_LITERAL(tok, "__int16")) {
664 } else if (IS_LITERAL(tok, "__int32")) {
666 } else if (IS_LITERAL(tok, "__int64")) {
668 } else if (IS_LITERAL(tok, "register")) {
674 if (!next_token(P, &tok)) {
684 if (flags & SIGNED) {
685 strcpy(type_name, "int8_t");
686 } else if (flags & UNSIGNED) {
687 strcpy(type_name, "uint8_t");
689 if (((char) -1) > 0) {
690 strcpy(type_name, "uint8_t");
692 strcpy(type_name, "int8_t");
695 } else if (flags & INT8) {
696 strcpy(type_name, (flags & UNSIGNED) ? "uint8_t" : "int8_t");
697 } else if (flags & INT16) {
698 strcpy(type_name, (flags & UNSIGNED) ? "uint16_t" : "int16_t");
699 } else if (flags & INT32) {
700 strcpy(type_name, (flags & UNSIGNED) ? "uint32_t" : "int32_t");
701 } else if (flags & INT64) {
702 strcpy(type_name, (flags & UNSIGNED) ? "uint64_t" : "int64_t");
703 } else if (flags & LONG_LONG) {
704 strcpy(type_name, (flags & UNSIGNED) ? "uint64_t" : "int64_t");
705 } else if (flags & SHORT) {
706 #define SHORT_TYPE(u) (sizeof(short) == sizeof(int64_t) ? \
707 u "int64_t" : sizeof(short) == sizeof(int32_t) ? \
708 u "int32_t" : u "int16_t")
709 if (flags & UNSIGNED) {
710 strcpy(type_name, SHORT_TYPE("u"));
712 strcpy(type_name, SHORT_TYPE(""));
715 } else if (flags & LONG) {
716 #define LONG_TYPE(u) (sizeof(long) == sizeof(int64_t) ? \
717 u "int64_t" : u "int32_t")
718 if (flags & UNSIGNED) {
719 strcpy(type_name, LONG_TYPE("u"));
721 strcpy(type_name, LONG_TYPE(""));
725 #define INT_TYPE(u) (sizeof(int) == sizeof(int64_t) ? \
726 u "int64_t" : sizeof(int) == sizeof(int32_t) ? \
727 u "int32_t" : u "int16_t")
728 if (flags & UNSIGNED) {
729 strcpy(type_name, INT_TYPE("u"));
731 strcpy(type_name, INT_TYPE(""));
735 strncpy(type_name, tok.str, tok.size);
741 /* parse_attribute parses a token to see if it is an attribute. It may then
742 * parse some following tokens to decode the attribute setting the appropriate
743 * fields in ct. It will return 1 if the token was used (and possibly some
744 * more following it) or 0 if not. If the token was used, the next token must
745 * be retrieved using next_token/require_token. */
746 static int parse_attribute(struct parser *P, struct token *tok,
747 struct cp_ctype *ct, struct parser *asmname)
749 if (tok->type != TOK_TOKEN) {
751 } else if (asmname && (IS_LITERAL(*tok, "__asm__")
752 || IS_LITERAL(*tok, "__asm"))) {
753 check_token(P, TOK_OPEN_PAREN, NULL,
754 "unexpected token after __asm__ on line %d",
758 require_token(P, tok);
759 while (tok->type == TOK_STRING) {
760 require_token(P, tok);
763 if (tok->type != TOK_CLOSE_PAREN) {
764 cp_error("unexpected token after __asm__ on line %d",
769 } else if (IS_LITERAL(*tok, "__attribute__")
770 || IS_LITERAL(*tok, "__declspec")) {
772 check_token(P, TOK_OPEN_PAREN, NULL,
773 "expected parenthesis after __attribute__ or "
774 "__declspec on line %d", P->line);
777 require_token(P, tok);
778 if (tok->type == TOK_OPEN_PAREN) {
780 } else if (tok->type == TOK_CLOSE_PAREN) {
785 } else if (tok->type != TOK_TOKEN) {
786 /* ignore unknown symbols within parentheses */
788 } else if (IS_LITERAL(*tok, "align") ||
789 IS_LITERAL(*tok, "aligned") ||
790 IS_LITERAL(*tok, "__aligned__")) {
792 require_token(P, tok);
795 case TOK_CLOSE_PAREN:
796 align = ALIGNED_DEFAULT;
801 require_token(P, tok);
803 if (tok->type != TOK_NUMBER) {
804 cp_error("expected align(#) "
805 "on line %d", P->line);
808 switch (tok->integer) {
809 case 1: align = 0; break;
810 case 2: align = 1; break;
811 case 4: align = 3; break;
812 case 8: align = 7; break;
813 case 16: align = 15; break;
815 cp_error("unsupported align "
820 check_token(P, TOK_CLOSE_PAREN, NULL,
821 "expected align(#) on line %d",
826 cp_error("expected align(#) on line %d",
830 /* __attribute__(aligned(#)) is only supposed
831 * to increase alignment */
832 ct->align_mask = max(align, ct->align_mask);
834 } else if (IS_LITERAL(*tok, "packed")
835 || IS_LITERAL(*tok, "__packed__")) {
839 } else if (IS_LITERAL(*tok, "mode")
840 || IS_LITERAL(*tok, "__mode__")) {
842 check_token(P, TOK_OPEN_PAREN, NULL,
843 "expected mode(MODE) on line %d",
846 require_token(P, tok);
847 if (tok->type != TOK_TOKEN) {
848 cp_error("expected mode(MODE) on line %d",
853 struct {char ch; uint16_t v;} a16;
854 struct {char ch; uint32_t v;} a32;
855 struct {char ch; uint64_t v;} a64;
857 if (IS_LITERAL(*tok, "QI")
858 || IS_LITERAL(*tok, "__QI__")
859 || IS_LITERAL(*tok, "byte")
860 || IS_LITERAL(*tok, "__byte__")
862 ct->type = INT8_TYPE;
863 ct->base_size = sizeof(uint8_t);
866 } else if (IS_LITERAL(*tok, "HI")
867 || IS_LITERAL(*tok, "__HI__")) {
868 ct->type = INT16_TYPE;
869 ct->base_size = sizeof(uint16_t);
870 ct->align_mask = ALIGNOF(a16);
872 } else if (IS_LITERAL(*tok, "SI")
873 || IS_LITERAL(*tok, "__SI__")
874 #if defined ARCH_X86 || defined ARCH_ARM
875 || IS_LITERAL(*tok, "word")
876 || IS_LITERAL(*tok, "__word__")
877 || IS_LITERAL(*tok, "pointer")
878 || IS_LITERAL(*tok, "__pointer__")
881 ct->type = INT32_TYPE;
882 ct->base_size = sizeof(uint32_t);
883 ct->align_mask = ALIGNOF(a32);
885 } else if (IS_LITERAL(*tok, "DI")
886 || IS_LITERAL(*tok, "__DI__")
888 || IS_LITERAL(*tok, "word")
889 || IS_LITERAL(*tok, "__word__")
890 || IS_LITERAL(*tok, "pointer")
891 || IS_LITERAL(*tok, "__pointer__")
894 ct->type = INT64_TYPE;
895 ct->base_size = sizeof(uint64_t);
896 ct->align_mask = ALIGNOF(a64);
899 cp_error("unexpected mode on line %d",
903 check_token(P, TOK_CLOSE_PAREN, NULL,
904 "expected mode(MODE) on line %d", P->line);
906 } else if (IS_LITERAL(*tok, "cdecl")
907 || IS_LITERAL(*tok, "__cdecl__")) {
908 ct->calling_convention = C_CALL;
910 } else if (IS_LITERAL(*tok, "fastcall")
911 || IS_LITERAL(*tok, "__fastcall__")) {
912 ct->calling_convention = FAST_CALL;
914 } else if (IS_LITERAL(*tok, "stdcall")
915 || IS_LITERAL(*tok, "__stdcall__")) {
916 ct->calling_convention = STD_CALL;
918 /* ignore unknown tokens within parentheses */
922 } else if (IS_LITERAL(*tok, "__cdecl")) {
923 ct->calling_convention = C_CALL;
926 } else if (IS_LITERAL(*tok, "__fastcall")) {
927 ct->calling_convention = FAST_CALL;
930 } else if (IS_LITERAL(*tok, "__stdcall")) {
931 ct->calling_convention = STD_CALL;
934 } else if (IS_LITERAL(*tok, "__extension__")
935 || IS_LITERAL(*tok, "extern")) {
943 /* parses from after the opening paranthesis to after the closing parenthesis */
944 static void parse_function_arguments(struct parser* P, struct cp_ctype* ct)
950 require_token(P, &tok);
952 if (tok.type == TOK_CLOSE_PAREN)
956 if (tok.type != TOK_COMMA) {
957 cp_error("unexpected token in function "
958 "argument %d on line %d",
961 require_token(P, &tok);
964 if (tok.type == TOK_VA_ARG) {
965 ct->has_var_arg = true;
966 check_token(P, TOK_CLOSE_PAREN, "",
967 "unexpected token after ... in "
968 "function on line %d",
971 } else if (tok.type == TOK_TOKEN) {
976 parse_argument(P, &at, NULL, NULL);
978 /* array arguments are just treated as their
979 * base pointer type */
982 /* check for the c style int func(void) and error
983 * on other uses of arguments of type void */
984 if (at.type == VOID_TYPE && at.pointers == 0) {
986 cp_error("can't have argument of type "
991 check_token(P, TOK_CLOSE_PAREN, "",
992 "unexpected void in function on line %d",
999 cp_error("unexpected token in function argument %d "
1000 "on line %d", args+1, P->line);
1005 static int max_bitfield_size(int type)
1024 static struct cp_ctype *parse_argument2(struct parser *P, struct cp_ctype *ct,
1025 struct token *name, struct parser *asmname);
1027 /* parses from after the first ( in a function declaration or function pointer
1029 * void foo(...) before ...
1030 * void (foo)(...) before foo
1031 * void (* <>)(...) before <> which is the inner type */
1032 static struct cp_ctype *parse_function(struct parser *P, struct cp_ctype *ct,
1033 struct token *name, struct parser *asmname)
1035 /* We have a function pointer or a function. The usr table will
1036 * get replaced by the canonical one (if there is one) in
1037 * find_canonical_usr after all the arguments and returns have
1040 struct cp_ctype *ret = ct;
1044 memset(ct, 0, sizeof(*ct));
1045 ct->base_size = sizeof(void (*)());
1046 ct->align_mask = min(FUNCTION_ALIGN_MASK, P->align_mask);
1047 ct->type = FUNCTION_TYPE;
1050 if (name->type == TOK_NIL) {
1052 require_token(P, &tok);
1054 if (tok.type == TOK_STAR) {
1055 if (ct->type == FUNCTION_TYPE) {
1056 ct->type = FUNCTION_PTR_TYPE;
1058 increase_ptr_deref_level(P, ct);
1060 } else if (parse_attribute(P, &tok, ct, asmname)) {
1061 /* parse_attribute sets the appropriate fields */
1063 /* call parse_argument to handle the inner
1064 * contents e.g. the <> in "void (* <>)
1065 * (...)". Note that the inner contents can
1066 * itself be a function, a function ptr,
1067 * array, etc (e.g. "void (*signal(int sig,
1068 * void (*func)(int)))(int)" ). */
1069 cp_error("TODO: inner function not supported for now.");
1071 ct = parse_argument2(P, ct, name, asmname);
1076 check_token(P, TOK_CLOSE_PAREN, NULL,
1077 "unexpected token in function on line %d", P->line);
1078 check_token(P, TOK_OPEN_PAREN, NULL,
1079 "unexpected token in function on line %d", P->line);
1082 parse_function_arguments(P, ct);
1084 /*@TODO support for inner function 24.11 2013 (houqp)*/
1085 /* if we have an inner function then set the outer function ptr as its
1086 * return type and return the inner function
1087 * e.g. for void (* <signal(int, void (*)(int))> )(int) inner is
1088 * surrounded by <>, return type is void (*)(int) */
1093 static struct cp_ctype *parse_argument2(struct parser *P, struct cp_ctype *ct,
1094 struct token *name, struct parser *asmname)
1099 if (!next_token(P, &tok)) {
1100 /* we've reached the end of the string */
1102 } else if (tok.type == TOK_STAR) {
1103 increase_ptr_deref_level(P, ct);
1105 /* __declspec(align(#)) may come before the type in a
1107 if (!ct->is_packed) {
1108 ct->align_mask = max(min(PTR_ALIGN_MASK, P->align_mask),
1111 } else if (tok.type == TOK_REFERENCE) {
1112 cp_error("NYI: c++ reference types");
1114 } else if (parse_attribute(P, &tok, ct, asmname)) {
1115 /* parse attribute has filled out appropriate fields in type */
1117 } else if (tok.type == TOK_OPEN_PAREN) {
1118 ct = parse_function(P, ct, name, asmname);
1119 } else if (tok.type == TOK_OPEN_SQUARE) {
1121 if (ct->pointers == POINTER_MAX) {
1122 cp_error("maximum number of pointer derefs "
1123 "reached - use a struct to break up "
1128 ct->const_mask <<= 1;
1129 require_token(P, &tok);
1131 if (ct->pointers == 1 && !ct->is_defined) {
1132 cp_error("array of undefined type on line %d",
1136 if (ct->is_variable_struct || ct->is_variable_array) {
1137 cp_error("can't have an array of a variably "
1138 "sized type on line %d", P->line);
1141 if (tok.type == TOK_QUESTION) {
1142 ct->is_variable_array = 1;
1143 ct->variable_increment = (ct->pointers > 1) ?
1144 sizeof(void*) : ct->base_size;
1145 check_token(P, TOK_CLOSE_SQUARE, "",
1146 "invalid character in array on line %d",
1149 } else if (tok.type == TOK_CLOSE_SQUARE) {
1152 } else if (tok.type == TOK_TOKEN && IS_RESTRICT(tok)) {
1153 /* odd gcc extension foo[__restrict] for arguments */
1155 check_token(P, TOK_CLOSE_SQUARE, "",
1156 "invalid character in array on line %d",
1161 asize = calculate_constant(P);
1163 cp_error("array size can not be "
1164 "negative on line %d", P->line);
1167 ct->array_size = (size_t) asize;
1168 check_token(P, TOK_CLOSE_SQUARE, "",
1169 "invalid character in array on line %d",
1173 } else if (tok.type == TOK_COLON) {
1174 int64_t bsize = calculate_constant(P);
1176 if (ct->pointers || bsize < 0
1177 || bsize > max_bitfield_size(ct->type)) {
1178 cp_error("invalid bitfield on line %d", P->line);
1181 ct->is_bitfield = 1;
1182 ct->bit_size = (unsigned) bsize;
1184 } else if (tok.type != TOK_TOKEN) {
1185 /* we've reached the end of the declaration */
1189 } else if (IS_CONST(tok)) {
1190 ct->const_mask |= 1;
1192 } else if (IS_VOLATILE(tok) || IS_RESTRICT(tok)) {
1193 /* ignored for now */
1205 /* parses after the main base type of a typedef, function argument or
1206 * struct/union member
1207 * eg for const void* bar[3] the base type is void with the subtype so far of
1208 * const, this parses the "* bar[3]" and updates the type argument
1210 * type must be as filled out by parse_type
1212 * pushes the updated user value on the top of the stack
1214 void parse_argument(struct parser *P, struct cp_ctype *ct, struct token *pname,
1215 struct parser *asmname)
1217 struct token tok, name;
1219 memset(&name, 0, sizeof(name));
1220 parse_argument2(P, ct, &name, asmname);
1223 if (!next_token(P, &tok)) {
1225 } else if (parse_attribute(P, &tok, ct, asmname)) {
1226 /* parse_attribute sets the appropriate fields */
1238 static void parse_typedef(struct parser *P)
1241 struct cp_ctype base_type;
1242 char typedef_name[MAX_TYPE_NAME_LEN];
1244 parse_type(P, &base_type);
1247 struct cp_ctype arg_type = base_type;
1250 memset(&name, 0, sizeof(name));
1252 parse_argument(P, &arg_type, &name, NULL);
1255 cp_error("Can't have a typedef without a name on line %d",
1257 } else if (arg_type.is_variable_array) {
1258 cp_error("Can't typedef a variable length array on line %d",
1262 memset(typedef_name, 0, sizeof(typedef_name));
1263 strncpy(typedef_name, name.str, name.size);
1264 /* link typedef name with ctype for parser */
1265 cp_ctype_reg_type(typedef_name, &arg_type);
1267 require_token(P, &tok);
1269 if (tok.type == TOK_SEMICOLON) {
1271 } else if (tok.type != TOK_COMMA) {
1272 cp_error("Unexpected character in typedef on line %d",
1279 #define PRAGMA_POP 1
1281 static int parse_root(struct parser *P)
1285 while (next_token(P, &tok)) {
1290 * struct/enum/union declaration
1292 * function declaration
1296 if (tok.type == TOK_SEMICOLON) {
1297 /* empty semicolon in root continue on */
1299 } else if (tok.type == TOK_POUND) {
1301 check_token(P, TOK_TOKEN, "pragma",
1302 "unexpected pre processor directive on line %d",
1304 check_token(P, TOK_TOKEN, "pack",
1305 "unexpected pre processor directive on line %d",
1307 check_token(P, TOK_OPEN_PAREN, "",
1308 "invalid pack directive on line %d",
1310 require_token(P, &tok);
1312 if (tok.type == TOK_NUMBER) {
1313 if (tok.integer != 1 && tok.integer != 2
1316 && tok.integer != 16) {
1317 cp_error("pack directive with invalid "
1318 "pack size on line %d",
1323 P->align_mask = (unsigned) (tok.integer - 1);
1324 check_token(P, TOK_CLOSE_PAREN, "",
1325 "invalid pack directive on line %d",
1327 } else if (tok.type == TOK_TOKEN && IS_LITERAL(tok, "push")) {
1328 /*int line = P->line;*/
1329 unsigned previous_alignment = P->align_mask;
1331 check_token(P, TOK_CLOSE_PAREN, "",
1332 "invalid pack directive on line %d",
1335 if (parse_root(P) != PRAGMA_POP) {
1336 cp_error("reached end of string "
1337 "without a pragma pop to "
1338 "match the push on line %d",
1343 P->align_mask = previous_alignment;
1345 } else if (tok.type == TOK_TOKEN && IS_LITERAL(tok, "pop")) {
1346 check_token(P, TOK_CLOSE_PAREN, "",
1347 "invalid pack directive on line %d",
1351 cp_error("invalid pack directive on line %d",
1355 } else if (tok.type != TOK_TOKEN) {
1356 cp_error("unexpected character on line %d", P->line);
1358 } else if (IS_LITERAL(tok, "__extension__")) {
1361 } else if (IS_LITERAL(tok, "extern")) {
1362 /* ignore extern as data and functions can only be
1365 } else if (IS_LITERAL(tok, "typedef")) {
1367 } else if (IS_LITERAL(tok, "static")) {
1368 /*@TODO we haven't tested static so far */
1369 cp_error("TODO: support static keyword.\n");
1371 /* type declaration, type definition, or function
1373 struct cp_ctype type;
1375 struct parser asmname;
1377 memset(&name, 0, sizeof(name));
1378 memset(&asmname, 0, sizeof(asmname));
1381 parse_type(P, &type);
1384 parse_argument(P, &type, &name, &asmname);
1387 /* global/function declaration */
1388 cp_symbol_build_func(&type, name.str, name.size);
1389 /* @TODO asmname is not used for now
1390 * since we are not supporting __asm__
1392 * might need to bind it with function
1395 /* type declaration/definition -
1396 * already been processed */
1398 require_token(P, &tok);
1400 if (tok.type == TOK_SEMICOLON) {
1402 } else if (tok.type != TOK_COMMA) {
1403 cp_error("missing semicolon on line %d",
1413 static int64_t calculate_constant2(struct parser *P, struct token *tok);
1416 static int64_t calculate_constant1(struct parser *P, struct token *tok)
1420 if (tok->type == TOK_NUMBER) {
1425 } else if (tok->type == TOK_TOKEN) {
1426 /* look up name in constants table */
1427 cp_error("TODO: support name lookup in constant table\n");
1431 } else if (tok->type == TOK_OPEN_PAREN) {
1432 struct parser before_cast = *P;
1433 cp_error("TODO: handle open parent token in constant1\n");
1435 ret = calculate_constant(P);
1437 require_token(P, tok);
1438 if (tok->type != TOK_CLOSE_PAREN) {
1439 cp_error("error whilst parsing constant at line %d",
1446 cp_error("unexpected token whilst parsing constant at line %d",
1452 /* ! and ~, unary + and -, and sizeof */
1453 static int64_t calculate_constant2(struct parser *P, struct token *tok)
1455 if (tok->type == TOK_LOGICAL_NOT) {
1456 require_token(P, tok);
1457 return !calculate_constant2(P, tok);
1459 } else if (tok->type == TOK_BITWISE_NOT) {
1460 require_token(P, tok);
1461 return ~calculate_constant2(P, tok);
1463 } else if (tok->type == TOK_PLUS) {
1464 require_token(P, tok);
1465 return calculate_constant2(P, tok);
1467 } else if (tok->type == TOK_MINUS) {
1468 require_token(P, tok);
1469 return -calculate_constant2(P, tok);
1471 } else if (tok->type == TOK_TOKEN &&
1472 (IS_LITERAL(*tok, "sizeof")
1473 || IS_LITERAL(*tok, "alignof")
1474 || IS_LITERAL(*tok, "__alignof__")
1475 || IS_LITERAL(*tok, "__alignof"))) {
1476 cp_error("TODO: support sizeof\n");
1477 bool issize = IS_LITERAL(*tok, "sizeof");
1478 struct cp_ctype type;
1480 require_token(P, tok);
1481 if (tok->type != TOK_OPEN_PAREN) {
1482 cp_error("invalid sizeof at line %d", P->line);
1485 parse_type(P, &type);
1486 parse_argument(P, &type, NULL, NULL);
1488 require_token(P, tok);
1489 if (tok->type != TOK_CLOSE_PAREN) {
1490 cp_error("invalid sizeof at line %d", P->line);
1495 return issize ? ctype_size(&type) : type.align_mask + 1;
1498 return calculate_constant1(P, tok);
1502 /* binary * / and % (left associative) */
1503 static int64_t calculate_constant3(struct parser *P, struct token *tok)
1505 int64_t left = calculate_constant2(P, tok);
1508 if (tok->type == TOK_MULTIPLY) {
1509 require_token(P, tok);
1510 left *= calculate_constant2(P, tok);
1512 } else if (tok->type == TOK_DIVIDE) {
1513 require_token(P, tok);
1514 left /= calculate_constant2(P, tok);
1516 } else if (tok->type == TOK_MODULUS) {
1517 require_token(P, tok);
1518 left %= calculate_constant2(P, tok);
1526 /* binary + and - (left associative) */
1527 static int64_t calculate_constant4(struct parser *P, struct token *tok)
1529 int64_t left = calculate_constant3(P, tok);
1532 if (tok->type == TOK_PLUS) {
1533 require_token(P, tok);
1534 left += calculate_constant3(P, tok);
1536 } else if (tok->type == TOK_MINUS) {
1537 require_token(P, tok);
1538 left -= calculate_constant3(P, tok);
1546 /* binary << and >> (left associative) */
1547 static int64_t calculate_constant5(struct parser *P, struct token *tok)
1549 int64_t left = calculate_constant4(P, tok);
1552 if (tok->type == TOK_LEFT_SHIFT) {
1553 require_token(P, tok);
1554 left <<= calculate_constant4(P, tok);
1556 } else if (tok->type == TOK_RIGHT_SHIFT) {
1557 require_token(P, tok);
1558 left >>= calculate_constant4(P, tok);
1566 /* binary <, <=, >, and >= (left associative) */
1567 static int64_t calculate_constant6(struct parser *P, struct token *tok)
1569 int64_t left = calculate_constant5(P, tok);
1572 if (tok->type == TOK_LESS) {
1573 require_token(P, tok);
1574 left = (left < calculate_constant5(P, tok));
1576 } else if (tok->type == TOK_LESS_EQUAL) {
1577 require_token(P, tok);
1578 left = (left <= calculate_constant5(P, tok));
1580 } else if (tok->type == TOK_GREATER) {
1581 require_token(P, tok);
1582 left = (left > calculate_constant5(P, tok));
1584 } else if (tok->type == TOK_GREATER_EQUAL) {
1585 require_token(P, tok);
1586 left = (left >= calculate_constant5(P, tok));
1594 /* binary ==, != (left associative) */
1595 static int64_t calculate_constant7(struct parser *P, struct token *tok)
1597 int64_t left = calculate_constant6(P, tok);
1600 if (tok->type == TOK_EQUAL) {
1601 require_token(P, tok);
1602 left = (left == calculate_constant6(P, tok));
1604 } else if (tok->type == TOK_NOT_EQUAL) {
1605 require_token(P, tok);
1606 left = (left != calculate_constant6(P, tok));
1614 /* binary & (left associative) */
1615 static int64_t calculate_constant8(struct parser *P, struct token *tok)
1617 int64_t left = calculate_constant7(P, tok);
1620 if (tok->type == TOK_BITWISE_AND) {
1621 require_token(P, tok);
1622 left = (left & calculate_constant7(P, tok));
1630 /* binary ^ (left associative) */
1631 static int64_t calculate_constant9(struct parser *P, struct token *tok)
1633 int64_t left = calculate_constant8(P, tok);
1636 if (tok->type == TOK_BITWISE_XOR) {
1637 require_token(P, tok);
1638 left = (left ^ calculate_constant8(P, tok));
1646 /* binary | (left associative) */
1647 static int64_t calculate_constant10(struct parser *P, struct token *tok)
1649 int64_t left = calculate_constant9(P, tok);
1652 if (tok->type == TOK_BITWISE_OR) {
1653 require_token(P, tok);
1654 left = (left | calculate_constant9(P, tok));
1662 /* binary && (left associative) */
1663 static int64_t calculate_constant11(struct parser *P, struct token *tok)
1665 int64_t left = calculate_constant10(P, tok);
1668 if (tok->type == TOK_LOGICAL_AND) {
1669 require_token(P, tok);
1670 left = (left && calculate_constant10(P, tok));
1678 /* binary || (left associative) */
1679 static int64_t calculate_constant12(struct parser *P, struct token *tok)
1681 int64_t left = calculate_constant11(P, tok);
1684 if (tok->type == TOK_LOGICAL_OR) {
1685 require_token(P, tok);
1686 left = (left || calculate_constant11(P, tok));
1694 /* ternary ?: (right associative) */
1695 static int64_t calculate_constant13(struct parser *P, struct token *tok)
1697 int64_t left = calculate_constant12(P, tok);
1699 if (tok->type == TOK_QUESTION) {
1700 int64_t middle, right;
1701 require_token(P, tok);
1702 middle = calculate_constant13(P, tok);
1703 if (tok->type != TOK_COLON) {
1704 cp_error("invalid ternery (? :) in constant on line %d",
1707 require_token(P, tok);
1708 right = calculate_constant13(P, tok);
1709 return left ? middle : right;
1716 int64_t calculate_constant(struct parser* P)
1720 require_token(P, &tok);
1721 ret = calculate_constant13(P, &tok);
1723 if (tok.type != TOK_NIL) {
1730 int ffi_cdef(const char *s)
1734 memset(&P, 0, sizeof(struct parser));
1736 P.prev = P.next = s;
1737 P.align_mask = DEFAULT_ALIGN_MASK;
1739 if (parse_root(&P) == PRAGMA_POP) {
1740 cp_error("pragma pop without an associated push on line %d",
1747 void ffi_cparser_init(void)
1752 void ffi_cparser_free(void)