コード例 #1
0
ファイル: cpp.c プロジェクト: rui314/8cc-old
/*
 * Reads function-like macro arguments.  Returns true if the argument list ends
 * with "...".  Otherwise false.
 */
static bool read_funclike_define_args(CppContext *ctx, Dict *param) {
    for (;;) {
        Token *tok = read_cpp_token(ctx);
        if (is_punct(tok, ')'))
            return false;
        if (dict_size(param)) {
            if (!is_punct(tok, ','))
                error_token(tok, "',' expected, but got '%s'", token_to_string(tok));
            tok = read_cpp_token(ctx);
        }
        if (!tok || tok->toktype == TOKTYPE_NEWLINE)
            error_token(tok, "missing ')' in macro parameter list");
        if (is_punct(tok, KEYWORD_THREEDOTS)) {
            Token *subst = make_token(ctx, TOKTYPE_MACRO_PARAM, (TokenValue)dict_size(param));
            dict_put(param, to_string("__VA_ARGS__"), subst);
            Token *tok1 = read_cpp_token(ctx);
            if (!is_punct(tok1, ')'))
                error_token(tok1, "')' expected, but got '%s'", token_to_string(tok1));
            return true;
        }
        if (tok->toktype != TOKTYPE_IDENT)
            error_token(tok, "identifier expected, but got '%s'", token_to_string(tok));
        Token *subst = make_token(ctx, TOKTYPE_MACRO_PARAM, (TokenValue)dict_size(param));
        dict_put(param, tok->val.str, subst);
    }
}
コード例 #2
0
ファイル: cpp.c プロジェクト: rui314/8cc-old
/*
 * Reads a file name of #include directive.  If the file name is quoted with <>,
 * "std" will set to true.  If quoted with doublequote, set to false.  We use
 * expand_one() rather than read_cpp_token(), because macros are allowed to be
 * used in #include.
 * (C99 6.10.2 Source file inclusion)
 */
static void read_cpp_header_name(CppContext *ctx, String **name, bool *std) {
    if (LIST_IS_EMPTY(ctx->ungotten)) {
        *name = read_header_name(ctx, std);
        if (name)
            return;
    }

    Token *tok = expand_one(ctx);
    if (!tok || tok->toktype == TOKTYPE_NEWLINE)
        error_token(tok, "expected file name, but got '%s'", token_to_string(tok));
    if (tok->toktype == TOKTYPE_STRING) {
        *name = tok->val.str;
        *std = false;
        return;
    }
    List *tokens = make_list();
    if (is_punct(tok, '<')) {
        for (;;) {
            Token *tok = expand_one(ctx);
            if (!tok || tok->toktype == TOKTYPE_NEWLINE)
                error_token(tok, "premature end of header name");
            if (is_punct(tok, '>'))
                break;
            list_push(tokens, tok);
        }
        *name = join_tokens(tokens, false);
        *std = true;
        return;
    }
    error_token(tok, "'<' expected, but got '%s'", token_to_string(tok));
}
コード例 #3
0
ファイル: cpp.c プロジェクト: rui314/8cc-old
/*
 * C99 6.10.9 Pragma operator.
 *
 * _Pragma("tokens ...") is equivalent to #pragma tokens ....
 */
static void handle_pragma_macro(CppContext *ctx, Token *ignore) {
    Token *tok = read_cpp_token(ctx);
    if (!is_punct(tok, '('))
        error_token(tok, "'(' expected, but got '%s'", token_to_string(tok));
    Token *body = read_cpp_token(ctx);
    if (body->toktype != TOKTYPE_STRING)
        error_token(body, "string expected, but got '%s'", token_to_string(body));
    tok = read_cpp_token(ctx);
    if (!is_punct(tok, ')'))
        error_token(tok, "')' expected, but got '%s'", token_to_string(tok));

    File *file = make_string_file(body->val.str);
    do_include(ctx, file);
    handle_pragma(ctx);
}
コード例 #4
0
ファイル: cpp.c プロジェクト: rui314/8cc-old
/*
 * #undef
 * (C99 6.10.5 Scope of macro definisions, paragraph 2)
 */
