// suck all the global function, struct, union, enum, and typedef prototypes out of the token stream // -- which means creating a new "defs" token stream, and splitting out a defs_idx from the idx_tbl uint32_t proto_pass(struct proto_info *inf, uint8_t *new_eb) { int32_t i; uint32_t j, k, m; uint8_t bol_flag, *p, *c, *sp; int8_t level, def_flg; bol_flag = 1; def_flg = level = 0; i = k = m = 0; p = sp = wrksp_top; if (new_eb != NULL) p = sp = new_eb; while (1) { // At top level, the only thing I should ever encounter at bol are typespecs/declspecs and typedefs? // HIHI!! I must also copydown the EMIT buffer! Use the c pointer for that! But there is a problem for the defs = -1 case that gets cancelled ... if (level == 0 && def_flg == 0) { inf->idx_strt = k; // save the *next* idx index sp = p; // save a ptr to the beginning of any prototype } switch (*p) { // HIHI!! how to detect the beginning of a function definition?? It's the only thing that's not a typespec or declspec or variable name? case TOK_STRUCT: case TOK_UNION: case TOK_ENUM: if (level == 0) def_flg = -1; break; case TOK_NAME_IDX: j = idx_tbl[k++]; if (++m != k) idx_tbl[m - 1] = j; // rebuild a compressed idx_tbl c = name_strings + j; // if (level == 0 && def_flg == 0) // HIHI debugging! // bol_flag = 0; break; case TOK_INT_CONST: case TOK_FP_CONST: case TOK_NONAME_IDX: j = idx_tbl[k++]; // must keep k aligned with the token stream if (++m != k) idx_tbl[m - 1] = j; // rebuild a compressed idx_tbl break; case TOK_TYPEDEF: if (bol_flag != 0) { if (level == 0) def_flg = 2; // HIHI can you do typedefs with only local scope? } // else show_error (0, "typedef syntax error", NULL, 1, inf); // must recalculate the line number and fname first! break; case TOK_SEMIC: if (level == 0 && def_flg != 0) def_flg = 32; bol_flag = 1; break; case TOK_OCURLY: if (def_flg < 0) def_flg = 1; bol_flag = 1; ++level; break; case TOK_CCURLY: if (--level == 0) { if (def_flg == 1) def_flg = 16; } bol_flag = 1; break; case TOK_ENDOFBUF: if (inf->infd < 0) return m; // HIHI!! if (def_flg != 0) then I must do a partial copy to the wrkbuf! (and reset sp = p;) read_tok (&p); break; default: if (def_flg < 0) def_flg = 0; bol_flag = 0; } // end of switch on *p ++p; if (def_flg > 2) // found a definition? { m -= k - inf->idx_strt; j = p - sp; inf->wrkbuf = sp; // HIHI getting rid of the wrkbuf ptr? if (def_flg == 32) parse_typedef(j, inf); // else if (def_flg == 16) parse_struct(j, inf->cur_ptr, inf->idx_strt, inf); // HIHI!!! then send it into a parsing routine, to break the whole thing into pieces and store it in defs // -- but I think I want separate parsing routines for typedefs, functions, and structs // parse_proto(&p, inf, 0); def_flg = 0; } // if ((uint32_t) (emit_ptr - wrksp) > wrk_rem - 30 * 1024) handle_emit_overflow(); // HIHI!! do the dealie that guarantees 16K or whatever in the buffer -- at least *nxt_pass_info amount } // infinite loop }
static int process_line(struct protolib *plib, struct locus *loc, char *buf) { char *str = buf; char *tmp; debug(3, "Reading line %d of `%s'", loc->line_no, loc->filename); eat_spaces(&str); /* A comment or empty line. */ if (*str == ';' || *str == 0 || *str == '\n' || *str == '#') return 0; if (strncmp(str, "typedef", 7) == 0) { parse_typedef(plib, loc, &str); return 0; } struct prototype fun; prototype_init(&fun); struct param *extra_param = NULL; char *proto_name = NULL; int own; fun.return_info = parse_lens(plib, loc, &str, NULL, 0, &own, NULL); if (fun.return_info == NULL) { err: debug(3, " Skipping line %d", loc->line_no); if (extra_param != NULL) { param_destroy(extra_param); free(extra_param); } prototype_destroy(&fun); free(proto_name); return -1; } fun.own_return_info = own; debug(4, " return_type = %d", fun.return_info->type); eat_spaces(&str); tmp = start_of_arg_sig(str); if (tmp == NULL) { report_error(loc->filename, loc->line_no, "syntax error"); goto err; } *tmp = '\0'; proto_name = strdup(str); if (proto_name == NULL) { oom: report_error(loc->filename, loc->line_no, "%s", strerror(errno)); goto err; } str = tmp + 1; debug(3, " name = %s", proto_name); int have_stop = 0; while (1) { eat_spaces(&str); if (*str == ')') break; if (str[0] == '+') { if (have_stop == 0) { struct param param; param_init_stop(¶m); if (prototype_push_param(&fun, ¶m) < 0) goto oom; have_stop = 1; } str++; } int own; size_t param_num = prototype_num_params(&fun) - have_stop; struct arg_type_info *type = parse_lens(plib, loc, &str, &extra_param, param_num, &own, NULL); if (type == NULL) { report_error(loc->filename, loc->line_no, "unknown argument type"); goto err; } struct param param; param_init_type(¶m, type, own); if (prototype_push_param(&fun, ¶m) < 0) goto oom; eat_spaces(&str); if (*str == ',') { str++; continue; } else if (*str == ')') { continue; } else { if (str[strlen(str) - 1] == '\n') str[strlen(str) - 1] = '\0'; report_error(loc->filename, loc->line_no, "syntax error around \"%s\"", str); goto err; } } /* We used to allow void parameter as a synonym to an argument * that shouldn't be displayed. But backends really need to * know the exact type that they are dealing with. The proper * way to do this these days is to use the hide lens. * * So if there are any voids in the parameter list, show a * warning and assume that they are ints. If there's a sole * void, assume the function doesn't take any arguments. The * latter is conservative, we can drop the argument * altogether, instead of fetching and then not showing it, * without breaking any observable behavior. */ if (prototype_num_params(&fun) == 1 && param_is_void(prototype_get_nth_param(&fun, 0))) { if (0) /* Don't show this warning. Pre-0.7.0 * ltrace.conf often used this idiom. This * should be postponed until much later, when * extant uses are likely gone. */ report_warning(loc->filename, loc->line_no, "sole void parameter ignored"); prototype_destroy_nth_param(&fun, 0); } else { prototype_each_param(&fun, NULL, void_to_hidden_int, loc); } if (extra_param != NULL) { prototype_push_param(&fun, extra_param); free(extra_param); extra_param = NULL; } if (protolib_add_prototype(plib, proto_name, 1, &fun) < 0) { report_error(loc->filename, loc->line_no, "couldn't add prototype: %s", strerror(errno)); goto err; } return 0; }