Mercurial
comparison third_party/luajit/src/lj_cparse.c @ 178:94705b5986b3
[ThirdParty] Added WRK and luajit for load testing.
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Thu, 22 Jan 2026 20:10:30 -0800 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 177:24fe8ff94056 | 178:94705b5986b3 |
|---|---|
| 1 /* | |
| 2 ** C declaration parser. | |
| 3 ** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h | |
| 4 */ | |
| 5 | |
| 6 #include "lj_obj.h" | |
| 7 | |
| 8 #if LJ_HASFFI | |
| 9 | |
| 10 #include "lj_gc.h" | |
| 11 #include "lj_err.h" | |
| 12 #include "lj_buf.h" | |
| 13 #include "lj_ctype.h" | |
| 14 #include "lj_cparse.h" | |
| 15 #include "lj_frame.h" | |
| 16 #include "lj_vm.h" | |
| 17 #include "lj_char.h" | |
| 18 #include "lj_strscan.h" | |
| 19 #include "lj_strfmt.h" | |
| 20 | |
| 21 /* | |
| 22 ** Important note: this is NOT a validating C parser! This is a minimal | |
| 23 ** C declaration parser, solely for use by the LuaJIT FFI. | |
| 24 ** | |
| 25 ** It ought to return correct results for properly formed C declarations, | |
| 26 ** but it may accept some invalid declarations, too (and return nonsense). | |
| 27 ** Also, it shows rather generic error messages to avoid unnecessary bloat. | |
| 28 ** If in doubt, please check the input against your favorite C compiler. | |
| 29 */ | |
| 30 | |
| 31 #ifdef LUA_USE_ASSERT | |
| 32 #define lj_assertCP(c, ...) (lj_assertG_(G(cp->L), (c), __VA_ARGS__)) | |
| 33 #else | |
| 34 #define lj_assertCP(c, ...) ((void)cp) | |
| 35 #endif | |
| 36 | |
| 37 /* -- Miscellaneous ------------------------------------------------------- */ | |
| 38 | |
| 39 /* Match string against a C literal. */ | |
| 40 #define cp_str_is(str, k) \ | |
| 41 ((str)->len == sizeof(k)-1 && !memcmp(strdata(str), k, sizeof(k)-1)) | |
| 42 | |
| 43 /* Check string against a linear list of matches. */ | |
| 44 int lj_cparse_case(GCstr *str, const char *match) | |
| 45 { | |
| 46 MSize len; | |
| 47 int n; | |
| 48 for (n = 0; (len = (MSize)*match++); n++, match += len) { | |
| 49 if (str->len == len && !memcmp(match, strdata(str), len)) | |
| 50 return n; | |
| 51 } | |
| 52 return -1; | |
| 53 } | |
| 54 | |
| 55 /* -- C lexer ------------------------------------------------------------- */ | |
| 56 | |
| 57 /* C lexer token names. */ | |
| 58 static const char *const ctoknames[] = { | |
| 59 #define CTOKSTR(name, str) str, | |
| 60 CTOKDEF(CTOKSTR) | |
| 61 #undef CTOKSTR | |
| 62 NULL | |
| 63 }; | |
| 64 | |
| 65 /* Forward declaration. */ | |
| 66 LJ_NORET static void cp_err(CPState *cp, ErrMsg em); | |
| 67 | |
| 68 static const char *cp_tok2str(CPState *cp, CPToken tok) | |
| 69 { | |
| 70 lj_assertCP(tok < CTOK_FIRSTDECL, "bad CPToken %d", tok); | |
| 71 if (tok > CTOK_OFS) | |
| 72 return ctoknames[tok-CTOK_OFS-1]; | |
| 73 else if (!lj_char_iscntrl(tok)) | |
| 74 return lj_strfmt_pushf(cp->L, "%c", tok); | |
| 75 else | |
| 76 return lj_strfmt_pushf(cp->L, "char(%d)", tok); | |
| 77 } | |
| 78 | |
| 79 /* End-of-line? */ | |
| 80 static LJ_AINLINE int cp_iseol(CPChar c) | |
| 81 { | |
| 82 return (c == '\n' || c == '\r'); | |
| 83 } | |
| 84 | |
| 85 /* Peek next raw character. */ | |
| 86 static LJ_AINLINE CPChar cp_rawpeek(CPState *cp) | |
| 87 { | |
| 88 return (CPChar)(uint8_t)(*cp->p); | |
| 89 } | |
| 90 | |
| 91 static LJ_NOINLINE CPChar cp_get_bs(CPState *cp); | |
| 92 | |
| 93 /* Get next character. */ | |
| 94 static LJ_AINLINE CPChar cp_get(CPState *cp) | |
| 95 { | |
| 96 cp->c = (CPChar)(uint8_t)(*cp->p++); | |
| 97 if (LJ_LIKELY(cp->c != '\\')) return cp->c; | |
| 98 return cp_get_bs(cp); | |
| 99 } | |
| 100 | |
| 101 /* Transparently skip backslash-escaped line breaks. */ | |
| 102 static LJ_NOINLINE CPChar cp_get_bs(CPState *cp) | |
| 103 { | |
| 104 CPChar c2, c = cp_rawpeek(cp); | |
| 105 if (!cp_iseol(c)) return cp->c; | |
| 106 cp->p++; | |
| 107 c2 = cp_rawpeek(cp); | |
| 108 if (cp_iseol(c2) && c2 != c) cp->p++; | |
| 109 cp->linenumber++; | |
| 110 return cp_get(cp); | |
| 111 } | |
| 112 | |
| 113 /* Save character in buffer. */ | |
| 114 static LJ_AINLINE void cp_save(CPState *cp, CPChar c) | |
| 115 { | |
| 116 lj_buf_putb(&cp->sb, c); | |
| 117 } | |
| 118 | |
| 119 /* Skip line break. Handles "\n", "\r", "\r\n" or "\n\r". */ | |
| 120 static void cp_newline(CPState *cp) | |
| 121 { | |
| 122 CPChar c = cp_rawpeek(cp); | |
| 123 if (cp_iseol(c) && c != cp->c) cp->p++; | |
| 124 cp->linenumber++; | |
| 125 } | |
| 126 | |
| 127 LJ_NORET static void cp_errmsg(CPState *cp, CPToken tok, ErrMsg em, ...) | |
| 128 { | |
| 129 const char *msg, *tokstr; | |
| 130 lua_State *L; | |
| 131 va_list argp; | |
| 132 if (tok == 0) { | |
| 133 tokstr = NULL; | |
| 134 } else if (tok == CTOK_IDENT || tok == CTOK_INTEGER || tok == CTOK_STRING || | |
| 135 tok >= CTOK_FIRSTDECL) { | |
| 136 if (cp->sb.w == cp->sb.b) cp_save(cp, '$'); | |
| 137 cp_save(cp, '\0'); | |
| 138 tokstr = cp->sb.b; | |
| 139 } else { | |
| 140 tokstr = cp_tok2str(cp, tok); | |
| 141 } | |
| 142 L = cp->L; | |
| 143 va_start(argp, em); | |
| 144 msg = lj_strfmt_pushvf(L, err2msg(em), argp); | |
| 145 va_end(argp); | |
| 146 if (tokstr) | |
| 147 msg = lj_strfmt_pushf(L, err2msg(LJ_ERR_XNEAR), msg, tokstr); | |
| 148 if (cp->linenumber > 1) | |
| 149 msg = lj_strfmt_pushf(L, "%s at line %d", msg, cp->linenumber); | |
| 150 lj_err_callermsg(L, msg); | |
| 151 } | |
| 152 | |
| 153 LJ_NORET LJ_NOINLINE static void cp_err_token(CPState *cp, CPToken tok) | |
| 154 { | |
| 155 cp_errmsg(cp, cp->tok, LJ_ERR_XTOKEN, cp_tok2str(cp, tok)); | |
| 156 } | |
| 157 | |
| 158 LJ_NORET LJ_NOINLINE static void cp_err_badidx(CPState *cp, CType *ct) | |
| 159 { | |
| 160 GCstr *s = lj_ctype_repr(cp->cts->L, ctype_typeid(cp->cts, ct), NULL); | |
| 161 cp_errmsg(cp, 0, LJ_ERR_FFI_BADIDX, strdata(s)); | |
| 162 } | |
| 163 | |
| 164 LJ_NORET LJ_NOINLINE static void cp_err(CPState *cp, ErrMsg em) | |
| 165 { | |
| 166 cp_errmsg(cp, 0, em); | |
| 167 } | |
| 168 | |
| 169 /* -- Main lexical scanner ------------------------------------------------ */ | |
| 170 | |
| 171 /* Parse number literal. Only handles int32_t/uint32_t right now. */ | |
| 172 static CPToken cp_number(CPState *cp) | |
| 173 { | |
| 174 StrScanFmt fmt; | |
| 175 TValue o; | |
| 176 do { cp_save(cp, cp->c); } while (lj_char_isident(cp_get(cp))); | |
| 177 cp_save(cp, '\0'); | |
| 178 fmt = lj_strscan_scan((const uint8_t *)(cp->sb.b), sbuflen(&cp->sb)-1, | |
| 179 &o, STRSCAN_OPT_C); | |
| 180 if (fmt == STRSCAN_INT) cp->val.id = CTID_INT32; | |
| 181 else if (fmt == STRSCAN_U32) cp->val.id = CTID_UINT32; | |
| 182 else if (!(cp->mode & CPARSE_MODE_SKIP)) | |
| 183 cp_errmsg(cp, CTOK_INTEGER, LJ_ERR_XNUMBER); | |
| 184 cp->val.u32 = (uint32_t)o.i; | |
| 185 return CTOK_INTEGER; | |
| 186 } | |
| 187 | |
| 188 /* Parse identifier or keyword. */ | |
| 189 static CPToken cp_ident(CPState *cp) | |
| 190 { | |
| 191 do { cp_save(cp, cp->c); } while (lj_char_isident(cp_get(cp))); | |
| 192 cp->str = lj_buf_str(cp->L, &cp->sb); | |
| 193 cp->val.id = lj_ctype_getname(cp->cts, &cp->ct, cp->str, cp->tmask); | |
| 194 if (ctype_type(cp->ct->info) == CT_KW) | |
| 195 return ctype_cid(cp->ct->info); | |
| 196 return CTOK_IDENT; | |
| 197 } | |
| 198 | |
| 199 /* Parse parameter. */ | |
| 200 static CPToken cp_param(CPState *cp) | |
| 201 { | |
| 202 CPChar c = cp_get(cp); | |
| 203 TValue *o = cp->param; | |
| 204 if (lj_char_isident(c) || c == '$') /* Reserve $xyz for future extensions. */ | |
| 205 cp_errmsg(cp, c, LJ_ERR_XSYNTAX); | |
| 206 if (!o || o >= cp->L->top) | |
| 207 cp_err(cp, LJ_ERR_FFI_NUMPARAM); | |
| 208 cp->param = o+1; | |
| 209 if (tvisstr(o)) { | |
| 210 cp->str = strV(o); | |
| 211 cp->val.id = 0; | |
| 212 cp->ct = &cp->cts->tab[0]; | |
| 213 return CTOK_IDENT; | |
| 214 } else if (tvisnumber(o)) { | |
| 215 cp->val.i32 = numberVint(o); | |
| 216 cp->val.id = CTID_INT32; | |
| 217 return CTOK_INTEGER; | |
| 218 } else { | |
| 219 GCcdata *cd; | |
| 220 if (!tviscdata(o)) | |
| 221 lj_err_argtype(cp->L, (int)(o-cp->L->base)+1, "type parameter"); | |
| 222 cd = cdataV(o); | |
| 223 if (cd->ctypeid == CTID_CTYPEID) | |
| 224 cp->val.id = *(CTypeID *)cdataptr(cd); | |
| 225 else | |
| 226 cp->val.id = cd->ctypeid; | |
| 227 return '$'; | |
| 228 } | |
| 229 } | |
| 230 | |
| 231 /* Parse string or character constant. */ | |
| 232 static CPToken cp_string(CPState *cp) | |
| 233 { | |
| 234 CPChar delim = cp->c; | |
| 235 cp_get(cp); | |
| 236 while (cp->c != delim) { | |
| 237 CPChar c = cp->c; | |
| 238 if (c == '\0') cp_errmsg(cp, CTOK_EOF, LJ_ERR_XSTR); | |
| 239 if (c == '\\') { | |
| 240 c = cp_get(cp); | |
| 241 switch (c) { | |
| 242 case '\0': cp_errmsg(cp, CTOK_EOF, LJ_ERR_XSTR); break; | |
| 243 case 'a': c = '\a'; break; | |
| 244 case 'b': c = '\b'; break; | |
| 245 case 'f': c = '\f'; break; | |
| 246 case 'n': c = '\n'; break; | |
| 247 case 'r': c = '\r'; break; | |
| 248 case 't': c = '\t'; break; | |
| 249 case 'v': c = '\v'; break; | |
| 250 case 'e': c = 27; break; | |
| 251 case 'x': | |
| 252 c = 0; | |
| 253 while (lj_char_isxdigit(cp_get(cp))) | |
| 254 c = (c<<4) + (lj_char_isdigit(cp->c) ? cp->c-'0' : (cp->c&15)+9); | |
| 255 cp_save(cp, (c & 0xff)); | |
| 256 continue; | |
| 257 default: | |
| 258 if (lj_char_isdigit(c)) { | |
| 259 c -= '0'; | |
| 260 if (lj_char_isdigit(cp_get(cp))) { | |
| 261 c = c*8 + (cp->c - '0'); | |
| 262 if (lj_char_isdigit(cp_get(cp))) { | |
| 263 c = c*8 + (cp->c - '0'); | |
| 264 cp_get(cp); | |
| 265 } | |
| 266 } | |
| 267 cp_save(cp, (c & 0xff)); | |
| 268 continue; | |
| 269 } | |
| 270 break; | |
| 271 } | |
| 272 } | |
| 273 cp_save(cp, c); | |
| 274 cp_get(cp); | |
| 275 } | |
| 276 cp_get(cp); | |
| 277 if (delim == '"') { | |
| 278 cp->str = lj_buf_str(cp->L, &cp->sb); | |
| 279 return CTOK_STRING; | |
| 280 } else { | |
| 281 if (sbuflen(&cp->sb) != 1) cp_err_token(cp, '\''); | |
| 282 cp->val.i32 = (int32_t)(char)*cp->sb.b; | |
| 283 cp->val.id = CTID_INT32; | |
| 284 return CTOK_INTEGER; | |
| 285 } | |
| 286 } | |
| 287 | |
| 288 /* Skip C comment. */ | |
| 289 static void cp_comment_c(CPState *cp) | |
| 290 { | |
| 291 do { | |
| 292 if (cp_get(cp) == '*') { | |
| 293 do { | |
| 294 if (cp_get(cp) == '/') { cp_get(cp); return; } | |
| 295 } while (cp->c == '*'); | |
| 296 } | |
| 297 if (cp_iseol(cp->c)) cp_newline(cp); | |
| 298 } while (cp->c != '\0'); | |
| 299 } | |
| 300 | |
| 301 /* Skip C++ comment. */ | |
| 302 static void cp_comment_cpp(CPState *cp) | |
| 303 { | |
| 304 while (!cp_iseol(cp_get(cp)) && cp->c != '\0') | |
| 305 ; | |
| 306 } | |
| 307 | |
| 308 /* Lexical scanner for C. Only a minimal subset is implemented. */ | |
| 309 static CPToken cp_next_(CPState *cp) | |
| 310 { | |
| 311 lj_buf_reset(&cp->sb); | |
| 312 for (;;) { | |
| 313 if (lj_char_isident(cp->c)) | |
| 314 return lj_char_isdigit(cp->c) ? cp_number(cp) : cp_ident(cp); | |
| 315 switch (cp->c) { | |
| 316 case '\n': case '\r': cp_newline(cp); /* fallthrough. */ | |
| 317 case ' ': case '\t': case '\v': case '\f': cp_get(cp); break; | |
| 318 case '"': case '\'': return cp_string(cp); | |
| 319 case '/': | |
| 320 if (cp_get(cp) == '*') cp_comment_c(cp); | |
| 321 else if (cp->c == '/') cp_comment_cpp(cp); | |
| 322 else return '/'; | |
| 323 break; | |
| 324 case '|': | |
| 325 if (cp_get(cp) != '|') return '|'; | |
| 326 cp_get(cp); return CTOK_OROR; | |
| 327 case '&': | |
| 328 if (cp_get(cp) != '&') return '&'; | |
| 329 cp_get(cp); return CTOK_ANDAND; | |
| 330 case '=': | |
| 331 if (cp_get(cp) != '=') return '='; | |
| 332 cp_get(cp); return CTOK_EQ; | |
| 333 case '!': | |
| 334 if (cp_get(cp) != '=') return '!'; | |
| 335 cp_get(cp); return CTOK_NE; | |
| 336 case '<': | |
| 337 if (cp_get(cp) == '=') { cp_get(cp); return CTOK_LE; } | |
| 338 else if (cp->c == '<') { cp_get(cp); return CTOK_SHL; } | |
| 339 return '<'; | |
| 340 case '>': | |
| 341 if (cp_get(cp) == '=') { cp_get(cp); return CTOK_GE; } | |
| 342 else if (cp->c == '>') { cp_get(cp); return CTOK_SHR; } | |
| 343 return '>'; | |
| 344 case '-': | |
| 345 if (cp_get(cp) != '>') return '-'; | |
| 346 cp_get(cp); return CTOK_DEREF; | |
| 347 case '$': | |
| 348 return cp_param(cp); | |
| 349 case '\0': return CTOK_EOF; | |
| 350 default: { CPToken c = cp->c; cp_get(cp); return c; } | |
| 351 } | |
| 352 } | |
| 353 } | |
| 354 | |
| 355 static LJ_NOINLINE CPToken cp_next(CPState *cp) | |
| 356 { | |
| 357 return (cp->tok = cp_next_(cp)); | |
| 358 } | |
| 359 | |
| 360 /* -- C parser ------------------------------------------------------------ */ | |
| 361 | |
| 362 /* Namespaces for resolving identifiers. */ | |
| 363 #define CPNS_DEFAULT \ | |
| 364 ((1u<<CT_KW)|(1u<<CT_TYPEDEF)|(1u<<CT_FUNC)|(1u<<CT_EXTERN)|(1u<<CT_CONSTVAL)) | |
| 365 #define CPNS_STRUCT ((1u<<CT_KW)|(1u<<CT_STRUCT)|(1u<<CT_ENUM)) | |
| 366 | |
| 367 typedef CTypeID CPDeclIdx; /* Index into declaration stack. */ | |
| 368 typedef uint32_t CPscl; /* Storage class flags. */ | |
| 369 | |
| 370 /* Type declaration context. */ | |
| 371 typedef struct CPDecl { | |
| 372 CPDeclIdx top; /* Top of declaration stack. */ | |
| 373 CPDeclIdx pos; /* Insertion position in declaration chain. */ | |
| 374 CPDeclIdx specpos; /* Saved position for declaration specifier. */ | |
| 375 uint32_t mode; /* Declarator mode. */ | |
| 376 CPState *cp; /* C parser state. */ | |
| 377 GCstr *name; /* Name of declared identifier (if direct). */ | |
| 378 GCstr *redir; /* Redirected symbol name. */ | |
| 379 CTypeID nameid; /* Existing typedef for declared identifier. */ | |
| 380 CTInfo attr; /* Attributes. */ | |
| 381 CTInfo fattr; /* Function attributes. */ | |
| 382 CTInfo specattr; /* Saved attributes. */ | |
| 383 CTInfo specfattr; /* Saved function attributes. */ | |
| 384 CTSize bits; /* Field size in bits (if any). */ | |
| 385 CType stack[CPARSE_MAX_DECLSTACK]; /* Type declaration stack. */ | |
| 386 } CPDecl; | |
| 387 | |
| 388 /* Forward declarations. */ | |
| 389 static CPscl cp_decl_spec(CPState *cp, CPDecl *decl, CPscl scl); | |
| 390 static void cp_declarator(CPState *cp, CPDecl *decl); | |
| 391 static CTypeID cp_decl_abstract(CPState *cp); | |
| 392 | |
| 393 /* Initialize C parser state. Caller must set up: L, p, srcname, mode. */ | |
| 394 static void cp_init(CPState *cp) | |
| 395 { | |
| 396 cp->linenumber = 1; | |
| 397 cp->depth = 0; | |
| 398 cp->curpack = 0; | |
| 399 cp->packstack[0] = 255; | |
| 400 lj_buf_init(cp->L, &cp->sb); | |
| 401 lj_assertCP(cp->p != NULL, "uninitialized cp->p"); | |
| 402 cp_get(cp); /* Read-ahead first char. */ | |
| 403 cp->tok = 0; | |
| 404 cp->tmask = CPNS_DEFAULT; | |
| 405 cp_next(cp); /* Read-ahead first token. */ | |
| 406 } | |
| 407 | |
| 408 /* Cleanup C parser state. */ | |
| 409 static void cp_cleanup(CPState *cp) | |
| 410 { | |
| 411 global_State *g = G(cp->L); | |
| 412 lj_buf_free(g, &cp->sb); | |
| 413 } | |
| 414 | |
| 415 /* Check and consume optional token. */ | |
| 416 static int cp_opt(CPState *cp, CPToken tok) | |
| 417 { | |
| 418 if (cp->tok == tok) { cp_next(cp); return 1; } | |
| 419 return 0; | |
| 420 } | |
| 421 | |
| 422 /* Check and consume token. */ | |
| 423 static void cp_check(CPState *cp, CPToken tok) | |
| 424 { | |
| 425 if (cp->tok != tok) cp_err_token(cp, tok); | |
| 426 cp_next(cp); | |
| 427 } | |
| 428 | |
| 429 /* Check if the next token may start a type declaration. */ | |
| 430 static int cp_istypedecl(CPState *cp) | |
| 431 { | |
| 432 if (cp->tok >= CTOK_FIRSTDECL && cp->tok <= CTOK_LASTDECL) return 1; | |
| 433 if (cp->tok == CTOK_IDENT && ctype_istypedef(cp->ct->info)) return 1; | |
| 434 if (cp->tok == '$') return 1; | |
| 435 return 0; | |
| 436 } | |
| 437 | |
| 438 /* -- Constant expression evaluator --------------------------------------- */ | |
| 439 | |
| 440 /* Forward declarations. */ | |
| 441 static void cp_expr_unary(CPState *cp, CPValue *k); | |
| 442 static void cp_expr_sub(CPState *cp, CPValue *k, int pri); | |
| 443 | |
| 444 /* Please note that type handling is very weak here. Most ops simply | |
| 445 ** assume integer operands. Accessors are only needed to compute types and | |
| 446 ** return synthetic values. The only purpose of the expression evaluator | |
| 447 ** is to compute the values of constant expressions one would typically | |
| 448 ** find in C header files. And again: this is NOT a validating C parser! | |
| 449 */ | |
| 450 | |
| 451 /* Parse comma separated expression and return last result. */ | |
| 452 static void cp_expr_comma(CPState *cp, CPValue *k) | |
| 453 { | |
| 454 do { cp_expr_sub(cp, k, 0); } while (cp_opt(cp, ',')); | |
| 455 } | |
| 456 | |
| 457 /* Parse sizeof/alignof operator. */ | |
| 458 static void cp_expr_sizeof(CPState *cp, CPValue *k, int wantsz) | |
| 459 { | |
| 460 CTSize sz; | |
| 461 CTInfo info; | |
| 462 if (cp_opt(cp, '(')) { | |
| 463 if (cp_istypedecl(cp)) | |
| 464 k->id = cp_decl_abstract(cp); | |
| 465 else | |
| 466 cp_expr_comma(cp, k); | |
| 467 cp_check(cp, ')'); | |
| 468 } else { | |
| 469 cp_expr_unary(cp, k); | |
| 470 } | |
| 471 info = lj_ctype_info_raw(cp->cts, k->id, &sz); | |
| 472 if (wantsz) { | |
| 473 if (sz != CTSIZE_INVALID) | |
| 474 k->u32 = sz; | |
| 475 else if (k->id != CTID_A_CCHAR) /* Special case for sizeof("string"). */ | |
| 476 cp_err(cp, LJ_ERR_FFI_INVSIZE); | |
| 477 } else { | |
| 478 k->u32 = 1u << ctype_align(info); | |
| 479 } | |
| 480 k->id = CTID_UINT32; /* Really size_t. */ | |
| 481 } | |
| 482 | |
| 483 /* Parse prefix operators. */ | |
| 484 static void cp_expr_prefix(CPState *cp, CPValue *k) | |
| 485 { | |
| 486 if (cp->tok == CTOK_INTEGER) { | |
| 487 *k = cp->val; cp_next(cp); | |
| 488 } else if (cp_opt(cp, '+')) { | |
| 489 cp_expr_unary(cp, k); /* Nothing to do (well, integer promotion). */ | |
| 490 } else if (cp_opt(cp, '-')) { | |
| 491 cp_expr_unary(cp, k); k->i32 = (int32_t)(~(uint32_t)k->i32+1); | |
| 492 } else if (cp_opt(cp, '~')) { | |
| 493 cp_expr_unary(cp, k); k->i32 = ~k->i32; | |
| 494 } else if (cp_opt(cp, '!')) { | |
| 495 cp_expr_unary(cp, k); k->i32 = !k->i32; k->id = CTID_INT32; | |
| 496 } else if (cp_opt(cp, '(')) { | |
| 497 if (cp_istypedecl(cp)) { /* Cast operator. */ | |
| 498 CTypeID id = cp_decl_abstract(cp); | |
| 499 cp_check(cp, ')'); | |
| 500 cp_expr_unary(cp, k); | |
| 501 k->id = id; /* No conversion performed. */ | |
| 502 } else { /* Sub-expression. */ | |
| 503 cp_expr_comma(cp, k); | |
| 504 cp_check(cp, ')'); | |
| 505 } | |
| 506 } else if (cp_opt(cp, '*')) { /* Indirection. */ | |
| 507 CType *ct; | |
| 508 cp_expr_unary(cp, k); | |
| 509 ct = lj_ctype_rawref(cp->cts, k->id); | |
| 510 if (!ctype_ispointer(ct->info)) | |
| 511 cp_err_badidx(cp, ct); | |
| 512 k->u32 = 0; k->id = ctype_cid(ct->info); | |
| 513 } else if (cp_opt(cp, '&')) { /* Address operator. */ | |
| 514 cp_expr_unary(cp, k); | |
| 515 k->id = lj_ctype_intern(cp->cts, CTINFO(CT_PTR, CTALIGN_PTR+k->id), | |
| 516 CTSIZE_PTR); | |
| 517 } else if (cp_opt(cp, CTOK_SIZEOF)) { | |
| 518 cp_expr_sizeof(cp, k, 1); | |
| 519 } else if (cp_opt(cp, CTOK_ALIGNOF)) { | |
| 520 cp_expr_sizeof(cp, k, 0); | |
| 521 } else if (cp->tok == CTOK_IDENT) { | |
| 522 if (ctype_type(cp->ct->info) == CT_CONSTVAL) { | |
| 523 k->u32 = cp->ct->size; k->id = ctype_cid(cp->ct->info); | |
| 524 } else if (ctype_type(cp->ct->info) == CT_EXTERN) { | |
| 525 k->u32 = cp->val.id; k->id = ctype_cid(cp->ct->info); | |
| 526 } else if (ctype_type(cp->ct->info) == CT_FUNC) { | |
| 527 k->u32 = cp->val.id; k->id = cp->val.id; | |
| 528 } else { | |
| 529 goto err_expr; | |
| 530 } | |
| 531 cp_next(cp); | |
| 532 } else if (cp->tok == CTOK_STRING) { | |
| 533 CTSize sz = cp->str->len; | |
| 534 while (cp_next(cp) == CTOK_STRING) | |
| 535 sz += cp->str->len; | |
| 536 k->u32 = sz + 1; | |
| 537 k->id = CTID_A_CCHAR; | |
| 538 } else { | |
| 539 err_expr: | |
| 540 cp_errmsg(cp, cp->tok, LJ_ERR_XSYMBOL); | |
| 541 } | |
| 542 } | |
| 543 | |
| 544 /* Parse postfix operators. */ | |
| 545 static void cp_expr_postfix(CPState *cp, CPValue *k) | |
| 546 { | |
| 547 for (;;) { | |
| 548 CType *ct; | |
| 549 if (cp_opt(cp, '[')) { /* Array/pointer index. */ | |
| 550 CPValue k2; | |
| 551 cp_expr_comma(cp, &k2); | |
| 552 ct = lj_ctype_rawref(cp->cts, k->id); | |
| 553 if (!ctype_ispointer(ct->info)) { | |
| 554 ct = lj_ctype_rawref(cp->cts, k2.id); | |
| 555 if (!ctype_ispointer(ct->info)) | |
| 556 cp_err_badidx(cp, ct); | |
| 557 } | |
| 558 cp_check(cp, ']'); | |
| 559 k->u32 = 0; | |
| 560 } else if (cp->tok == '.' || cp->tok == CTOK_DEREF) { /* Struct deref. */ | |
| 561 CTSize ofs; | |
| 562 CType *fct; | |
| 563 ct = lj_ctype_rawref(cp->cts, k->id); | |
| 564 if (cp->tok == CTOK_DEREF) { | |
| 565 if (!ctype_ispointer(ct->info)) | |
| 566 cp_err_badidx(cp, ct); | |
| 567 ct = lj_ctype_rawref(cp->cts, ctype_cid(ct->info)); | |
| 568 } | |
| 569 cp_next(cp); | |
| 570 if (cp->tok != CTOK_IDENT) cp_err_token(cp, CTOK_IDENT); | |
| 571 if (!ctype_isstruct(ct->info) || ct->size == CTSIZE_INVALID || | |
| 572 !(fct = lj_ctype_getfield(cp->cts, ct, cp->str, &ofs)) || | |
| 573 ctype_isbitfield(fct->info)) { | |
| 574 GCstr *s = lj_ctype_repr(cp->cts->L, ctype_typeid(cp->cts, ct), NULL); | |
| 575 cp_errmsg(cp, 0, LJ_ERR_FFI_BADMEMBER, strdata(s), strdata(cp->str)); | |
| 576 } | |
| 577 ct = fct; | |
| 578 k->u32 = ctype_isconstval(ct->info) ? ct->size : 0; | |
| 579 cp_next(cp); | |
| 580 } else { | |
| 581 return; | |
| 582 } | |
| 583 k->id = ctype_cid(ct->info); | |
| 584 } | |
| 585 } | |
| 586 | |
| 587 /* Parse infix operators. */ | |
| 588 static void cp_expr_infix(CPState *cp, CPValue *k, int pri) | |
| 589 { | |
| 590 CPValue k2; | |
| 591 k2.u32 = 0; k2.id = 0; /* Silence the compiler. */ | |
| 592 for (;;) { | |
| 593 switch (pri) { | |
| 594 case 0: | |
| 595 if (cp_opt(cp, '?')) { | |
| 596 CPValue k3; | |
| 597 cp_expr_comma(cp, &k2); /* Right-associative. */ | |
| 598 cp_check(cp, ':'); | |
| 599 cp_expr_sub(cp, &k3, 0); | |
| 600 k->u32 = k->u32 ? k2.u32 : k3.u32; | |
| 601 k->id = k2.id > k3.id ? k2.id : k3.id; | |
| 602 continue; | |
| 603 } | |
| 604 /* fallthrough */ | |
| 605 case 1: | |
| 606 if (cp_opt(cp, CTOK_OROR)) { | |
| 607 cp_expr_sub(cp, &k2, 2); k->i32 = k->u32 || k2.u32; k->id = CTID_INT32; | |
| 608 continue; | |
| 609 } | |
| 610 /* fallthrough */ | |
| 611 case 2: | |
| 612 if (cp_opt(cp, CTOK_ANDAND)) { | |
| 613 cp_expr_sub(cp, &k2, 3); k->i32 = k->u32 && k2.u32; k->id = CTID_INT32; | |
| 614 continue; | |
| 615 } | |
| 616 /* fallthrough */ | |
| 617 case 3: | |
| 618 if (cp_opt(cp, '|')) { | |
| 619 cp_expr_sub(cp, &k2, 4); k->u32 = k->u32 | k2.u32; goto arith_result; | |
| 620 } | |
| 621 /* fallthrough */ | |
| 622 case 4: | |
| 623 if (cp_opt(cp, '^')) { | |
| 624 cp_expr_sub(cp, &k2, 5); k->u32 = k->u32 ^ k2.u32; goto arith_result; | |
| 625 } | |
| 626 /* fallthrough */ | |
| 627 case 5: | |
| 628 if (cp_opt(cp, '&')) { | |
| 629 cp_expr_sub(cp, &k2, 6); k->u32 = k->u32 & k2.u32; goto arith_result; | |
| 630 } | |
| 631 /* fallthrough */ | |
| 632 case 6: | |
| 633 if (cp_opt(cp, CTOK_EQ)) { | |
| 634 cp_expr_sub(cp, &k2, 7); k->i32 = k->u32 == k2.u32; k->id = CTID_INT32; | |
| 635 continue; | |
| 636 } else if (cp_opt(cp, CTOK_NE)) { | |
| 637 cp_expr_sub(cp, &k2, 7); k->i32 = k->u32 != k2.u32; k->id = CTID_INT32; | |
| 638 continue; | |
| 639 } | |
| 640 /* fallthrough */ | |
| 641 case 7: | |
| 642 if (cp_opt(cp, '<')) { | |
| 643 cp_expr_sub(cp, &k2, 8); | |
| 644 if (k->id == CTID_INT32 && k2.id == CTID_INT32) | |
| 645 k->i32 = k->i32 < k2.i32; | |
| 646 else | |
| 647 k->i32 = k->u32 < k2.u32; | |
| 648 k->id = CTID_INT32; | |
| 649 continue; | |
| 650 } else if (cp_opt(cp, '>')) { | |
| 651 cp_expr_sub(cp, &k2, 8); | |
| 652 if (k->id == CTID_INT32 && k2.id == CTID_INT32) | |
| 653 k->i32 = k->i32 > k2.i32; | |
| 654 else | |
| 655 k->i32 = k->u32 > k2.u32; | |
| 656 k->id = CTID_INT32; | |
| 657 continue; | |
| 658 } else if (cp_opt(cp, CTOK_LE)) { | |
| 659 cp_expr_sub(cp, &k2, 8); | |
| 660 if (k->id == CTID_INT32 && k2.id == CTID_INT32) | |
| 661 k->i32 = k->i32 <= k2.i32; | |
| 662 else | |
| 663 k->i32 = k->u32 <= k2.u32; | |
| 664 k->id = CTID_INT32; | |
| 665 continue; | |
| 666 } else if (cp_opt(cp, CTOK_GE)) { | |
| 667 cp_expr_sub(cp, &k2, 8); | |
| 668 if (k->id == CTID_INT32 && k2.id == CTID_INT32) | |
| 669 k->i32 = k->i32 >= k2.i32; | |
| 670 else | |
| 671 k->i32 = k->u32 >= k2.u32; | |
| 672 k->id = CTID_INT32; | |
| 673 continue; | |
| 674 } | |
| 675 /* fallthrough */ | |
| 676 case 8: | |
| 677 if (cp_opt(cp, CTOK_SHL)) { | |
| 678 cp_expr_sub(cp, &k2, 9); k->u32 = k->u32 << k2.u32; | |
| 679 continue; | |
| 680 } else if (cp_opt(cp, CTOK_SHR)) { | |
| 681 cp_expr_sub(cp, &k2, 9); | |
| 682 if (k->id == CTID_INT32) | |
| 683 k->i32 = k->i32 >> k2.i32; | |
| 684 else | |
| 685 k->u32 = k->u32 >> k2.u32; | |
| 686 continue; | |
| 687 } | |
| 688 /* fallthrough */ | |
| 689 case 9: | |
| 690 if (cp_opt(cp, '+')) { | |
| 691 cp_expr_sub(cp, &k2, 10); k->u32 = k->u32 + k2.u32; | |
| 692 arith_result: | |
| 693 if (k2.id > k->id) k->id = k2.id; /* Trivial promotion to unsigned. */ | |
| 694 continue; | |
| 695 } else if (cp_opt(cp, '-')) { | |
| 696 cp_expr_sub(cp, &k2, 10); k->u32 = k->u32 - k2.u32; goto arith_result; | |
| 697 } | |
| 698 /* fallthrough */ | |
| 699 case 10: | |
| 700 if (cp_opt(cp, '*')) { | |
| 701 cp_expr_unary(cp, &k2); k->u32 = k->u32 * k2.u32; goto arith_result; | |
| 702 } else if (cp_opt(cp, '/')) { | |
| 703 cp_expr_unary(cp, &k2); | |
| 704 if (k2.id > k->id) k->id = k2.id; /* Trivial promotion to unsigned. */ | |
| 705 if (k2.u32 == 0 || | |
| 706 (k->id == CTID_INT32 && k->u32 == 0x80000000u && k2.i32 == -1)) | |
| 707 cp_err(cp, LJ_ERR_BADVAL); | |
| 708 if (k->id == CTID_INT32) | |
| 709 k->i32 = k->i32 / k2.i32; | |
| 710 else | |
| 711 k->u32 = k->u32 / k2.u32; | |
| 712 continue; | |
| 713 } else if (cp_opt(cp, '%')) { | |
| 714 cp_expr_unary(cp, &k2); | |
| 715 if (k2.id > k->id) k->id = k2.id; /* Trivial promotion to unsigned. */ | |
| 716 if (k2.u32 == 0 || | |
| 717 (k->id == CTID_INT32 && k->u32 == 0x80000000u && k2.i32 == -1)) | |
| 718 cp_err(cp, LJ_ERR_BADVAL); | |
| 719 if (k->id == CTID_INT32) | |
| 720 k->i32 = k->i32 % k2.i32; | |
| 721 else | |
| 722 k->u32 = k->u32 % k2.u32; | |
| 723 continue; | |
| 724 } | |
| 725 default: | |
| 726 return; | |
| 727 } | |
| 728 } | |
| 729 } | |
| 730 | |
| 731 /* Parse and evaluate unary expression. */ | |
| 732 static void cp_expr_unary(CPState *cp, CPValue *k) | |
| 733 { | |
| 734 if (++cp->depth > CPARSE_MAX_DECLDEPTH) cp_err(cp, LJ_ERR_XLEVELS); | |
| 735 cp_expr_prefix(cp, k); | |
| 736 cp_expr_postfix(cp, k); | |
| 737 cp->depth--; | |
| 738 } | |
| 739 | |
| 740 /* Parse and evaluate sub-expression. */ | |
| 741 static void cp_expr_sub(CPState *cp, CPValue *k, int pri) | |
| 742 { | |
| 743 cp_expr_unary(cp, k); | |
| 744 cp_expr_infix(cp, k, pri); | |
| 745 } | |
| 746 | |
| 747 /* Parse constant integer expression. */ | |
| 748 static void cp_expr_kint(CPState *cp, CPValue *k) | |
| 749 { | |
| 750 CType *ct; | |
| 751 cp_expr_sub(cp, k, 0); | |
| 752 ct = ctype_raw(cp->cts, k->id); | |
| 753 if (!ctype_isinteger(ct->info)) cp_err(cp, LJ_ERR_BADVAL); | |
| 754 } | |
| 755 | |
| 756 /* Parse (non-negative) size expression. */ | |
| 757 static CTSize cp_expr_ksize(CPState *cp) | |
| 758 { | |
| 759 CPValue k; | |
| 760 cp_expr_kint(cp, &k); | |
| 761 if (k.u32 >= 0x80000000u) cp_err(cp, LJ_ERR_FFI_INVSIZE); | |
| 762 return k.u32; | |
| 763 } | |
| 764 | |
| 765 /* -- Type declaration stack management ----------------------------------- */ | |
| 766 | |
| 767 /* Add declaration element behind the insertion position. */ | |
| 768 static CPDeclIdx cp_add(CPDecl *decl, CTInfo info, CTSize size) | |
| 769 { | |
| 770 CPDeclIdx top = decl->top; | |
| 771 if (top >= CPARSE_MAX_DECLSTACK) cp_err(decl->cp, LJ_ERR_XLEVELS); | |
| 772 decl->stack[top].info = info; | |
| 773 decl->stack[top].size = size; | |
| 774 decl->stack[top].sib = 0; | |
| 775 setgcrefnull(decl->stack[top].name); | |
| 776 decl->stack[top].next = decl->stack[decl->pos].next; | |
| 777 decl->stack[decl->pos].next = (CTypeID1)top; | |
| 778 decl->top = top+1; | |
| 779 return top; | |
| 780 } | |
| 781 | |
| 782 /* Push declaration element before the insertion position. */ | |
| 783 static CPDeclIdx cp_push(CPDecl *decl, CTInfo info, CTSize size) | |
| 784 { | |
| 785 return (decl->pos = cp_add(decl, info, size)); | |
| 786 } | |
| 787 | |
| 788 /* Push or merge attributes. */ | |
| 789 static void cp_push_attributes(CPDecl *decl) | |
| 790 { | |
| 791 CType *ct = &decl->stack[decl->pos]; | |
| 792 if (ctype_isfunc(ct->info)) { /* Ok to modify in-place. */ | |
| 793 #if LJ_TARGET_X86 | |
| 794 if ((decl->fattr & CTFP_CCONV)) | |
| 795 ct->info = (ct->info & (CTMASK_NUM|CTF_VARARG|CTMASK_CID)) + | |
| 796 (decl->fattr & ~CTMASK_CID); | |
| 797 #endif | |
| 798 } else { | |
| 799 if ((decl->attr & CTFP_ALIGNED) && !(decl->mode & CPARSE_MODE_FIELD)) | |
| 800 cp_push(decl, CTINFO(CT_ATTRIB, CTATTRIB(CTA_ALIGN)), | |
| 801 ctype_align(decl->attr)); | |
| 802 } | |
| 803 } | |
| 804 | |
| 805 /* Push unrolled type to declaration stack and merge qualifiers. */ | |
| 806 static void cp_push_type(CPDecl *decl, CTypeID id) | |
| 807 { | |
| 808 CType *ct = ctype_get(decl->cp->cts, id); | |
| 809 CTInfo info = ct->info; | |
| 810 CTSize size = ct->size; | |
| 811 switch (ctype_type(info)) { | |
| 812 case CT_STRUCT: case CT_ENUM: | |
| 813 cp_push(decl, CTINFO(CT_TYPEDEF, id), 0); /* Don't copy unique types. */ | |
| 814 if ((decl->attr & CTF_QUAL)) { /* Push unmerged qualifiers. */ | |
| 815 cp_push(decl, CTINFO(CT_ATTRIB, CTATTRIB(CTA_QUAL)), | |
| 816 (decl->attr & CTF_QUAL)); | |
| 817 decl->attr &= ~CTF_QUAL; | |
| 818 } | |
| 819 break; | |
| 820 case CT_ATTRIB: | |
| 821 if (ctype_isxattrib(info, CTA_QUAL)) | |
| 822 decl->attr &= ~size; /* Remove redundant qualifiers. */ | |
| 823 cp_push_type(decl, ctype_cid(info)); /* Unroll. */ | |
| 824 cp_push(decl, info & ~CTMASK_CID, size); /* Copy type. */ | |
| 825 break; | |
| 826 case CT_ARRAY: | |
| 827 if ((ct->info & (CTF_VECTOR|CTF_COMPLEX))) { | |
| 828 info |= (decl->attr & CTF_QUAL); | |
| 829 decl->attr &= ~CTF_QUAL; | |
| 830 } | |
| 831 cp_push_type(decl, ctype_cid(info)); /* Unroll. */ | |
| 832 cp_push(decl, info & ~CTMASK_CID, size); /* Copy type. */ | |
| 833 decl->stack[decl->pos].sib = 1; /* Mark as already checked and sized. */ | |
| 834 /* Note: this is not copied to the ct->sib in the C type table. */ | |
| 835 break; | |
| 836 case CT_FUNC: | |
| 837 /* Copy type, link parameters (shared). */ | |
| 838 decl->stack[cp_push(decl, info, size)].sib = ct->sib; | |
| 839 break; | |
| 840 default: | |
| 841 /* Copy type, merge common qualifiers. */ | |
| 842 cp_push(decl, info|(decl->attr & CTF_QUAL), size); | |
| 843 decl->attr &= ~CTF_QUAL; | |
| 844 break; | |
| 845 } | |
| 846 } | |
| 847 | |
| 848 /* Consume the declaration element chain and intern the C type. */ | |
| 849 static CTypeID cp_decl_intern(CPState *cp, CPDecl *decl) | |
| 850 { | |
| 851 CTypeID id = 0; | |
| 852 CPDeclIdx idx = 0; | |
| 853 CTSize csize = CTSIZE_INVALID; | |
| 854 CTSize cinfo = 0; | |
| 855 do { | |
| 856 CType *ct = &decl->stack[idx]; | |
| 857 CTInfo info = ct->info; | |
| 858 CTInfo size = ct->size; | |
| 859 /* The cid is already part of info for copies of pointers/functions. */ | |
| 860 idx = ct->next; | |
| 861 if (ctype_istypedef(info)) { | |
| 862 lj_assertCP(id == 0, "typedef not at toplevel"); | |
| 863 id = ctype_cid(info); | |
| 864 /* Always refetch info/size, since struct/enum may have been completed. */ | |
| 865 cinfo = ctype_get(cp->cts, id)->info; | |
| 866 csize = ctype_get(cp->cts, id)->size; | |
| 867 lj_assertCP(ctype_isstruct(cinfo) || ctype_isenum(cinfo), | |
| 868 "typedef of bad type"); | |
| 869 } else if (ctype_isfunc(info)) { /* Intern function. */ | |
| 870 CType *fct; | |
| 871 CTypeID fid; | |
| 872 CTypeID sib; | |
| 873 if (id) { | |
| 874 CType *refct = ctype_raw(cp->cts, id); | |
| 875 /* Reject function or refarray return types. */ | |
| 876 if (ctype_isfunc(refct->info) || ctype_isrefarray(refct->info)) | |
| 877 cp_err(cp, LJ_ERR_FFI_INVTYPE); | |
| 878 } | |
| 879 /* No intervening attributes allowed, skip forward. */ | |
| 880 while (idx) { | |
| 881 CType *ctn = &decl->stack[idx]; | |
| 882 if (!ctype_isattrib(ctn->info)) break; | |
| 883 idx = ctn->next; /* Skip attribute. */ | |
| 884 } | |
| 885 sib = ct->sib; /* Next line may reallocate the C type table. */ | |
| 886 fid = lj_ctype_new(cp->cts, &fct); | |
| 887 csize = CTSIZE_INVALID; | |
| 888 fct->info = cinfo = info + id; | |
| 889 fct->size = size; | |
| 890 fct->sib = sib; | |
| 891 id = fid; | |
| 892 } else if (ctype_isattrib(info)) { | |
| 893 if (ctype_isxattrib(info, CTA_QUAL)) | |
| 894 cinfo |= size; | |
| 895 else if (ctype_isxattrib(info, CTA_ALIGN)) | |
| 896 CTF_INSERT(cinfo, ALIGN, size); | |
| 897 id = lj_ctype_intern(cp->cts, info+id, size); | |
| 898 /* Inherit csize/cinfo from original type. */ | |
| 899 } else { | |
| 900 if (ctype_isnum(info)) { /* Handle mode/vector-size attributes. */ | |
| 901 lj_assertCP(id == 0, "number not at toplevel"); | |
| 902 if (!(info & CTF_BOOL)) { | |
| 903 CTSize msize = ctype_msizeP(decl->attr); | |
| 904 CTSize vsize = ctype_vsizeP(decl->attr); | |
| 905 if (msize && (!(info & CTF_FP) || (msize == 4 || msize == 8))) { | |
| 906 CTSize malign = lj_fls(msize); | |
| 907 if (malign > 4) malign = 4; /* Limit alignment. */ | |
| 908 CTF_INSERT(info, ALIGN, malign); | |
| 909 size = msize; /* Override size via mode. */ | |
| 910 } | |
| 911 if (vsize) { /* Vector size set? */ | |
| 912 CTSize esize = lj_fls(size); | |
| 913 if (vsize >= esize) { | |
| 914 /* Intern the element type first. */ | |
| 915 id = lj_ctype_intern(cp->cts, info, size); | |
| 916 /* Then create a vector (array) with vsize alignment. */ | |
| 917 size = (1u << vsize); | |
| 918 if (vsize > 4) vsize = 4; /* Limit alignment. */ | |
| 919 if (ctype_align(info) > vsize) vsize = ctype_align(info); | |
| 920 info = CTINFO(CT_ARRAY, (info & CTF_QUAL) + CTF_VECTOR + | |
| 921 CTALIGN(vsize)); | |
| 922 } | |
| 923 } | |
| 924 } | |
| 925 } else if (ctype_isptr(info)) { | |
| 926 /* Reject pointer/ref to ref. */ | |
| 927 if (id && ctype_isref(ctype_raw(cp->cts, id)->info)) | |
| 928 cp_err(cp, LJ_ERR_FFI_INVTYPE); | |
| 929 if (ctype_isref(info)) { | |
| 930 info &= ~CTF_VOLATILE; /* Refs are always const, never volatile. */ | |
| 931 /* No intervening attributes allowed, skip forward. */ | |
| 932 while (idx) { | |
| 933 CType *ctn = &decl->stack[idx]; | |
| 934 if (!ctype_isattrib(ctn->info)) break; | |
| 935 idx = ctn->next; /* Skip attribute. */ | |
| 936 } | |
| 937 } | |
| 938 } else if (ctype_isarray(info)) { /* Check for valid array size etc. */ | |
| 939 if (ct->sib == 0) { /* Only check/size arrays not copied by unroll. */ | |
| 940 if (ctype_isref(cinfo)) /* Reject arrays of refs. */ | |
| 941 cp_err(cp, LJ_ERR_FFI_INVTYPE); | |
| 942 /* Reject VLS or unknown-sized types. */ | |
| 943 if (ctype_isvltype(cinfo) || csize == CTSIZE_INVALID) | |
| 944 cp_err(cp, LJ_ERR_FFI_INVSIZE); | |
| 945 /* a[] and a[?] keep their invalid size. */ | |
| 946 if (size != CTSIZE_INVALID) { | |
| 947 uint64_t xsz = (uint64_t)size * csize; | |
| 948 if (xsz >= 0x80000000u) cp_err(cp, LJ_ERR_FFI_INVSIZE); | |
| 949 size = (CTSize)xsz; | |
| 950 } | |
| 951 } | |
| 952 if ((cinfo & CTF_ALIGN) > (info & CTF_ALIGN)) /* Find max. align. */ | |
| 953 info = (info & ~CTF_ALIGN) | (cinfo & CTF_ALIGN); | |
| 954 info |= (cinfo & CTF_QUAL); /* Inherit qual. */ | |
| 955 } else { | |
| 956 lj_assertCP(ctype_isvoid(info), "bad ctype %08x", info); | |
| 957 } | |
| 958 csize = size; | |
| 959 cinfo = info+id; | |
| 960 id = lj_ctype_intern(cp->cts, info+id, size); | |
| 961 } | |
| 962 } while (idx); | |
| 963 return id; | |
| 964 } | |
| 965 | |
| 966 /* -- C declaration parser ------------------------------------------------ */ | |
| 967 | |
| 968 /* Reset declaration state to declaration specifier. */ | |
| 969 static void cp_decl_reset(CPDecl *decl) | |
| 970 { | |
| 971 decl->pos = decl->specpos; | |
| 972 decl->top = decl->specpos+1; | |
| 973 decl->stack[decl->specpos].next = 0; | |
| 974 decl->attr = decl->specattr; | |
| 975 decl->fattr = decl->specfattr; | |
| 976 decl->name = NULL; | |
| 977 decl->redir = NULL; | |
| 978 } | |
| 979 | |
| 980 /* Parse constant initializer. */ | |
| 981 /* NYI: FP constants and strings as initializers. */ | |
| 982 static CTypeID cp_decl_constinit(CPState *cp, CType **ctp, CTypeID ctypeid) | |
| 983 { | |
| 984 CType *ctt = ctype_get(cp->cts, ctypeid); | |
| 985 CTInfo info; | |
| 986 CTSize size; | |
| 987 CPValue k; | |
| 988 CTypeID constid; | |
| 989 while (ctype_isattrib(ctt->info)) { /* Skip attributes. */ | |
| 990 ctypeid = ctype_cid(ctt->info); /* Update ID, too. */ | |
| 991 ctt = ctype_get(cp->cts, ctypeid); | |
| 992 } | |
| 993 info = ctt->info; | |
| 994 size = ctt->size; | |
| 995 if (!ctype_isinteger(info) || !(info & CTF_CONST) || size > 4) | |
| 996 cp_err(cp, LJ_ERR_FFI_INVTYPE); | |
| 997 cp_check(cp, '='); | |
| 998 cp_expr_sub(cp, &k, 0); | |
| 999 constid = lj_ctype_new(cp->cts, ctp); | |
| 1000 (*ctp)->info = CTINFO(CT_CONSTVAL, CTF_CONST|ctypeid); | |
| 1001 k.u32 <<= 8*(4-size); | |
| 1002 if ((info & CTF_UNSIGNED)) | |
| 1003 k.u32 >>= 8*(4-size); | |
| 1004 else | |
| 1005 k.u32 = (uint32_t)((int32_t)k.u32 >> 8*(4-size)); | |
| 1006 (*ctp)->size = k.u32; | |
| 1007 return constid; | |
| 1008 } | |
| 1009 | |
| 1010 /* Parse size in parentheses as part of attribute. */ | |
| 1011 static CTSize cp_decl_sizeattr(CPState *cp) | |
| 1012 { | |
| 1013 CTSize sz; | |
| 1014 uint32_t oldtmask = cp->tmask; | |
| 1015 cp->tmask = CPNS_DEFAULT; /* Required for expression evaluator. */ | |
| 1016 cp_check(cp, '('); | |
| 1017 sz = cp_expr_ksize(cp); | |
| 1018 cp->tmask = oldtmask; | |
| 1019 cp_check(cp, ')'); | |
| 1020 return sz; | |
| 1021 } | |
| 1022 | |
| 1023 /* Parse alignment attribute. */ | |
| 1024 static void cp_decl_align(CPState *cp, CPDecl *decl) | |
| 1025 { | |
| 1026 CTSize al = 4; /* Unspecified alignment is 16 bytes. */ | |
| 1027 if (cp->tok == '(') { | |
| 1028 al = cp_decl_sizeattr(cp); | |
| 1029 al = al ? lj_fls(al) : 0; | |
| 1030 } | |
| 1031 CTF_INSERT(decl->attr, ALIGN, al); | |
| 1032 decl->attr |= CTFP_ALIGNED; | |
| 1033 } | |
| 1034 | |
| 1035 /* Parse GCC asm("name") redirect. */ | |
| 1036 static void cp_decl_asm(CPState *cp, CPDecl *decl) | |
| 1037 { | |
| 1038 UNUSED(decl); | |
| 1039 cp_next(cp); | |
| 1040 cp_check(cp, '('); | |
| 1041 if (cp->tok == CTOK_STRING) { | |
| 1042 GCstr *str = cp->str; | |
| 1043 while (cp_next(cp) == CTOK_STRING) { | |
| 1044 lj_strfmt_pushf(cp->L, "%s%s", strdata(str), strdata(cp->str)); | |
| 1045 cp->L->top--; | |
| 1046 str = strV(cp->L->top); | |
| 1047 } | |
| 1048 decl->redir = str; | |
| 1049 } | |
| 1050 cp_check(cp, ')'); | |
| 1051 } | |
| 1052 | |
| 1053 /* Parse GCC __attribute__((mode(...))). */ | |
| 1054 static void cp_decl_mode(CPState *cp, CPDecl *decl) | |
| 1055 { | |
| 1056 cp_check(cp, '('); | |
| 1057 if (cp->tok == CTOK_IDENT) { | |
| 1058 const char *s = strdata(cp->str); | |
| 1059 CTSize sz = 0, vlen = 0; | |
| 1060 if (s[0] == '_' && s[1] == '_') s += 2; | |
| 1061 if (*s == 'V') { | |
| 1062 s++; | |
| 1063 vlen = *s++ - '0'; | |
| 1064 if (*s >= '0' && *s <= '9') | |
| 1065 vlen = vlen*10 + (*s++ - '0'); | |
| 1066 } | |
| 1067 switch (*s++) { | |
| 1068 case 'Q': sz = 1; break; | |
| 1069 case 'H': sz = 2; break; | |
| 1070 case 'S': sz = 4; break; | |
| 1071 case 'D': sz = 8; break; | |
| 1072 case 'T': sz = 16; break; | |
| 1073 case 'O': sz = 32; break; | |
| 1074 default: goto bad_size; | |
| 1075 } | |
| 1076 if (*s == 'I' || *s == 'F') { | |
| 1077 CTF_INSERT(decl->attr, MSIZEP, sz); | |
| 1078 if (vlen) CTF_INSERT(decl->attr, VSIZEP, lj_fls(vlen*sz)); | |
| 1079 } | |
| 1080 bad_size: | |
| 1081 cp_next(cp); | |
| 1082 } | |
| 1083 cp_check(cp, ')'); | |
| 1084 } | |
| 1085 | |
| 1086 /* Parse GCC __attribute__((...)). */ | |
| 1087 static void cp_decl_gccattribute(CPState *cp, CPDecl *decl) | |
| 1088 { | |
| 1089 cp_next(cp); | |
| 1090 cp_check(cp, '('); | |
| 1091 cp_check(cp, '('); | |
| 1092 while (cp->tok != ')') { | |
| 1093 if (cp->tok == CTOK_IDENT) { | |
| 1094 GCstr *attrstr = cp->str; | |
| 1095 cp_next(cp); | |
| 1096 switch (lj_cparse_case(attrstr, | |
| 1097 "\007aligned" "\013__aligned__" | |
| 1098 "\006packed" "\012__packed__" | |
| 1099 "\004mode" "\010__mode__" | |
| 1100 "\013vector_size" "\017__vector_size__" | |
| 1101 #if LJ_TARGET_X86 | |
| 1102 "\007regparm" "\013__regparm__" | |
| 1103 "\005cdecl" "\011__cdecl__" | |
| 1104 "\010thiscall" "\014__thiscall__" | |
| 1105 "\010fastcall" "\014__fastcall__" | |
| 1106 "\007stdcall" "\013__stdcall__" | |
| 1107 "\012sseregparm" "\016__sseregparm__" | |
| 1108 #endif | |
| 1109 )) { | |
| 1110 case 0: case 1: /* aligned */ | |
| 1111 cp_decl_align(cp, decl); | |
| 1112 break; | |
| 1113 case 2: case 3: /* packed */ | |
| 1114 decl->attr |= CTFP_PACKED; | |
| 1115 break; | |
| 1116 case 4: case 5: /* mode */ | |
| 1117 cp_decl_mode(cp, decl); | |
| 1118 break; | |
| 1119 case 6: case 7: /* vector_size */ | |
| 1120 { | |
| 1121 CTSize vsize = cp_decl_sizeattr(cp); | |
| 1122 if (vsize) CTF_INSERT(decl->attr, VSIZEP, lj_fls(vsize)); | |
| 1123 } | |
| 1124 break; | |
| 1125 #if LJ_TARGET_X86 | |
| 1126 case 8: case 9: /* regparm */ | |
| 1127 CTF_INSERT(decl->fattr, REGPARM, cp_decl_sizeattr(cp)); | |
| 1128 decl->fattr |= CTFP_CCONV; | |
| 1129 break; | |
| 1130 case 10: case 11: /* cdecl */ | |
| 1131 CTF_INSERT(decl->fattr, CCONV, CTCC_CDECL); | |
| 1132 decl->fattr |= CTFP_CCONV; | |
| 1133 break; | |
| 1134 case 12: case 13: /* thiscall */ | |
| 1135 CTF_INSERT(decl->fattr, CCONV, CTCC_THISCALL); | |
| 1136 decl->fattr |= CTFP_CCONV; | |
| 1137 break; | |
| 1138 case 14: case 15: /* fastcall */ | |
| 1139 CTF_INSERT(decl->fattr, CCONV, CTCC_FASTCALL); | |
| 1140 decl->fattr |= CTFP_CCONV; | |
| 1141 break; | |
| 1142 case 16: case 17: /* stdcall */ | |
| 1143 CTF_INSERT(decl->fattr, CCONV, CTCC_STDCALL); | |
| 1144 decl->fattr |= CTFP_CCONV; | |
| 1145 break; | |
| 1146 case 18: case 19: /* sseregparm */ | |
| 1147 decl->fattr |= CTF_SSEREGPARM; | |
| 1148 decl->fattr |= CTFP_CCONV; | |
| 1149 break; | |
| 1150 #endif | |
| 1151 default: /* Skip all other attributes. */ | |
| 1152 goto skip_attr; | |
| 1153 } | |
| 1154 } else if (cp->tok >= CTOK_FIRSTDECL) { /* For __attribute((const)) etc. */ | |
| 1155 cp_next(cp); | |
| 1156 skip_attr: | |
| 1157 if (cp_opt(cp, '(')) { | |
| 1158 while (cp->tok != ')' && cp->tok != CTOK_EOF) cp_next(cp); | |
| 1159 cp_check(cp, ')'); | |
| 1160 } | |
| 1161 } else { | |
| 1162 break; | |
| 1163 } | |
| 1164 if (!cp_opt(cp, ',')) break; | |
| 1165 } | |
| 1166 cp_check(cp, ')'); | |
| 1167 cp_check(cp, ')'); | |
| 1168 } | |
| 1169 | |
| 1170 /* Parse MSVC __declspec(...). */ | |
| 1171 static void cp_decl_msvcattribute(CPState *cp, CPDecl *decl) | |
| 1172 { | |
| 1173 cp_next(cp); | |
| 1174 cp_check(cp, '('); | |
| 1175 while (cp->tok == CTOK_IDENT) { | |
| 1176 GCstr *attrstr = cp->str; | |
| 1177 cp_next(cp); | |
| 1178 if (cp_str_is(attrstr, "align")) { | |
| 1179 cp_decl_align(cp, decl); | |
| 1180 } else { /* Ignore all other attributes. */ | |
| 1181 if (cp_opt(cp, '(')) { | |
| 1182 while (cp->tok != ')' && cp->tok != CTOK_EOF) cp_next(cp); | |
| 1183 cp_check(cp, ')'); | |
| 1184 } | |
| 1185 } | |
| 1186 } | |
| 1187 cp_check(cp, ')'); | |
| 1188 } | |
| 1189 | |
| 1190 /* Parse declaration attributes (and common qualifiers). */ | |
| 1191 static void cp_decl_attributes(CPState *cp, CPDecl *decl) | |
| 1192 { | |
| 1193 for (;;) { | |
| 1194 switch (cp->tok) { | |
| 1195 case CTOK_CONST: decl->attr |= CTF_CONST; break; | |
| 1196 case CTOK_VOLATILE: decl->attr |= CTF_VOLATILE; break; | |
| 1197 case CTOK_RESTRICT: break; /* Ignore. */ | |
| 1198 case CTOK_EXTENSION: break; /* Ignore. */ | |
| 1199 case CTOK_ATTRIBUTE: cp_decl_gccattribute(cp, decl); continue; | |
| 1200 case CTOK_ASM: cp_decl_asm(cp, decl); continue; | |
| 1201 case CTOK_DECLSPEC: cp_decl_msvcattribute(cp, decl); continue; | |
| 1202 case CTOK_CCDECL: | |
| 1203 #if LJ_TARGET_X86 | |
| 1204 CTF_INSERT(decl->fattr, CCONV, cp->ct->size); | |
| 1205 decl->fattr |= CTFP_CCONV; | |
| 1206 #endif | |
| 1207 break; | |
| 1208 case CTOK_PTRSZ: | |
| 1209 #if LJ_64 | |
| 1210 CTF_INSERT(decl->attr, MSIZEP, cp->ct->size); | |
| 1211 #endif | |
| 1212 break; | |
| 1213 default: return; | |
| 1214 } | |
| 1215 cp_next(cp); | |
| 1216 } | |
| 1217 } | |
| 1218 | |
| 1219 /* Parse struct/union/enum name. */ | |
| 1220 static CTypeID cp_struct_name(CPState *cp, CPDecl *sdecl, CTInfo info) | |
| 1221 { | |
| 1222 CTypeID sid; | |
| 1223 CType *ct; | |
| 1224 cp->tmask = CPNS_STRUCT; | |
| 1225 cp_next(cp); | |
| 1226 cp_decl_attributes(cp, sdecl); | |
| 1227 cp->tmask = CPNS_DEFAULT; | |
| 1228 if (cp->tok != '{') { | |
| 1229 if (cp->tok != CTOK_IDENT) cp_err_token(cp, CTOK_IDENT); | |
| 1230 if (cp->val.id) { /* Name of existing struct/union/enum. */ | |
| 1231 sid = cp->val.id; | |
| 1232 ct = cp->ct; | |
| 1233 if ((ct->info ^ info) & (CTMASK_NUM|CTF_UNION)) /* Wrong type. */ | |
| 1234 cp_errmsg(cp, 0, LJ_ERR_FFI_REDEF, strdata(gco2str(gcref(ct->name)))); | |
| 1235 } else { /* Create named, incomplete struct/union/enum. */ | |
| 1236 if ((cp->mode & CPARSE_MODE_NOIMPLICIT)) | |
| 1237 cp_errmsg(cp, 0, LJ_ERR_FFI_BADTAG, strdata(cp->str)); | |
| 1238 sid = lj_ctype_new(cp->cts, &ct); | |
| 1239 ct->info = info; | |
| 1240 ct->size = CTSIZE_INVALID; | |
| 1241 ctype_setname(ct, cp->str); | |
| 1242 lj_ctype_addname(cp->cts, ct, sid); | |
| 1243 } | |
| 1244 cp_next(cp); | |
| 1245 } else { /* Create anonymous, incomplete struct/union/enum. */ | |
| 1246 sid = lj_ctype_new(cp->cts, &ct); | |
| 1247 ct->info = info; | |
| 1248 ct->size = CTSIZE_INVALID; | |
| 1249 } | |
| 1250 if (cp->tok == '{') { | |
| 1251 if (ct->size != CTSIZE_INVALID || ct->sib) | |
| 1252 cp_errmsg(cp, 0, LJ_ERR_FFI_REDEF, strdata(gco2str(gcref(ct->name)))); | |
| 1253 ct->sib = 1; /* Indicate the type is currently being defined. */ | |
| 1254 } | |
| 1255 return sid; | |
| 1256 } | |
| 1257 | |
| 1258 /* Determine field alignment. */ | |
| 1259 static CTSize cp_field_align(CPState *cp, CType *ct, CTInfo info) | |
| 1260 { | |
| 1261 CTSize align = ctype_align(info); | |
| 1262 UNUSED(cp); UNUSED(ct); | |
| 1263 #if (LJ_TARGET_X86 && !LJ_ABI_WIN) || (LJ_TARGET_ARM && __APPLE__) | |
| 1264 /* The SYSV i386 and iOS ABIs limit alignment of non-vector fields to 2^2. */ | |
| 1265 if (align > 2 && !(info & CTFP_ALIGNED)) { | |
| 1266 if (ctype_isarray(info) && !(info & CTF_VECTOR)) { | |
| 1267 do { | |
| 1268 ct = ctype_rawchild(cp->cts, ct); | |
| 1269 info = ct->info; | |
| 1270 } while (ctype_isarray(info) && !(info & CTF_VECTOR)); | |
| 1271 } | |
| 1272 if (ctype_isnum(info) || ctype_isenum(info)) | |
| 1273 align = 2; | |
| 1274 } | |
| 1275 #endif | |
| 1276 return align; | |
| 1277 } | |
| 1278 | |
| 1279 /* Layout struct/union fields. */ | |
| 1280 static void cp_struct_layout(CPState *cp, CTypeID sid, CTInfo sattr) | |
| 1281 { | |
| 1282 CTSize bofs = 0, bmaxofs = 0; /* Bit offset and max. bit offset. */ | |
| 1283 CTSize maxalign = ctype_align(sattr); | |
| 1284 CType *sct = ctype_get(cp->cts, sid); | |
| 1285 CTInfo sinfo = sct->info; | |
| 1286 CTypeID fieldid = sct->sib; | |
| 1287 while (fieldid) { | |
| 1288 CType *ct = ctype_get(cp->cts, fieldid); | |
| 1289 CTInfo attr = ct->size; /* Field declaration attributes (temp.). */ | |
| 1290 | |
| 1291 if (ctype_isfield(ct->info) || | |
| 1292 (ctype_isxattrib(ct->info, CTA_SUBTYPE) && attr)) { | |
| 1293 CTSize align, amask; /* Alignment (pow2) and alignment mask (bits). */ | |
| 1294 CTSize sz; | |
| 1295 CTInfo info = lj_ctype_info(cp->cts, ctype_cid(ct->info), &sz); | |
| 1296 CTSize bsz, csz = 8*sz; /* Field size and container size (in bits). */ | |
| 1297 sinfo |= (info & (CTF_QUAL|CTF_VLA)); /* Merge pseudo-qualifiers. */ | |
| 1298 | |
| 1299 /* Check for size overflow and determine alignment. */ | |
| 1300 if (sz >= 0x20000000u || bofs + csz < bofs || (info & CTF_VLA)) { | |
| 1301 if (!(sz == CTSIZE_INVALID && ctype_isarray(info) && | |
| 1302 !(sinfo & CTF_UNION))) | |
| 1303 cp_err(cp, LJ_ERR_FFI_INVSIZE); | |
| 1304 csz = sz = 0; /* Treat a[] and a[?] as zero-sized. */ | |
| 1305 } | |
| 1306 align = cp_field_align(cp, ct, info); | |
| 1307 if (((attr|sattr) & CTFP_PACKED) || | |
| 1308 ((attr & CTFP_ALIGNED) && ctype_align(attr) > align)) | |
| 1309 align = ctype_align(attr); | |
| 1310 if (cp->packstack[cp->curpack] < align) | |
| 1311 align = cp->packstack[cp->curpack]; | |
| 1312 if (align > maxalign) maxalign = align; | |
| 1313 amask = (8u << align) - 1; | |
| 1314 | |
| 1315 bsz = ctype_bitcsz(ct->info); /* Bitfield size (temp.). */ | |
| 1316 if (bsz == CTBSZ_FIELD || !ctype_isfield(ct->info)) { | |
| 1317 bsz = csz; /* Regular fields or subtypes always fill the container. */ | |
| 1318 bofs = (bofs + amask) & ~amask; /* Start new aligned field. */ | |
| 1319 ct->size = (bofs >> 3); /* Store field offset. */ | |
| 1320 } else { /* Bitfield. */ | |
| 1321 if (bsz == 0 || (attr & CTFP_ALIGNED) || | |
| 1322 (!((attr|sattr) & CTFP_PACKED) && (bofs & amask) + bsz > csz)) | |
| 1323 bofs = (bofs + amask) & ~amask; /* Start new aligned field. */ | |
| 1324 | |
| 1325 /* Prefer regular field over bitfield. */ | |
| 1326 if (bsz == csz && (bofs & amask) == 0) { | |
| 1327 ct->info = CTINFO(CT_FIELD, ctype_cid(ct->info)); | |
| 1328 ct->size = (bofs >> 3); /* Store field offset. */ | |
| 1329 } else { | |
| 1330 ct->info = CTINFO(CT_BITFIELD, | |
| 1331 (info & (CTF_QUAL|CTF_UNSIGNED|CTF_BOOL)) + | |
| 1332 (csz << (CTSHIFT_BITCSZ-3)) + (bsz << CTSHIFT_BITBSZ)); | |
| 1333 #if LJ_BE | |
| 1334 ct->info += ((csz - (bofs & (csz-1)) - bsz) << CTSHIFT_BITPOS); | |
| 1335 #else | |
| 1336 ct->info += ((bofs & (csz-1)) << CTSHIFT_BITPOS); | |
| 1337 #endif | |
| 1338 ct->size = ((bofs & ~(csz-1)) >> 3); /* Store container offset. */ | |
| 1339 } | |
| 1340 } | |
| 1341 | |
| 1342 /* Determine next offset or max. offset. */ | |
| 1343 if ((sinfo & CTF_UNION)) { | |
| 1344 if (bsz > bmaxofs) bmaxofs = bsz; | |
| 1345 } else { | |
| 1346 bofs += bsz; | |
| 1347 } | |
| 1348 } /* All other fields in the chain are already set up. */ | |
| 1349 | |
| 1350 fieldid = ct->sib; | |
| 1351 } | |
| 1352 | |
| 1353 /* Complete struct/union. */ | |
| 1354 sct->info = sinfo + CTALIGN(maxalign); | |
| 1355 bofs = (sinfo & CTF_UNION) ? bmaxofs : bofs; | |
| 1356 maxalign = (8u << maxalign) - 1; | |
| 1357 sct->size = (((bofs + maxalign) & ~maxalign) >> 3); | |
| 1358 } | |
| 1359 | |
| 1360 /* Parse struct/union declaration. */ | |
| 1361 static CTypeID cp_decl_struct(CPState *cp, CPDecl *sdecl, CTInfo sinfo) | |
| 1362 { | |
| 1363 CTypeID sid = cp_struct_name(cp, sdecl, sinfo); | |
| 1364 if (cp_opt(cp, '{')) { /* Struct/union definition. */ | |
| 1365 CTypeID lastid = sid; | |
| 1366 int lastdecl = 0; | |
| 1367 while (cp->tok != '}') { | |
| 1368 CPDecl decl; | |
| 1369 CPscl scl = cp_decl_spec(cp, &decl, CDF_STATIC); | |
| 1370 decl.mode = scl ? CPARSE_MODE_DIRECT : | |
| 1371 CPARSE_MODE_DIRECT|CPARSE_MODE_ABSTRACT|CPARSE_MODE_FIELD; | |
| 1372 | |
| 1373 for (;;) { | |
| 1374 CTypeID ctypeid; | |
| 1375 | |
| 1376 if (lastdecl) cp_err_token(cp, '}'); | |
| 1377 | |
| 1378 /* Parse field declarator. */ | |
| 1379 decl.bits = CTSIZE_INVALID; | |
| 1380 cp_declarator(cp, &decl); | |
| 1381 ctypeid = cp_decl_intern(cp, &decl); | |
| 1382 | |
| 1383 if ((scl & CDF_STATIC)) { /* Static constant in struct namespace. */ | |
| 1384 CType *ct; | |
| 1385 CTypeID fieldid = cp_decl_constinit(cp, &ct, ctypeid); | |
| 1386 ctype_get(cp->cts, lastid)->sib = fieldid; | |
| 1387 lastid = fieldid; | |
| 1388 ctype_setname(ct, decl.name); | |
| 1389 } else { | |
| 1390 CTSize bsz = CTBSZ_FIELD; /* Temp. for layout phase. */ | |
| 1391 CType *ct; | |
| 1392 CTypeID fieldid = lj_ctype_new(cp->cts, &ct); /* Do this first. */ | |
| 1393 CType *tct = ctype_raw(cp->cts, ctypeid); | |
| 1394 | |
| 1395 if (decl.bits == CTSIZE_INVALID) { /* Regular field. */ | |
| 1396 if (ctype_isarray(tct->info) && tct->size == CTSIZE_INVALID) | |
| 1397 lastdecl = 1; /* a[] or a[?] must be the last declared field. */ | |
| 1398 | |
| 1399 /* Accept transparent struct/union/enum. */ | |
| 1400 if (!decl.name) { | |
| 1401 if (!((ctype_isstruct(tct->info) && !(tct->info & CTF_VLA)) || | |
| 1402 ctype_isenum(tct->info))) | |
| 1403 cp_err_token(cp, CTOK_IDENT); | |
| 1404 ct->info = CTINFO(CT_ATTRIB, CTATTRIB(CTA_SUBTYPE) + ctypeid); | |
| 1405 ct->size = ctype_isstruct(tct->info) ? | |
| 1406 (decl.attr|0x80000000u) : 0; /* For layout phase. */ | |
| 1407 goto add_field; | |
| 1408 } | |
| 1409 } else { /* Bitfield. */ | |
| 1410 bsz = decl.bits; | |
| 1411 if (!ctype_isinteger_or_bool(tct->info) || | |
| 1412 (bsz == 0 && decl.name) || 8*tct->size > CTBSZ_MAX || | |
| 1413 bsz > ((tct->info & CTF_BOOL) ? 1 : 8*tct->size)) | |
| 1414 cp_errmsg(cp, ':', LJ_ERR_BADVAL); | |
| 1415 } | |
| 1416 | |
| 1417 /* Create temporary field for layout phase. */ | |
| 1418 ct->info = CTINFO(CT_FIELD, ctypeid + (bsz << CTSHIFT_BITCSZ)); | |
| 1419 ct->size = decl.attr; | |
| 1420 if (decl.name) ctype_setname(ct, decl.name); | |
| 1421 | |
| 1422 add_field: | |
| 1423 ctype_get(cp->cts, lastid)->sib = fieldid; | |
| 1424 lastid = fieldid; | |
| 1425 } | |
| 1426 if (!cp_opt(cp, ',')) break; | |
| 1427 cp_decl_reset(&decl); | |
| 1428 } | |
| 1429 cp_check(cp, ';'); | |
| 1430 } | |
| 1431 cp_check(cp, '}'); | |
| 1432 ctype_get(cp->cts, lastid)->sib = 0; /* Drop sib = 1 for empty structs. */ | |
| 1433 cp_decl_attributes(cp, sdecl); /* Layout phase needs postfix attributes. */ | |
| 1434 cp_struct_layout(cp, sid, sdecl->attr); | |
| 1435 } | |
| 1436 return sid; | |
| 1437 } | |
| 1438 | |
| 1439 /* Parse enum declaration. */ | |
| 1440 static CTypeID cp_decl_enum(CPState *cp, CPDecl *sdecl) | |
| 1441 { | |
| 1442 CTypeID eid = cp_struct_name(cp, sdecl, CTINFO(CT_ENUM, CTID_VOID)); | |
| 1443 CTInfo einfo = CTINFO(CT_ENUM, CTALIGN(2) + CTID_UINT32); | |
| 1444 CTSize esize = 4; /* Only 32 bit enums are supported. */ | |
| 1445 if (cp_opt(cp, '{')) { /* Enum definition. */ | |
| 1446 CPValue k; | |
| 1447 CTypeID lastid = eid; | |
| 1448 k.u32 = 0; | |
| 1449 k.id = CTID_INT32; | |
| 1450 do { | |
| 1451 GCstr *name = cp->str; | |
| 1452 if (cp->tok != CTOK_IDENT) cp_err_token(cp, CTOK_IDENT); | |
| 1453 if (cp->val.id) cp_errmsg(cp, 0, LJ_ERR_FFI_REDEF, strdata(name)); | |
| 1454 cp_next(cp); | |
| 1455 if (cp_opt(cp, '=')) { | |
| 1456 cp_expr_kint(cp, &k); | |
| 1457 if (k.id == CTID_UINT32) { | |
| 1458 /* C99 says that enum constants are always (signed) integers. | |
| 1459 ** But since unsigned constants like 0x80000000 are quite common, | |
| 1460 ** those are left as uint32_t. | |
| 1461 */ | |
| 1462 if (k.i32 >= 0) k.id = CTID_INT32; | |
| 1463 } else { | |
| 1464 /* OTOH it's common practice and even mandated by some ABIs | |
| 1465 ** that the enum type itself is unsigned, unless there are any | |
| 1466 ** negative constants. | |
| 1467 */ | |
| 1468 k.id = CTID_INT32; | |
| 1469 if (k.i32 < 0) einfo = CTINFO(CT_ENUM, CTALIGN(2) + CTID_INT32); | |
| 1470 } | |
| 1471 } | |
| 1472 /* Add named enum constant. */ | |
| 1473 { | |
| 1474 CType *ct; | |
| 1475 CTypeID constid = lj_ctype_new(cp->cts, &ct); | |
| 1476 ctype_get(cp->cts, lastid)->sib = constid; | |
| 1477 lastid = constid; | |
| 1478 ctype_setname(ct, name); | |
| 1479 ct->info = CTINFO(CT_CONSTVAL, CTF_CONST|k.id); | |
| 1480 ct->size = k.u32++; | |
| 1481 if (k.u32 == 0x80000000u) k.id = CTID_UINT32; | |
| 1482 lj_ctype_addname(cp->cts, ct, constid); | |
| 1483 } | |
| 1484 if (!cp_opt(cp, ',')) break; | |
| 1485 } while (cp->tok != '}'); /* Trailing ',' is ok. */ | |
| 1486 cp_check(cp, '}'); | |
| 1487 /* Complete enum. */ | |
| 1488 ctype_get(cp->cts, eid)->info = einfo; | |
| 1489 ctype_get(cp->cts, eid)->size = esize; | |
| 1490 } | |
| 1491 return eid; | |
| 1492 } | |
| 1493 | |
| 1494 /* Parse declaration specifiers. */ | |
| 1495 static CPscl cp_decl_spec(CPState *cp, CPDecl *decl, CPscl scl) | |
| 1496 { | |
| 1497 uint32_t cds = 0, sz = 0; | |
| 1498 CTypeID tdef = 0; | |
| 1499 | |
| 1500 decl->cp = cp; | |
| 1501 decl->mode = cp->mode; | |
| 1502 decl->name = NULL; | |
| 1503 decl->redir = NULL; | |
| 1504 decl->attr = 0; | |
| 1505 decl->fattr = 0; | |
| 1506 decl->pos = decl->top = 0; | |
| 1507 decl->stack[0].next = 0; | |
| 1508 | |
| 1509 for (;;) { /* Parse basic types. */ | |
| 1510 cp_decl_attributes(cp, decl); | |
| 1511 if (cp->tok >= CTOK_FIRSTDECL && cp->tok <= CTOK_LASTDECLFLAG) { | |
| 1512 uint32_t cbit; | |
| 1513 if (cp->ct->size) { | |
| 1514 if (sz) goto end_decl; | |
| 1515 sz = cp->ct->size; | |
| 1516 } | |
| 1517 cbit = (1u << (cp->tok - CTOK_FIRSTDECL)); | |
| 1518 cds = cds | cbit | ((cbit & cds & CDF_LONG) << 1); | |
| 1519 if (cp->tok >= CTOK_FIRSTSCL) { | |
| 1520 if (!(scl & cbit)) cp_errmsg(cp, cp->tok, LJ_ERR_FFI_BADSCL); | |
| 1521 } else if (tdef) { | |
| 1522 goto end_decl; | |
| 1523 } | |
| 1524 cp_next(cp); | |
| 1525 continue; | |
| 1526 } | |
| 1527 if (sz || tdef || | |
| 1528 (cds & (CDF_SHORT|CDF_LONG|CDF_SIGNED|CDF_UNSIGNED|CDF_COMPLEX))) | |
| 1529 break; | |
| 1530 switch (cp->tok) { | |
| 1531 case CTOK_STRUCT: | |
| 1532 tdef = cp_decl_struct(cp, decl, CTINFO(CT_STRUCT, 0)); | |
| 1533 continue; | |
| 1534 case CTOK_UNION: | |
| 1535 tdef = cp_decl_struct(cp, decl, CTINFO(CT_STRUCT, CTF_UNION)); | |
| 1536 continue; | |
| 1537 case CTOK_ENUM: | |
| 1538 tdef = cp_decl_enum(cp, decl); | |
| 1539 continue; | |
| 1540 case CTOK_IDENT: | |
| 1541 if (ctype_istypedef(cp->ct->info)) { | |
| 1542 tdef = ctype_cid(cp->ct->info); /* Get typedef. */ | |
| 1543 cp_next(cp); | |
| 1544 continue; | |
| 1545 } | |
| 1546 break; | |
| 1547 case '$': | |
| 1548 tdef = cp->val.id; | |
| 1549 cp_next(cp); | |
| 1550 continue; | |
| 1551 default: | |
| 1552 break; | |
| 1553 } | |
| 1554 break; | |
| 1555 } | |
| 1556 end_decl: | |
| 1557 | |
| 1558 if ((cds & CDF_COMPLEX)) /* Use predefined complex types. */ | |
| 1559 tdef = sz == 4 ? CTID_COMPLEX_FLOAT : CTID_COMPLEX_DOUBLE; | |
| 1560 | |
| 1561 if (tdef) { | |
| 1562 cp_push_type(decl, tdef); | |
| 1563 } else if ((cds & CDF_VOID)) { | |
| 1564 cp_push(decl, CTINFO(CT_VOID, (decl->attr & CTF_QUAL)), CTSIZE_INVALID); | |
| 1565 decl->attr &= ~CTF_QUAL; | |
| 1566 } else { | |
| 1567 /* Determine type info and size. */ | |
| 1568 CTInfo info = CTINFO(CT_NUM, (cds & CDF_UNSIGNED) ? CTF_UNSIGNED : 0); | |
| 1569 if ((cds & CDF_BOOL)) { | |
| 1570 if ((cds & ~(CDF_SCL|CDF_BOOL|CDF_INT|CDF_SIGNED|CDF_UNSIGNED))) | |
| 1571 cp_errmsg(cp, 0, LJ_ERR_FFI_INVTYPE); | |
| 1572 info |= CTF_BOOL; | |
| 1573 if (!(cds & CDF_SIGNED)) info |= CTF_UNSIGNED; | |
| 1574 if (!sz) { | |
| 1575 sz = 1; | |
| 1576 } | |
| 1577 } else if ((cds & CDF_FP)) { | |
| 1578 info = CTINFO(CT_NUM, CTF_FP); | |
| 1579 if ((cds & CDF_LONG)) sz = sizeof(long double); | |
| 1580 } else if ((cds & CDF_CHAR)) { | |
| 1581 if ((cds & (CDF_CHAR|CDF_SIGNED|CDF_UNSIGNED)) == CDF_CHAR) | |
| 1582 info |= CTF_UCHAR; /* Handle platforms where char is unsigned. */ | |
| 1583 } else if ((cds & CDF_SHORT)) { | |
| 1584 sz = sizeof(short); | |
| 1585 } else if ((cds & CDF_LONGLONG)) { | |
| 1586 sz = 8; | |
| 1587 } else if ((cds & CDF_LONG)) { | |
| 1588 info |= CTF_LONG; | |
| 1589 sz = sizeof(long); | |
| 1590 } else if (!sz) { | |
| 1591 if (!(cds & (CDF_SIGNED|CDF_UNSIGNED))) | |
| 1592 cp_errmsg(cp, cp->tok, LJ_ERR_FFI_DECLSPEC); | |
| 1593 sz = sizeof(int); | |
| 1594 } | |
| 1595 lj_assertCP(sz != 0, "basic ctype with zero size"); | |
| 1596 info += CTALIGN(lj_fls(sz)); /* Use natural alignment. */ | |
| 1597 info += (decl->attr & CTF_QUAL); /* Merge qualifiers. */ | |
| 1598 cp_push(decl, info, sz); | |
| 1599 decl->attr &= ~CTF_QUAL; | |
| 1600 } | |
| 1601 decl->specpos = decl->pos; | |
| 1602 decl->specattr = decl->attr; | |
| 1603 decl->specfattr = decl->fattr; | |
| 1604 return (cds & CDF_SCL); /* Return storage class. */ | |
| 1605 } | |
| 1606 | |
| 1607 /* Parse array declaration. */ | |
| 1608 static void cp_decl_array(CPState *cp, CPDecl *decl) | |
| 1609 { | |
| 1610 CTInfo info = CTINFO(CT_ARRAY, 0); | |
| 1611 CTSize nelem = CTSIZE_INVALID; /* Default size for a[] or a[?]. */ | |
| 1612 cp_decl_attributes(cp, decl); | |
| 1613 if (cp_opt(cp, '?')) | |
| 1614 info |= CTF_VLA; /* Create variable-length array a[?]. */ | |
| 1615 else if (cp->tok != ']') | |
| 1616 nelem = cp_expr_ksize(cp); | |
| 1617 cp_check(cp, ']'); | |
| 1618 cp_add(decl, info, nelem); | |
| 1619 } | |
| 1620 | |
| 1621 /* Parse function declaration. */ | |
| 1622 static void cp_decl_func(CPState *cp, CPDecl *fdecl) | |
| 1623 { | |
| 1624 CTSize nargs = 0; | |
| 1625 CTInfo info = CTINFO(CT_FUNC, 0); | |
| 1626 CTypeID lastid = 0, anchor = 0; | |
| 1627 if (cp->tok != ')') { | |
| 1628 do { | |
| 1629 CPDecl decl; | |
| 1630 CTypeID ctypeid, fieldid; | |
| 1631 CType *ct; | |
| 1632 if (cp_opt(cp, '.')) { /* Vararg function. */ | |
| 1633 cp_check(cp, '.'); /* Workaround for the minimalistic lexer. */ | |
| 1634 cp_check(cp, '.'); | |
| 1635 info |= CTF_VARARG; | |
| 1636 break; | |
| 1637 } | |
| 1638 cp_decl_spec(cp, &decl, CDF_REGISTER); | |
| 1639 decl.mode = CPARSE_MODE_DIRECT|CPARSE_MODE_ABSTRACT; | |
| 1640 cp_declarator(cp, &decl); | |
| 1641 ctypeid = cp_decl_intern(cp, &decl); | |
| 1642 ct = ctype_raw(cp->cts, ctypeid); | |
| 1643 if (ctype_isvoid(ct->info)) | |
| 1644 break; | |
| 1645 else if (ctype_isrefarray(ct->info)) | |
| 1646 ctypeid = lj_ctype_intern(cp->cts, | |
| 1647 CTINFO(CT_PTR, CTALIGN_PTR|ctype_cid(ct->info)), CTSIZE_PTR); | |
| 1648 else if (ctype_isfunc(ct->info)) | |
| 1649 ctypeid = lj_ctype_intern(cp->cts, | |
| 1650 CTINFO(CT_PTR, CTALIGN_PTR|ctypeid), CTSIZE_PTR); | |
| 1651 /* Add new parameter. */ | |
| 1652 fieldid = lj_ctype_new(cp->cts, &ct); | |
| 1653 if (anchor) | |
| 1654 ctype_get(cp->cts, lastid)->sib = fieldid; | |
| 1655 else | |
| 1656 anchor = fieldid; | |
| 1657 lastid = fieldid; | |
| 1658 if (decl.name) ctype_setname(ct, decl.name); | |
| 1659 ct->info = CTINFO(CT_FIELD, ctypeid); | |
| 1660 ct->size = nargs++; | |
| 1661 } while (cp_opt(cp, ',')); | |
| 1662 } | |
| 1663 cp_check(cp, ')'); | |
| 1664 if (cp_opt(cp, '{')) { /* Skip function definition. */ | |
| 1665 int level = 1; | |
| 1666 cp->mode |= CPARSE_MODE_SKIP; | |
| 1667 for (;;) { | |
| 1668 if (cp->tok == '{') level++; | |
| 1669 else if (cp->tok == '}' && --level == 0) break; | |
| 1670 else if (cp->tok == CTOK_EOF) cp_err_token(cp, '}'); | |
| 1671 cp_next(cp); | |
| 1672 } | |
| 1673 cp->mode &= ~CPARSE_MODE_SKIP; | |
| 1674 cp->tok = ';'; /* Ok for cp_decl_multi(), error in cp_decl_single(). */ | |
| 1675 } | |
| 1676 info |= (fdecl->fattr & ~CTMASK_CID); | |
| 1677 fdecl->fattr = 0; | |
| 1678 fdecl->stack[cp_add(fdecl, info, nargs)].sib = anchor; | |
| 1679 } | |
| 1680 | |
| 1681 /* Parse declarator. */ | |
| 1682 static void cp_declarator(CPState *cp, CPDecl *decl) | |
| 1683 { | |
| 1684 if (++cp->depth > CPARSE_MAX_DECLDEPTH) cp_err(cp, LJ_ERR_XLEVELS); | |
| 1685 | |
| 1686 for (;;) { /* Head of declarator. */ | |
| 1687 if (cp_opt(cp, '*')) { /* Pointer. */ | |
| 1688 CTSize sz; | |
| 1689 CTInfo info; | |
| 1690 cp_decl_attributes(cp, decl); | |
| 1691 sz = CTSIZE_PTR; | |
| 1692 info = CTINFO(CT_PTR, CTALIGN_PTR); | |
| 1693 #if LJ_64 | |
| 1694 if (ctype_msizeP(decl->attr) == 4) { | |
| 1695 sz = 4; | |
| 1696 info = CTINFO(CT_PTR, CTALIGN(2)); | |
| 1697 } | |
| 1698 #endif | |
| 1699 info += (decl->attr & (CTF_QUAL|CTF_REF)); | |
| 1700 decl->attr &= ~(CTF_QUAL|(CTMASK_MSIZEP<<CTSHIFT_MSIZEP)); | |
| 1701 cp_push(decl, info, sz); | |
| 1702 } else if (cp_opt(cp, '&') || cp_opt(cp, CTOK_ANDAND)) { /* Reference. */ | |
| 1703 decl->attr &= ~(CTF_QUAL|(CTMASK_MSIZEP<<CTSHIFT_MSIZEP)); | |
| 1704 cp_push(decl, CTINFO_REF(0), CTSIZE_PTR); | |
| 1705 } else { | |
| 1706 break; | |
| 1707 } | |
| 1708 } | |
| 1709 | |
| 1710 if (cp_opt(cp, '(')) { /* Inner declarator. */ | |
| 1711 CPDeclIdx pos; | |
| 1712 cp_decl_attributes(cp, decl); | |
| 1713 /* Resolve ambiguity between inner declarator and 1st function parameter. */ | |
| 1714 if ((decl->mode & CPARSE_MODE_ABSTRACT) && | |
| 1715 (cp->tok == ')' || cp_istypedecl(cp))) goto func_decl; | |
| 1716 pos = decl->pos; | |
| 1717 cp_declarator(cp, decl); | |
| 1718 cp_check(cp, ')'); | |
| 1719 decl->pos = pos; | |
| 1720 } else if (cp->tok == CTOK_IDENT) { /* Direct declarator. */ | |
| 1721 if (!(decl->mode & CPARSE_MODE_DIRECT)) cp_err_token(cp, CTOK_EOF); | |
| 1722 decl->name = cp->str; | |
| 1723 decl->nameid = cp->val.id; | |
| 1724 cp_next(cp); | |
| 1725 } else { /* Abstract declarator. */ | |
| 1726 if (!(decl->mode & CPARSE_MODE_ABSTRACT)) cp_err_token(cp, CTOK_IDENT); | |
| 1727 } | |
| 1728 | |
| 1729 for (;;) { /* Tail of declarator. */ | |
| 1730 if (cp_opt(cp, '[')) { /* Array. */ | |
| 1731 cp_decl_array(cp, decl); | |
| 1732 } else if (cp_opt(cp, '(')) { /* Function. */ | |
| 1733 func_decl: | |
| 1734 cp_decl_func(cp, decl); | |
| 1735 } else { | |
| 1736 break; | |
| 1737 } | |
| 1738 } | |
| 1739 | |
| 1740 if ((decl->mode & CPARSE_MODE_FIELD) && cp_opt(cp, ':')) /* Field width. */ | |
| 1741 decl->bits = cp_expr_ksize(cp); | |
| 1742 | |
| 1743 /* Process postfix attributes. */ | |
| 1744 cp_decl_attributes(cp, decl); | |
| 1745 cp_push_attributes(decl); | |
| 1746 | |
| 1747 cp->depth--; | |
| 1748 } | |
| 1749 | |
| 1750 /* Parse an abstract type declaration and return it's C type ID. */ | |
| 1751 static CTypeID cp_decl_abstract(CPState *cp) | |
| 1752 { | |
| 1753 CPDecl decl; | |
| 1754 cp_decl_spec(cp, &decl, 0); | |
| 1755 decl.mode = CPARSE_MODE_ABSTRACT; | |
| 1756 cp_declarator(cp, &decl); | |
| 1757 return cp_decl_intern(cp, &decl); | |
| 1758 } | |
| 1759 | |
| 1760 /* Handle pragmas. */ | |
| 1761 static void cp_pragma(CPState *cp, BCLine pragmaline) | |
| 1762 { | |
| 1763 cp_next(cp); | |
| 1764 if (cp->tok == CTOK_IDENT && cp_str_is(cp->str, "pack")) { | |
| 1765 cp_next(cp); | |
| 1766 cp_check(cp, '('); | |
| 1767 if (cp->tok == CTOK_IDENT) { | |
| 1768 if (cp_str_is(cp->str, "push")) { | |
| 1769 if (cp->curpack < CPARSE_MAX_PACKSTACK) { | |
| 1770 cp->packstack[cp->curpack+1] = cp->packstack[cp->curpack]; | |
| 1771 cp->curpack++; | |
| 1772 } | |
| 1773 } else if (cp_str_is(cp->str, "pop")) { | |
| 1774 if (cp->curpack > 0) cp->curpack--; | |
| 1775 } else { | |
| 1776 cp_errmsg(cp, cp->tok, LJ_ERR_XSYMBOL); | |
| 1777 } | |
| 1778 cp_next(cp); | |
| 1779 if (!cp_opt(cp, ',')) goto end_pack; | |
| 1780 } | |
| 1781 if (cp->tok == CTOK_INTEGER) { | |
| 1782 cp->packstack[cp->curpack] = cp->val.u32 ? lj_fls(cp->val.u32) : 0; | |
| 1783 cp_next(cp); | |
| 1784 } else { | |
| 1785 cp->packstack[cp->curpack] = 255; | |
| 1786 } | |
| 1787 end_pack: | |
| 1788 cp_check(cp, ')'); | |
| 1789 } else { /* Ignore all other pragmas. */ | |
| 1790 while (cp->tok != CTOK_EOF && cp->linenumber == pragmaline) | |
| 1791 cp_next(cp); | |
| 1792 } | |
| 1793 } | |
| 1794 | |
| 1795 /* Handle line number. */ | |
| 1796 static void cp_line(CPState *cp, BCLine hashline) | |
| 1797 { | |
| 1798 BCLine newline = cp->val.u32; | |
| 1799 /* TODO: Handle file name and include it in error messages. */ | |
| 1800 while (cp->tok != CTOK_EOF && cp->linenumber == hashline) | |
| 1801 cp_next(cp); | |
| 1802 cp->linenumber = newline; | |
| 1803 } | |
| 1804 | |
| 1805 /* Parse multiple C declarations of types or extern identifiers. */ | |
| 1806 static void cp_decl_multi(CPState *cp) | |
| 1807 { | |
| 1808 int first = 1; | |
| 1809 while (cp->tok != CTOK_EOF) { | |
| 1810 CPDecl decl; | |
| 1811 CPscl scl; | |
| 1812 if (cp_opt(cp, ';')) { /* Skip empty statements. */ | |
| 1813 first = 0; | |
| 1814 continue; | |
| 1815 } | |
| 1816 if (cp->tok == '#') { /* Workaround, since we have no preprocessor, yet. */ | |
| 1817 BCLine hashline = cp->linenumber; | |
| 1818 CPToken tok = cp_next(cp); | |
| 1819 if (tok == CTOK_INTEGER) { | |
| 1820 cp_line(cp, hashline); | |
| 1821 continue; | |
| 1822 } else if (tok == CTOK_IDENT && cp_str_is(cp->str, "line")) { | |
| 1823 if (cp_next(cp) != CTOK_INTEGER) cp_err_token(cp, tok); | |
| 1824 cp_line(cp, hashline); | |
| 1825 continue; | |
| 1826 } else if (tok == CTOK_IDENT && cp_str_is(cp->str, "pragma")) { | |
| 1827 cp_pragma(cp, hashline); | |
| 1828 continue; | |
| 1829 } else { | |
| 1830 cp_errmsg(cp, cp->tok, LJ_ERR_XSYMBOL); | |
| 1831 } | |
| 1832 } | |
| 1833 scl = cp_decl_spec(cp, &decl, CDF_TYPEDEF|CDF_EXTERN|CDF_STATIC); | |
| 1834 if ((cp->tok == ';' || cp->tok == CTOK_EOF) && | |
| 1835 ctype_istypedef(decl.stack[0].info)) { | |
| 1836 CTInfo info = ctype_rawchild(cp->cts, &decl.stack[0])->info; | |
| 1837 if (ctype_isstruct(info) || ctype_isenum(info)) | |
| 1838 goto decl_end; /* Accept empty declaration of struct/union/enum. */ | |
| 1839 } | |
| 1840 for (;;) { | |
| 1841 CTypeID ctypeid; | |
| 1842 cp_declarator(cp, &decl); | |
| 1843 ctypeid = cp_decl_intern(cp, &decl); | |
| 1844 if (decl.name && !decl.nameid) { /* NYI: redeclarations are ignored. */ | |
| 1845 CType *ct; | |
| 1846 CTypeID id; | |
| 1847 if ((scl & CDF_TYPEDEF)) { /* Create new typedef. */ | |
| 1848 id = lj_ctype_new(cp->cts, &ct); | |
| 1849 ct->info = CTINFO(CT_TYPEDEF, ctypeid); | |
| 1850 goto noredir; | |
| 1851 } else if (ctype_isfunc(ctype_get(cp->cts, ctypeid)->info)) { | |
| 1852 /* Treat both static and extern function declarations as extern. */ | |
| 1853 ct = ctype_get(cp->cts, ctypeid); | |
| 1854 /* We always get new anonymous functions (typedefs are copied). */ | |
| 1855 lj_assertCP(gcref(ct->name) == NULL, "unexpected named function"); | |
| 1856 id = ctypeid; /* Just name it. */ | |
| 1857 } else if ((scl & CDF_STATIC)) { /* Accept static constants. */ | |
| 1858 id = cp_decl_constinit(cp, &ct, ctypeid); | |
| 1859 goto noredir; | |
| 1860 } else { /* External references have extern or no storage class. */ | |
| 1861 id = lj_ctype_new(cp->cts, &ct); | |
| 1862 ct->info = CTINFO(CT_EXTERN, ctypeid); | |
| 1863 } | |
| 1864 if (decl.redir) { /* Add attribute for redirected symbol name. */ | |
| 1865 CType *cta; | |
| 1866 CTypeID aid = lj_ctype_new(cp->cts, &cta); | |
| 1867 ct = ctype_get(cp->cts, id); /* Table may have been reallocated. */ | |
| 1868 cta->info = CTINFO(CT_ATTRIB, CTATTRIB(CTA_REDIR)); | |
| 1869 cta->sib = ct->sib; | |
| 1870 ct->sib = aid; | |
| 1871 ctype_setname(cta, decl.redir); | |
| 1872 } | |
| 1873 noredir: | |
| 1874 ctype_setname(ct, decl.name); | |
| 1875 lj_ctype_addname(cp->cts, ct, id); | |
| 1876 } | |
| 1877 if (!cp_opt(cp, ',')) break; | |
| 1878 cp_decl_reset(&decl); | |
| 1879 } | |
| 1880 decl_end: | |
| 1881 if (cp->tok == CTOK_EOF && first) break; /* May omit ';' for 1 decl. */ | |
| 1882 first = 0; | |
| 1883 cp_check(cp, ';'); | |
| 1884 } | |
| 1885 } | |
| 1886 | |
| 1887 /* Parse a single C type declaration. */ | |
| 1888 static void cp_decl_single(CPState *cp) | |
| 1889 { | |
| 1890 CPDecl decl; | |
| 1891 cp_decl_spec(cp, &decl, 0); | |
| 1892 cp_declarator(cp, &decl); | |
| 1893 cp->val.id = cp_decl_intern(cp, &decl); | |
| 1894 if (cp->tok != CTOK_EOF) cp_err_token(cp, CTOK_EOF); | |
| 1895 } | |
| 1896 | |
| 1897 /* ------------------------------------------------------------------------ */ | |
| 1898 | |
| 1899 /* Protected callback for C parser. */ | |
| 1900 static TValue *cpcparser(lua_State *L, lua_CFunction dummy, void *ud) | |
| 1901 { | |
| 1902 CPState *cp = (CPState *)ud; | |
| 1903 UNUSED(dummy); | |
| 1904 cframe_errfunc(L->cframe) = -1; /* Inherit error function. */ | |
| 1905 cp_init(cp); | |
| 1906 if ((cp->mode & CPARSE_MODE_MULTI)) | |
| 1907 cp_decl_multi(cp); | |
| 1908 else | |
| 1909 cp_decl_single(cp); | |
| 1910 if (cp->param && cp->param != cp->L->top) | |
| 1911 cp_err(cp, LJ_ERR_FFI_NUMPARAM); | |
| 1912 lj_assertCP(cp->depth == 0, "unbalanced cparser declaration depth"); | |
| 1913 return NULL; | |
| 1914 } | |
| 1915 | |
| 1916 /* C parser. */ | |
| 1917 int lj_cparse(CPState *cp) | |
| 1918 { | |
| 1919 LJ_CTYPE_SAVE(cp->cts); | |
| 1920 int errcode = lj_vm_cpcall(cp->L, NULL, cp, cpcparser); | |
| 1921 if (errcode) | |
| 1922 LJ_CTYPE_RESTORE(cp->cts); | |
| 1923 cp_cleanup(cp); | |
| 1924 return errcode; | |
| 1925 } | |
| 1926 | |
| 1927 #endif |