/* FOLLOW(parameter-list) = { ')' }, peek to return empty list; even though K&R * require at least specifier: (void) * Set parameter-type-list = parameter-list, including the , ... */ static struct typetree *parameter_list(const struct typetree *base) { struct typetree *func = type_init(T_FUNCTION); func->next = base; while (peek().token != ')') { const char *name = NULL; struct typetree *type; type = declaration_specifiers(NULL); type = declarator(type, &name); if (is_void(type)) { if (nmembers(func)) { error("Incomplete type in parameter list."); } break; } type_add_member(func, name, type); if (peek().token != ',') { break; } consume(','); if (peek().token == ')') { error("Unexpected trailing comma in parameter list."); exit(1); } else if (peek().token == DOTS) { consume(DOTS); assert(!is_vararg(func)); type_add_member(func, "...", NULL); assert(is_vararg(func)); break; } } return func; }
static void generate_stub(int nparms) { FILE *stream = open_stub(); char formal[MAX_PARMSIZE]; char actual[MAX_PARMSIZE]; int i; int j; /* Generate "up-front" information, include correct header files */ fprintf(stream, "/* Auto-generated %s stub file -- do not edit */\n\n", g_parm[0]); fprintf(stream, "#include <nuttx/config.h>\n"); fprintf(stream, "#include <stdint.h>\n"); fprintf(stream, "#include <%s>\n\n", g_parm[HEADER_INDEX]); if (g_parm[COND_INDEX][0] != '\0') { fprintf(stream, "#if %s\n\n", g_parm[COND_INDEX]); } /* Generate the function definition that matches standard function prototype */ if (g_inline) { fprintf(stream, "static inline "); } fprintf(stream, "uintptr_t STUB_%s(", g_parm[NAME_INDEX]); /* Generate the formal parameter list. A function received no parameters is a special case. */ if (nparms <= 0) { fprintf(stream, "void"); } else { for (i = 0; i < nparms; i++) { /* Treat the first argument in the list differently from the others.. * It does not need a comma before it. */ if (i > 0) { /* Check for a variable number of arguments */ if (is_vararg(g_parm[PARM1_INDEX+i], i, nparms)) { /* Always receive six arguments in this case */ for (j = i+1; j <= 6; j++) { fprintf(stream, ", uintptr_t parm%d", j); } } else { fprintf(stream, ", uintptr_t parm%d", i+1); } } else { fprintf(stream, "uintptr_t parm%d", i+1); } } } fprintf(stream, ")\n{\n"); /* Then call the proxied function. Functions that have no return value are * a special case. */ if (strcmp(g_parm[RETTYPE_INDEX], "void") == 0) { fprintf(stream, " %s(", g_parm[NAME_INDEX]); } else { fprintf(stream, " return (uintptr_t)%s(", g_parm[NAME_INDEX]); } /* The pass all of the system call parameters, casting to the correct type * as necessary. */ for (i = 0; i < nparms; i++) { /* Get the formal type of the parameter, and get the type that we * actually have to cast to. For example for a formal type like 'int parm[]' * we have to cast the actual parameter to 'int*'. The worst is a union * type like 'union sigval' where we have to cast to (union sigval)((FAR void *)parm) * -- Yech. */ get_formalparmtype(g_parm[PARM1_INDEX+i], formal); get_actualparmtype(g_parm[PARM1_INDEX+i], actual); /* Treat the first argument in the list differently from the others.. * It does not need a comma before it. */ if (i > 0) { /* Check for a variable number of arguments */ if (is_vararg(actual, i, nparms)) { /* Always pass six arguments */ for (j = i+1; j <=6; j++) { fprintf(stream, ", parm%d", j); } } else { if (is_union(formal)) { fprintf(stream, ", (%s)((%s)parm%d)", formal, actual, i+1); } else { fprintf(stream, ", (%s)parm%d", actual, i+1); } } } else { if (is_union(formal)) { fprintf(stream, "(%s)((%s)parm%d)", formal, actual, i+1); } else { fprintf(stream, "(%s)parm%d",actual, i+1); } } } /* Tail end of the function. If the proxied function has no return * value, just return zero (OK). */ if (strcmp(g_parm[RETTYPE_INDEX], "void") == 0) { fprintf(stream, ");\n return 0;\n}\n\n"); } else { fprintf(stream, ");\n}\n\n"); } if (g_parm[COND_INDEX][0] != '\0') { fprintf(stream, "#endif /* %s */\n", g_parm[COND_INDEX]); } stub_close(stream); }
static void generate_proxy(int nparms) { FILE *stream = open_proxy(); char formal[MAX_PARMSIZE]; char fieldname[MAX_PARMSIZE]; bool bvarargs = false; int nformal; int nactual; int i; /* Generate "up-front" information, include correct header files */ fprintf(stream, "/* Auto-generated %s proxy file -- do not edit */\n\n", g_parm[NAME_INDEX]); fprintf(stream, "#include <nuttx/config.h>\n"); /* Does this function have a variable number of parameters? If so then the * final parameter type will be encoded as "..." */ if (is_vararg(g_parm[PARM1_INDEX+nparms-1], nparms-1, nparms)) { nformal = nparms-1; bvarargs = true; fprintf(stream, "#include <stdarg.h>\n"); } else { nformal = nparms; } fprintf(stream, "#include <%s>\n", g_parm[HEADER_INDEX]); fprintf(stream, "#include <syscall.h>\n\n"); if (g_parm[COND_INDEX][0] != '\0') { fprintf(stream, "#if %s\n\n", g_parm[COND_INDEX]); } /* Generate the function definition that matches standard function prototype */ fprintf(stream, "%s %s(", g_parm[RETTYPE_INDEX], g_parm[NAME_INDEX]); /* Generate the formal parameter list */ if (nformal <= 0) { fprintf(stream, "void"); } else { for (i = 0; i < nformal; i++) { /* The formal and actual parameter types may be encoded.. extra the * formal parameter type. */ get_formalparmtype(g_parm[PARM1_INDEX+i], formal); /* Arguments after the first must be separated from the preceding * parameter with a comma. */ if (i > 0) { fprintf(stream, ", "); } print_formalparm(stream, formal, i+1); } } /* Handle the end of the formal parameter list */ if (bvarargs) { fprintf(stream, ", ...)\n{\n"); /* Get parm variables .. some from the parameter list and others from * the varargs. */ if (nparms < 7) { fprintf(stream, " va_list ap;\n"); for (i = nparms; i < 7; i++) { fprintf(stream, " uintptr_t parm%d;\n", i); } fprintf(stream, "\n va_start(ap, parm%d);\n", nparms-1); for (i = nparms; i < 7; i++) { fprintf(stream, " parm%d = va_arg(ap, uintptr_t);\n", i); } fprintf(stream, " va_end(ap);\n\n"); } } else { fprintf(stream, ")\n{\n"); } /* Generate the system call. Functions that do not return or return void * are special cases. */ nactual = bvarargs ? 6 : nparms; if (strcmp(g_parm[RETTYPE_INDEX], "void") == 0) { fprintf(stream, " (void)sys_call%d(", nactual); } else { fprintf(stream, " return (%s)sys_call%d(", g_parm[RETTYPE_INDEX], nactual); } /* Create the parameter list with the matching types. The first parameter * is always the syscall number. */ fprintf(stream, "(unsigned int)SYS_%s", g_parm[NAME_INDEX]); for (i = 0; i < nactual; i++) { /* Is the parameter a union member */ if (i < nparms && is_union(g_parm[PARM1_INDEX+i])) { /* Then we will have to pick a field name that can be cast to a * uintptr_t. There probably should be some error handling here * to catch the case where the fieldname was not supplied. */ get_fieldname(g_parm[PARM1_INDEX+i], fieldname); fprintf(stream, ", (uintptr_t)parm%d.%s", i+1, fieldname); } else { fprintf(stream, ", (uintptr_t)parm%d", i+1); } } /* Handle the tail end of the function. */ fprintf(stream, ");\n}\n\n"); if (g_parm[COND_INDEX][0] != '\0') { fprintf(stream, "#endif /* %s */\n", g_parm[COND_INDEX]); } fclose(stream); }
static struct block *postfix_expression(struct block *block) { struct var root; block = primary_expression(block); root = block->expr; while (1) { const struct member *field; const struct typetree *type; struct var expr, copy, *arg; struct token tok; int i, j; switch ((tok = peek()).token) { case '[': do { /* Evaluate a[b] = *(a + b). The semantics of pointer arithmetic * takes care of multiplying b with the correct width. */ consume('['); block = expression(block); root = eval_expr(block, IR_OP_ADD, root, block->expr); root = eval_deref(block, root); consume(']'); } while (peek().token == '['); break; case '(': type = root.type; if (is_pointer(root.type) && is_function(root.type->next)) type = type_deref(root.type); else if (!is_function(root.type)) { error("Expression must have type pointer to function, was %t.", root.type); exit(1); } consume('('); arg = calloc(nmembers(type), sizeof(*arg)); for (i = 0; i < nmembers(type); ++i) { if (peek().token == ')') { error("Too few arguments, expected %d but got %d.", nmembers(type), i); exit(1); } block = assignment_expression(block); arg[i] = block->expr; /* todo: type check here. */ if (i < nmembers(type) - 1) { consume(','); } } while (is_vararg(type) && peek().token != ')') { consume(','); arg = realloc(arg, (i + 1) * sizeof(*arg)); block = assignment_expression(block); arg[i] = block->expr; i++; } consume(')'); for (j = 0; j < i; ++j) param(block, arg[j]); free(arg); root = eval_call(block, root); break; case '.': consume('.'); tok = consume(IDENTIFIER); field = find_type_member(root.type, tok.strval); if (!field) { error("Invalid field access, no member named '%s'.", tok.strval); exit(1); } root.type = field->type; root.offset += field->offset; break; case ARROW: consume(ARROW); tok = consume(IDENTIFIER); if (is_pointer(root.type) && is_struct_or_union(root.type->next)) { field = find_type_member(type_deref(root.type), tok.strval); if (!field) { error("Invalid field access, no member named '%s'.", tok.strval); exit(1); } /* Make it look like a pointer to the field type, then perform * normal dereferencing. */ root.type = type_init(T_POINTER, field->type); root = eval_deref(block, root); root.offset = field->offset; } else { error("Invalid field access."); exit(1); } break; case INCREMENT: consume(INCREMENT); copy = create_var(root.type); eval_assign(block, copy, root); expr = eval_expr(block, IR_OP_ADD, root, var_int(1)); eval_assign(block, root, expr); root = copy; break; case DECREMENT: consume(DECREMENT); copy = create_var(root.type); eval_assign(block, copy, root); expr = eval_expr(block, IR_OP_SUB, root, var_int(1)); eval_assign(block, root, expr); root = copy; break; default: block->expr = root; return block; } } }