static void read_undef(CppContext *ctx) {
    Token *name = read_cpp_token(ctx);
    if (!name || name->toktype != TOKTYPE_IDENT)
        error_token(name, "undef works only to an identifier, but got '%s'", token_to_string(name));
    expect_newline(ctx);
    dict_delete(ctx->defs, name->val.str);
}
コード例 #5
0
ファイル: epur_str.c プロジェクト: JimmyYezeguelian/42sh
char		*epur_single(char *str, t_epur *e)
{
  int		l;

  l = 0;
  while (l < 5)
    {
      if (error_token(str, e, l) == -1)
	return (NULL);
      if (str[e->i] == e->com[l] && str[e->i + 1] != e->com[l]
	  && str[e->i - 1] != '2')
	{
	  if (str[e->i - 1] != ' ' && str[e->i + 1] != ' ')
	    {
	      e->tmp[e->k++] = ' ';
	      e->tmp[e->k++] = e->com[l];
	      e->tmp[e->k++] = ' ';
	      e->i++;
	    }
	  epur_single_next(str, e, l++);
	}
      else
	if (check_double(str, e, l++) == -1)
	  return (NULL);
    }
  return (e->tmp);
}
コード例 #6
0
ファイル: cpp.c プロジェクト: rui314/8cc-old
static Token *cppnum_to_int(Token *tok) {
    char *p = STRING_BODY(tok->val.str);
    int base = 10;
    int val = 0;
    // Read prefix such as "0" or "0x".
    if (*p == '0') {
        p++;
        if (*p == 'x' || *p == 'X') {
            base = 16;
            p++;
        } else if (*p == 'b' || *p == 'B') {
            // Binary constant using '0b' prefix is GNU extension
            base = 2;
            p++;
        } else {
            base = 8;
        }
    }
    // Read numbers until non-number character.
    for (; *p; p++) {
        int v;
        if ('0' <= *p && *p <= '9')
            v = *p - '0';
        else if ('a' <= *p && *p <= 'f')
            v = *p - 'a' + 10;
        else if ('A' <= *p && *p <= 'F')
            v = *p - 'A' + 10;
        else
            break;
        if (v >= base)
            error_token(tok, "invalid digit '%c' in base %d number", *p, base);
        val *= base;
        val += v;
    }
    // Ignore all suffixes for now
    while (*p == 'U' || *p == 'u' || *p == 'L' || *p == 'l')
        p++;
    if (*p)
        error_token(tok, "invalid char '%c' in a number '%s'", *p, STRING_BODY(tok->val.str));

    Token *r = copy_token(tok);
    r->toktype = TOKTYPE_INT;
    r->val.i = val;
    return r;
}
コード例 #7
0
ファイル: cpp.c プロジェクト: rui314/8cc-old
/*
 * #error
 * (C99 6.10.5 Error directive)
 */
static void read_error_directive(CppContext *ctx, Token *define) {
    String *buf = make_string();
    Token *tok = read_cpp_token(ctx);
    while(tok && tok->toktype != TOKTYPE_NEWLINE) {
        o1(buf, ' ');
        string_append(buf, token_to_string(tok));
        tok = read_cpp_token(ctx);
    }
    error_token(define, "error: #error:%s", STRING_BODY(buf));
}
コード例 #8
0
ファイル: cpp.c プロジェクト: rui314/8cc-old
/*
 * #line
 * (C99 6.10.4 Line control)
 *
 * Line directive must be one of the following form in macro-expanded form:
 *
 *     #line digit-sequence
 *     #line digit-sequence "s-char-sequenceopt"
 */
static void handle_line_directive(CppContext *ctx) {
    Token *tok = expand_one(ctx);
    if (!tok || tok->toktype != TOKTYPE_CPPNUM)
        error_token(tok, "number expected, but got '%s'", token_to_string(tok));
    int line = cppnum_to_num(tok)->val.i;

    tok = expand_one(ctx);
    if (tok && tok->toktype == TOKTYPE_NEWLINE) {
        ctx->file->line = line;
        return;
    }
    if (tok && tok->toktype == TOKTYPE_STRING) {
        expect_newline(ctx);
        ctx->file->line = line;
        ctx->file->filename = tok->val.str;
        return;
    }
    error_token(tok, "filename expected, but got '%s'", token_to_string(tok));
}
コード例 #9
0
ファイル: cpp.c プロジェクト: rui314/8cc-old
/*
 * Reads "defined" unary operator of the form "defined <identifier>" or
 * "defined(<identifier>)".  The token "defined" is already read when the
 * function is called.
 *
 * (C99 6.10.1 Conditional inclusion, paragraph 1)
 */
static Token *read_defined(CppContext *ctx) {
    Token *tok = read_cpp_token(ctx);
    if (is_punct(tok, '(')) {
        tok = read_cpp_token(ctx);
        Token *tok1 = read_cpp_token(ctx);
        if (!tok1 || !is_punct(tok1, ')'))
            error_token(tok1, "')' expected, but got '%s'", token_to_string(tok1));
    }
    Token *r = copy_token(tok);
    r->toktype = TOKTYPE_CPPNUM;
    r->val.i = is_defined(ctx, tok);
    return r;
}
コード例 #10
0
ファイル: cpp.c プロジェクト: rui314/8cc-old
static void paste(String *b, Token *tok) {
    switch (tok->toktype) {
    case TOKTYPE_IDENT:
    case TOKTYPE_CPPNUM:
        string_append(b, STRING_BODY(tok->val.str));
        return;
    case TOKTYPE_PUNCT:
        string_append(b, token_to_string(tok));
        return;
    default:
        error_token(tok, "pasting invalid token: '%s'", token_to_string(tok));
    }
}
コード例 #11
0
ファイル: cpp.c プロジェクト: rui314/8cc-old
/*
 * Evaluate a given tokens as an integer constant expression and returns the
 * result.
 */
