edfb3e24a3
bshell: the front-end binary bshell.runtime: contains the parser, compiler, and classes needed to run bshell scripts bshell.core: contains the builtin commandlets and aliases
233 lines
6.1 KiB
C
233 lines
6.1 KiB
C
#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,
|
|
};
|