#include "lex-internal.h" static enum bshell_status arithmetic_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; } enqueue_token(ctx, tok); return BSHELL_SUCCESS; } static enum bshell_status arithmetic_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_SQUOTE: status = read_literal_string(ctx, &tok); if (status != BSHELL_SUCCESS) { return status; } enqueue_token(ctx, tok); return BSHELL_SUCCESS; case BSHELL_SYM_HYPHEN: return arithmetic_hyphen(ctx); 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 arithmetic_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; } unsigned int token_type = BSHELL_TOK_WORD; bool kw = false, number = false; if (convert_word_to_keyword(word)) { token_type = word->tok_keyword; } else if (convert_word_to_number(word)) { token_type = word->tok_type; } handle_lex_state_transition(ctx, token_type); enqueue_token(ctx, word); return BSHELL_SUCCESS; } static enum bshell_status arithmetic_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 arithmetic_symbol(ctx); } return arithmetic_word(ctx); } static const struct bshell_lex_state_link links[] = { LINK_CHANGE(BSHELL_SYM_EQUAL, BSHELL_LEX_STATE_STATEMENT), LINK_PUSH(BSHELL_SYM_DQUOTE, BSHELL_LEX_STATE_STRING, 0), LINK_PUSH(BSHELL_SYM_DOLLAR_LEFT_PAREN, BSHELL_LEX_STATE_STATEMENT, 0), LINK_POP(BSHELL_SYM_RIGHT_PAREN), LINK_CHANGE(BSHELL_SYM_SEMICOLON, BSHELL_LEX_STATE_STATEMENT), LINK_CHANGE(BSHELL_TOK_LINEFEED, BSHELL_LEX_STATE_STATEMENT), LINK_CHANGE(BSHELL_SYM_PIPE, BSHELL_LEX_STATE_STATEMENT), LINK_PUSH(BSHELL_SYM_AT_LEFT_BRACE, BSHELL_LEX_STATE_HASHTABLE, 0), LINK_PUSH( BSHELL_SYM_LEFT_PAREN, BSHELL_LEX_STATE_STATEMENT, STATEMENT_F_DISABLE_KEYWORDS), LINK_END, }; static const unsigned int keywords[] = { BSHELL_KW_IF, BSHELL_KW_ELSEIF, BSHELL_KW_ELSE, BSHELL_KW_NONE, }; static const unsigned int operators[] = { BSHELL_TKOP_F, BSHELL_TKOP_BAND, BSHELL_TKOP_BOR, BSHELL_TKOP_BXOR, BSHELL_TKOP_BNOT, BSHELL_TKOP_SHL, BSHELL_TKOP_SHR, BSHELL_TKOP_EQ, BSHELL_TKOP_NE, BSHELL_TKOP_GT, BSHELL_TKOP_LT, BSHELL_TKOP_GE, BSHELL_TKOP_LE, BSHELL_TKOP_MATCH, BSHELL_TKOP_NOTMATCH, BSHELL_TKOP_REPLACE, BSHELL_TKOP_LIKE, BSHELL_TKOP_NOTLIKE, BSHELL_TKOP_IN, BSHELL_TKOP_NOTIN, BSHELL_TKOP_CONTAINS, BSHELL_TKOP_NOTCONTAINS, BSHELL_TKOP_AND, BSHELL_TKOP_OR, BSHELL_TKOP_XOR, BSHELL_TKOP_NOT, BSHELL_TKOP_SPLIT, BSHELL_TKOP_JOIN, BSHELL_TKOP_IS, BSHELL_TKOP_ISNOT, BSHELL_TKOP_AS, BSHELL_TKOP_NONE, }; static const unsigned int symbols[] = { BSHELL_SYM_BANG, BSHELL_SYM_PLUS, BSHELL_SYM_HYPHEN, BSHELL_SYM_FORWARD_SLASH, BSHELL_SYM_ASTERISK, BSHELL_SYM_AMPERSAND, BSHELL_SYM_PERCENT, BSHELL_SYM_SQUOTE, BSHELL_SYM_DQUOTE, BSHELL_SYM_HASH, BSHELL_SYM_DOLLAR, BSHELL_SYM_DOLLAR_LEFT_PAREN, BSHELL_SYM_DOLLAR_LEFT_BRACE, BSHELL_SYM_AT, BSHELL_SYM_AT_LEFT_BRACE, BSHELL_SYM_PIPE, BSHELL_SYM_COMMA, BSHELL_SYM_SEMICOLON, BSHELL_SYM_LEFT_PAREN, BSHELL_SYM_RIGHT_PAREN, BSHELL_SYM_LEFT_BRACE, BSHELL_SYM_RIGHT_BRACE, BSHELL_SYM_LEFT_BRACKET, BSHELL_SYM_RIGHT_BRACKET, BSHELL_SYM_QUESTION_DOT, BSHELL_SYM_QUESTION_LEFT_BRACKET, BSHELL_SYM_EQUAL, BSHELL_SYM_PLUS_EQUAL, BSHELL_SYM_HYPHEN_EQUAL, BSHELL_SYM_FORWARD_SLASH_EQUAL, BSHELL_SYM_ASTERISK_EQUAL, BSHELL_SYM_PERCENT_EQUAL, BSHELL_SYM_DOT, BSHELL_SYM_DOT_DOT, BSHELL_SYM_COLON_COLON, BSHELL_SYM_NONE, }; const struct bshell_lex_state_type lex_arithmetic_state = { .s_id = BSHELL_LEX_STATE_ARITHMETIC, .s_pump_token = arithmetic_pump_token, .s_links = links, .s_keywords = keywords, .s_operators = operators, .s_symbols = symbols, };