static int eval_const_expr(CppContext *cppctx, List *tokens) {
    if (LIST_LEN(tokens) == 1 && ((Token *)LIST_REF(tokens, 0))->toktype == TOKTYPE_CPPNUM)
        return ((Token *)LIST_REF(tokens, 0))->val.i;

    CppContext *virt = make_virt_cpp_context(cppctx, tokens);
    ReadContext *readctx = make_read_context(cppctx->file, NULL, virt);
    readctx->in_const_expr = true;
    Var *var = read_comma_expr(readctx);

    Token *tok = read_token(readctx);
    if (tok)
        error_token(tok, "newline expected, but got '%s'", token_to_string(tok));

    ASSERT(var->stype == VAR_IMM);
    if (!ctype_equal(var->ctype, CTYPE_INT))
        error_cpp_ctx(cppctx, "integer expected");
    return var->val.i;
}
コード例 #12
0
ファイル: cpp.c プロジェクト: rui314/8cc-old
static void read_directive(CppContext *ctx) {
    Token *tok;
    if (read_if(ctx, "define"))       read_define(ctx);
    else if (read_if(ctx, "undef"))   read_undef(ctx);
    else if (read_if(ctx, "if"))      handle_cond_incl(ctx, COND_IF);
    else if (read_if(ctx, "elif"))    handle_cond_incl(ctx, COND_ELIF);
    else if (read_if(ctx, "else"))    handle_cond_incl(ctx, COND_ELSE);
    else if (read_if(ctx, "ifdef"))   handle_cond_incl(ctx, COND_IFDEF);
    else if (read_if(ctx, "ifndef"))  handle_cond_incl(ctx, COND_IFNDEF);
    else if (read_if(ctx, "endif"))   handle_cond_incl(ctx, COND_ENDIF);
    else if (read_if(ctx, "include")) handle_include(ctx);
    else if (read_if(ctx, "line"))    handle_line_directive(ctx);
    else if (read_if(ctx, "pragma"))  handle_pragma(ctx);
    else if ( (tok = read_if(ctx, "error")) ) {
        read_error_directive(ctx, tok);
    } else {
        tok = read_cpp_token(ctx);
        if (tok && tok->toktype == TOKTYPE_NEWLINE)
            // 6.10.7 NULL directive.  Do nothing.
            return;
        error_token(tok, "unsupported preprocessor directive: '%s'", token_to_string(tok));
    }
}
コード例 #13
0
ファイル: cpp.c プロジェクト: rui314/8cc-old
/*
 * Reads comma-separated arguments of function-like macro invocation.  Comma
 * characters in matching parentheses are not considered as separator.
 *
 * (C99 6.10.3 Macro replacement, sentence 10)
 */
static List *read_args_int(CppContext *ctx, Macro *macro) {
    List *r = make_list();
    List *arg = make_list();
    int depth = 0;

    Token *tok = peek_cpp_token(ctx);
    if (!tok || !is_punct(tok, '('))
        return NULL;
    read_cpp_token(ctx);

    for (Token *tok1 = read_cpp_token(ctx); ; tok1 = read_cpp_token(ctx)) {
        if (!tok1)
            error_token(tok, "unterminated macro argument list");
        if (tok1->toktype == TOKTYPE_NEWLINE)
            continue;
        if (depth) {
            if (is_punct(tok1, ')'))
                depth--;
            list_push(arg, tok1);
            continue;
        }
        if (is_punct(tok1, '('))
            depth++;
        if (is_punct(tok1, ')')) {
            unget_cpp_token(ctx, tok1);
            list_push(r, arg);
            return r;
        }
        bool in_threedots = macro->is_varg && LIST_LEN(r) + 1 == macro->nargs;
        if (is_punct(tok1, ',') && !in_threedots) {
            list_push(r, arg);
            arg = make_list();
            continue;
        }
        list_push(arg, tok1);
    }
}
コード例 #14
0
ファイル: cpp.c プロジェクト: rui314/8cc-old
static bool is_defined(CppContext *ctx, Token *tok) {
    if (!tok || tok->toktype != TOKTYPE_IDENT)
        error_token(tok, "identifier expected, but got '%s'", token_to_string(tok));
    return dict_has(ctx->defs, tok->val.str);
}
コード例 #15
0
ファイル: cpp.c プロジェクト: rui314/8cc-old
void expect_newline(CppContext *ctx) {
    Token *tok = read_cpp_token(ctx);
    if (tok && tok->toktype != TOKTYPE_NEWLINE)
        error_token(tok, "newline expected, but got '%s'", token_to_string(tok));

}