static struct_declaration *analyze_struct(parse_source *source) { parse_token current = get_mandatory_token(source); struct_declaration *dec = new(dec); dec->name = current.data; dec->members = ll_new(); current = get_mandatory_token(source); if(current.data.data[0] != '{') { semantic_error("Expected opening brace after name in struct declaration.", current.origin); } current = get_mandatory_token(source); while(current.data.data[0] != '}') { struct_member *member = new(member); if(current.type != WORD) { semantic_error("Struct members must be declared as <name> <type>;", current.origin); } member->name = current.data; current = get_mandatory_token(source); if(current.type != WORD) { semantic_error("Struct members must be declared as <name> <type>;",current.origin); } member->type = current.data; current = get_mandatory_token(source); if(current.data.data[0] != ';') { semantic_error("Struct members must be declared as <name> <type>;", current.origin); } ll_add_last(dec->members, member); current = get_mandatory_token(source); } return dec; }
void parse_line_range_desc(const char *arg, struct line_range *lr) { const char *ptr; char *tmp; /* * <Syntax> * SRC:SLN[+NUM|-ELN] * FUNC[:SLN[+NUM|-ELN]] */ ptr = strchr(arg, ':'); if (ptr) { lr->start = (unsigned int)strtoul(ptr + 1, &tmp, 0); if (*tmp == '+') lr->end = lr->start + (unsigned int)strtoul(tmp + 1, &tmp, 0); else if (*tmp == '-') lr->end = (unsigned int)strtoul(tmp + 1, &tmp, 0); else lr->end = 0; pr_debug("Line range is %u to %u\n", lr->start, lr->end); if (lr->end && lr->start > lr->end) semantic_error("Start line must be smaller" " than end line."); if (*tmp != '\0') semantic_error("Tailing with invalid character '%d'.", *tmp); tmp = strndup(arg, (ptr - arg)); } else tmp = strdup(arg); if (strchr(tmp, '.')) lr->file = tmp; else lr->function = tmp; }
static func_declaration *analyze_func(parse_source *source) { parse_token current = get_mandatory_token(source); func_declaration *func = new(func); func->parameters = ll_new(); if(current.type != WORD) { semantic_error("Function declaration must be in the form func <name>(<parameters>) <returntype> {<block>}", current.origin); } func->name = current.data; current = get_mandatory_token(source); if(current.data.data[0] != '(') { semantic_error("Function name must be followed by an open parenthesis", current.origin); } current = get_mandatory_token(source); while(current.data.data[0] != ')') { statement *name = new(name); name->type = NAME; name->children = ll_new(); if(current.type != WORD) { printf("%s\n", evaluate(current.data)); semantic_error("Parameter names must be a valid identifier", current.origin); } name->data = current.data; statement *param_type = parse_type_literal(source); ll_add_first(name->children, param_type); param_type->children = NULL; ll_add_last(func->parameters, name); current = get_mandatory_token(source); if(current.data.data[0] == ',') { current = get_mandatory_token(source); } } statement *returnType = parse_type_literal(source); func->type = returnType->data; free(returnType); current = peek_mandatory_token(source); if(current.data.data[0] != '{') { semantic_error("Function bodies must start with an open brace ('{')", current.origin); } int indent = 1; get_mandatory_token(source); func->root = new(func->root); func->root->type = ROOT; func->root->data = new_slice(""); func->root->children = ll_new(); while(indent > 0) { statement *state = get_expression(source, &indent); if(state != NULL) ll_add_last(func->root->children, state); } return func; }
/* Parse kprobe_events event into struct probe_point */ void parse_trace_kprobe_event(const char *str, struct probe_point *pp) { char pr; char *p; int ret, i, argc; char **argv; pr_debug("Parsing kprobe_events: %s\n", str); argv = argv_split(str, &argc); if (!argv) die("argv_split failed."); if (argc < 2) semantic_error("Too less arguments."); /* Scan event and group name. */ ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]", &pr, (float *)(void *)&pp->group, (float *)(void *)&pp->event); if (ret != 3) semantic_error("Failed to parse event name: %s", argv[0]); pr_debug("Group:%s Event:%s probe:%c\n", pp->group, pp->event, pr); pp->retprobe = (pr == 'r'); /* Scan function name and offset */ ret = sscanf(argv[1], "%a[^+]+%d", (float *)(void *)&pp->function, &pp->offset); if (ret == 1) pp->offset = 0; /* kprobe_events doesn't have this information */ pp->line = 0; pp->file = NULL; pp->nr_args = argc - 2; pp->args = zalloc(sizeof(char *) * pp->nr_args); for (i = 0; i < pp->nr_args; i++) { p = strchr(argv[i + 2], '='); if (p) /* We don't need which register is assigned. */ *p = '\0'; pp->args[i] = strdup(argv[i + 2]); if (!pp->args[i]) die("Failed to copy argument."); } argv_free(argv); }
static import_declaration *parse_import(parse_source *source) { parse_token current = get_mandatory_token(source); import_declaration *imp = new(imp); imp->name = current.data; current = get_mandatory_token(source); if(!equals_string(current.data, ";")) { semantic_error("Expected semicolon after import statement", current.origin); } return imp; }
node_ptr resolve_refs::visit (identifier &n) { if (std::find (refs.begin (), refs.end (), &n) != refs.end ()) throw semantic_error (refs, "variable `" + n.string + "' references itself (eventually)"); if (n.ref) { refs.push_back (&n); resume (ref); refs.pop_back (); return n.ref; } return visitor::visit (n); }
/* Parse perf-probe event definition */ void parse_perf_probe_event(const char *str, struct probe_point *pp, bool *need_dwarf) { char **argv; int argc, i; *need_dwarf = false; argv = argv_split(str, &argc); if (!argv) die("argv_split failed."); if (argc > MAX_PROBE_ARGS + 1) semantic_error("Too many arguments"); /* Parse probe point */ parse_perf_probe_probepoint(argv[0], pp); if (pp->file || pp->line || pp->lazy_line) *need_dwarf = true; /* Copy arguments and ensure return probe has no C argument */ pp->nr_args = argc - 1; pp->args = zalloc(sizeof(char *) * pp->nr_args); for (i = 0; i < pp->nr_args; i++) { pp->args[i] = strdup(argv[i + 1]); if (!pp->args[i]) die("Failed to copy argument."); if (is_c_varname(pp->args[i])) { if (pp->retprobe) semantic_error("You can't specify local" " variable for kretprobe"); *need_dwarf = true; } } argv_free(argv); }
static statement *get_expression(parse_source *source, int *indent) { parse_token token = get_mandatory_token(source); if(equals_string(token.data, "{")) { statement *expression = new(expression); expression->type = BLOCK; expression->children = ll_new(); expression->data = new_slice(""); int finished = *indent; *indent += 1; while(*indent != finished) { statement *state = get_expression(source, indent); if(state != NULL) ll_add_last(expression->children, state); } return expression; } else if(equals_string(token.data, "}")) { *indent -= 1; return NULL; } else if(equals_string(token.data, "if") || equals_string(token.data, "while") || equals_string(token.data, "for")) { statement *expression = new(expression); if(equals_string(token.data, "if")) expression->type = IF; else if(equals_string(token.data, "while")) expression->type = WHILE; else if(equals_string(token.data, "for")) expression->type = FOR; expression->children = ll_new(); expression->data = new_slice(""); ll_add_last(expression->children, get_expression(source, indent)); //Add the header if(expression->type == FOR) { ll_add_last(expression->children, get_expression(source, indent)); //Add the header ll_add_last(expression->children, get_expression(source, indent)); //Add the header } ll_add_last(expression->children, get_expression(source, indent)); //Add the body if(expression->type == IF) { parse_token next = peek_mandatory_token(source); if(equals_string(next.data, "else")) { get_mandatory_token(source); statement *elseState = new(elseState); elseState->type = ELSE; elseState->children = ll_new(); elseState->data = new_slice(""); ll_add_last(expression->children, elseState); ll_add_first(elseState->children, get_expression(source, indent)); } } return expression; } else if(equals_string(token.data, "break") || equals_string(token.data, "continue")) { statement *expression = new(expression); expression->type = equals_string(token.data, "break") ? BREAK : CONTINUE; expression->data = new_slice(""); expression->children = NULL; parse_token next = get_mandatory_token(source); if(!equals_string(next.data, ";")) semantic_error("Expected a semicolon after a break or continue", next.origin); return expression; } else if(equals_string(token.data, "return")) { statement *expression = new(expression); expression->type = RETURN; expression->data = new_slice(""); expression->children = ll_new(); ll_add_last(expression->children, get_expression(source, indent)); return expression; } else { linked_list *accumulator = ll_new(); parse_token next = token; while(true) { parse_token *allocated = new(allocated); *allocated = token; ll_add_last(accumulator, allocated); next = peek_mandatory_token(source); if(equals_string(next.data, "{") || equals_string(next.data, "}")) break; if(equals_string(next.data, ";")) { get_mandatory_token(source); break; } token = get_mandatory_token(source); } statement *expression = parse_simple_expression(accumulator); ll_delete_all(accumulator); return expression; } }
/* Parse probepoint definition. */ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp) { char *ptr, *tmp; char c, nc = 0; /* * <Syntax> * perf probe [EVENT=]SRC[:LN|;PTN] * perf probe [EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT] * * TODO:Group name support */ ptr = strpbrk(arg, ";=@+%"); if (ptr && *ptr == '=') { /* Event name */ *ptr = '\0'; tmp = ptr + 1; ptr = strchr(arg, ':'); if (ptr) /* Group name is not supported yet. */ semantic_error("Group name is not supported yet."); if (!check_event_name(arg)) semantic_error("%s is bad for event name -it must " "follow C symbol-naming rule.", arg); pp->event = strdup(arg); arg = tmp; } ptr = strpbrk(arg, ";:+@%"); if (ptr) { nc = *ptr; *ptr++ = '\0'; } /* Check arg is function or file and copy it */ if (strchr(arg, '.')) /* File */ pp->file = strdup(arg); else /* Function */ pp->function = strdup(arg); DIE_IF(pp->file == NULL && pp->function == NULL); /* Parse other options */ while (ptr) { arg = ptr; c = nc; if (c == ';') { /* Lazy pattern must be the last part */ pp->lazy_line = strdup(arg); break; } ptr = strpbrk(arg, ";:+@%"); if (ptr) { nc = *ptr; *ptr++ = '\0'; } switch (c) { case ':': /* Line number */ pp->line = strtoul(arg, &tmp, 0); if (*tmp != '\0') semantic_error("There is non-digit char" " in line number."); break; case '+': /* Byte offset from a symbol */ pp->offset = strtoul(arg, &tmp, 0); if (*tmp != '\0') semantic_error("There is non-digit character" " in offset."); break; case '@': /* File name */ if (pp->file) semantic_error("SRC@SRC is not allowed."); pp->file = strdup(arg); DIE_IF(pp->file == NULL); break; case '%': /* Probe places */ if (strcmp(arg, "return") == 0) { pp->retprobe = 1; } else /* Others not supported yet */ semantic_error("%%%s is not supported.", arg); break; default: DIE_IF("Program has a bug."); break; } } /* Exclusion check */ if (pp->lazy_line && pp->line) semantic_error("Lazy pattern can't be used with line number."); if (pp->lazy_line && pp->offset) semantic_error("Lazy pattern can't be used with offset."); if (pp->line && pp->offset) semantic_error("Offset can't be used with line number."); if (!pp->line && !pp->lazy_line && pp->file && !pp->function) semantic_error("File always requires line number or " "lazy pattern."); if (pp->offset && !pp->function) semantic_error("Offset requires an entry function."); if (pp->retprobe && !pp->function) semantic_error("Return probe requires an entry function."); if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe) semantic_error("Offset/Line/Lazy pattern can't be used with " "return probe."); pr_debug("symbol:%s file:%s line:%d offset:%d return:%d lazy:%s\n", pp->function, pp->file, pp->line, pp->offset, pp->retprobe, pp->lazy_line); }