#include "lex-internal.h" static enum bshell_status statement_hyphen(struct bshell_lex_ctx *ctx) { fx_wchar c = peek_char(ctx); if (!fx_wchar_is_alnum(c)) { push_symbol(ctx, BSHELL_SYM_HYPHEN); handle_lex_state_transition(ctx, BSHELL_SYM_HYPHEN); return BSHELL_SUCCESS; } struct bshell_lex_token *tok = NULL; enum bshell_status status = read_word( ctx, READ_NO_SET_TOKEN_START | READ_APPEND_HYPHEN, &tok); if (status != BSHELL_SUCCESS) { return status; } unsigned int token_type = BSHELL_TOK_WORD; if (convert_word_to_number(tok)) { token_type = tok->tok_type; /* because of APPEND_HYPHEN (which is needed to ensure operator * tokens are detected properly), the resulting number will be * negative. * this token will be preceded by a HYPHEN token, so the number * must be positive */ fx_value neg = FX_INT(-1); fx_value_multiply(&tok->tok_number, &neg, &tok->tok_number); push_symbol(ctx, BSHELL_SYM_HYPHEN); } else if (convert_word_to_operator(ctx, tok)) { token_type = tok->tok_operator; } handle_lex_state_transition(ctx, token_type); enqueue_token(ctx, tok); return BSHELL_SUCCESS; } static enum bshell_status statement_symbol(struct bshell_lex_ctx *ctx) { const struct bshell_lex_token_definition *sym = NULL; enum bshell_status status = read_symbol(ctx, &sym); if (status != BSHELL_SUCCESS) { return status; } handle_lex_state_transition(ctx, sym->id); struct bshell_lex_token *tok = NULL; switch (sym->id) { case BSHELL_SYM_DQUOTE: return BSHELL_SUCCESS; case BSHELL_SYM_HYPHEN: return statement_hyphen(ctx); case BSHELL_SYM_SQUOTE: status = read_literal_string(ctx, &tok); if (status != BSHELL_SUCCESS) { return status; } enqueue_token(ctx, tok); return BSHELL_SUCCESS; case BSHELL_SYM_HASH: return read_line_comment(ctx); case BSHELL_SYM_DOLLAR: status = read_var(ctx, BSHELL_TOK_VAR, &tok); if (status != BSHELL_SUCCESS) { return status; } enqueue_token(ctx, tok); return status; case BSHELL_SYM_AT: status = read_var(ctx, BSHELL_TOK_VAR_SPLAT, &tok); if (status != BSHELL_SUCCESS) { return status; } enqueue_token(ctx, tok); return status; case BSHELL_SYM_DOLLAR_LEFT_BRACE: status = read_braced_var(ctx, BSHELL_TOK_VAR, &tok); if (status != BSHELL_SUCCESS) { return status; } enqueue_token(ctx, tok); return status; default: break; } push_symbol(ctx, sym->id); return BSHELL_SUCCESS; } static enum bshell_status statement_word(struct bshell_lex_ctx *ctx) { struct bshell_lex_token *word = NULL; enum bshell_status status = read_word(ctx, 0, &word); if (status != BSHELL_SUCCESS) { return status; } struct bshell_lex_state *state = lex_state_get(ctx); bool enable_keywords = !(state->s_flags & STATEMENT_F_DISABLE_KEYWORDS); unsigned int token = BSHELL_TOK_WORD; if (enable_keywords && convert_word_to_keyword(word)) { token = word->tok_keyword; } else if (convert_word_to_number(word)) { token = word->tok_type; } handle_lex_state_transition(ctx, token); enqueue_token(ctx, word); return BSHELL_SUCCESS; } static enum bshell_status statement_pump_token(struct bshell_lex_ctx *ctx) { fx_wchar c = peek_char(ctx); bool newline = false; set_token_start(ctx); while (fx_wchar_is_space(c)) { if (c == '\n') { newline = true; } set_token_end(ctx); advance_char_noread(ctx); c = peek_char_noread(ctx); } if (newline) { struct bshell_lex_token *tok = bshell_lex_token_create(BSHELL_TOK_LINEFEED); enqueue_token(ctx, tok); handle_lex_state_transition(ctx, BSHELL_TOK_LINEFEED); return BSHELL_SUCCESS; } if (char_can_begin_symbol(ctx, c)) { return statement_symbol(ctx); } if (char_has_flags(ctx, c, BSHELL_LEX_TOKEN_UNARY_ARITHMETIC)) { lex_state_change(ctx, BSHELL_LEX_STATE_ARITHMETIC); return BSHELL_SUCCESS; } return statement_word(ctx); } static const struct bshell_lex_state_link links[] = { LINK_PUSH(BSHELL_SYM_DQUOTE, BSHELL_LEX_STATE_STRING, 0), /* arithmetic tokens */ LINK_CHANGE(BSHELL_TOK_KEYWORD, BSHELL_LEX_STATE_ARITHMETIC), LINK_CHANGE(BSHELL_SYM_SQUOTE, BSHELL_LEX_STATE_ARITHMETIC), LINK_CHANGE(BSHELL_TOK_INT, BSHELL_LEX_STATE_ARITHMETIC), LINK_CHANGE(BSHELL_TOK_DOUBLE, BSHELL_LEX_STATE_ARITHMETIC), LINK_PUSH(BSHELL_SYM_DOLLAR, BSHELL_LEX_STATE_ARITHMETIC, 0), LINK_PUSH_WITH_TERM( BSHELL_SYM_DOLLAR_LEFT_BRACE, BSHELL_LEX_STATE_ARITHMETIC, 0, BSHELL_SYM_RIGHT_BRACE), LINK_CHANGE(BSHELL_SYM_AT_LEFT_BRACE, BSHELL_LEX_STATE_ARITHMETIC), LINK_CHANGE(BSHELL_SYM_AT_LEFT_PAREN, BSHELL_LEX_STATE_ARITHMETIC), LINK_PUSH_WITH_TERM( BSHELL_SYM_AT_LEFT_BRACE, BSHELL_LEX_STATE_HASHTABLE, 0, BSHELL_SYM_RIGHT_BRACE), LINK_PUSH(BSHELL_SYM_AT, BSHELL_LEX_STATE_ARITHMETIC, 0), LINK_CHANGE(BSHELL_SYM_LEFT_PAREN, BSHELL_LEX_STATE_ARITHMETIC), LINK_CHANGE(BSHELL_SYM_LEFT_BRACKET, BSHELL_LEX_STATE_ARITHMETIC), LINK_CHANGE(BSHELL_SYM_BANG, BSHELL_LEX_STATE_ARITHMETIC), LINK_PUSH_WITH_TERM( BSHELL_SYM_LEFT_PAREN, BSHELL_LEX_STATE_STATEMENT, STATEMENT_F_DISABLE_KEYWORDS, BSHELL_SYM_RIGHT_PAREN), /* statement tokens */ LINK_PUSH_WITH_TERM( BSHELL_SYM_LEFT_BRACE, BSHELL_LEX_STATE_STATEMENT, 0, BSHELL_SYM_RIGHT_BRACE), LINK_PUSH_WITH_TERM( BSHELL_SYM_DOLLAR_LEFT_PAREN, BSHELL_LEX_STATE_STATEMENT, 0, BSHELL_SYM_RIGHT_PAREN), /* command tokens */ LINK_CHANGE(BSHELL_KW_FUNC, BSHELL_LEX_STATE_COMMAND), LINK_CHANGE(BSHELL_SYM_AMPERSAND, BSHELL_LEX_STATE_COMMAND), LINK_CHANGE(BSHELL_TOK_WORD, BSHELL_LEX_STATE_COMMAND), LINK_END, }; static const unsigned int keywords[] = { BSHELL_KW_FUNC, BSHELL_KW_IF, BSHELL_KW_ELSEIF, BSHELL_KW_ELSE, BSHELL_KW_NONE, }; static const unsigned int operators[] = { BSHELL_TKOP_BNOT, BSHELL_TKOP_NOT, BSHELL_TKOP_NONE, }; static const unsigned int symbols[] = { BSHELL_SYM_AMPERSAND, BSHELL_SYM_BANG, BSHELL_SYM_SQUOTE, BSHELL_SYM_DQUOTE, BSHELL_SYM_HASH, BSHELL_SYM_AT, BSHELL_SYM_AT_LEFT_PAREN, BSHELL_SYM_AT_LEFT_BRACE, BSHELL_SYM_PIPE, BSHELL_SYM_COMMA, BSHELL_SYM_SEMICOLON, BSHELL_SYM_LEFT_BRACE, BSHELL_SYM_RIGHT_BRACE, BSHELL_SYM_LEFT_BRACKET, BSHELL_SYM_RIGHT_BRACKET, BSHELL_SYM_LEFT_PAREN, BSHELL_SYM_RIGHT_PAREN, BSHELL_SYM_NONE, }; const struct bshell_lex_state_type lex_statement_state = { .s_id = BSHELL_LEX_STATE_STATEMENT, .s_pump_token = statement_pump_token, .s_links = links, .s_keywords = keywords, .s_operators = operators, .s_symbols = symbols, };