X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Flanguage%2Fcommand.c;h=e67f6ab80800352ec1132cdb9d36866c87e63c3f;hb=refs%2Fheads%2Fvariable-sets;hp=068ae0ea631a7f19da70898336a2414052205c55;hpb=cd221d80fafb54e550398c6de105d4c1b7f02ba0;p=pspp diff --git a/src/language/command.c b/src/language/command.c index 068ae0ea63..e67f6ab808 100644 --- a/src/language/command.c +++ b/src/language/command.c @@ -55,9 +55,6 @@ cmd_result_is_valid (enum cmd_result result) case CMD_SUCCESS: case CMD_EOF: case CMD_FINISH: - case CMD_DATA_LIST: - case CMD_END_CASE: - case CMD_END_FILE: case CMD_FAILURE: case CMD_NOT_IMPLEMENTED: case CMD_CASCADING_FAILURE: @@ -89,19 +86,23 @@ cmd_result_is_failure (enum cmd_result result) /* Command processing states. */ enum states { - S_INITIAL = 0x01, /* Allowed before active dataset defined. */ - S_DATA = 0x02, /* Allowed after active dataset defined. */ - S_INPUT_PROGRAM = 0x04, /* Allowed in INPUT PROGRAM. */ - S_FILE_TYPE = 0x08, /* Allowed in FILE TYPE. */ - S_ANY = 0x0f /* Allowed anywhere. */ + S_INITIAL = 1 << CMD_STATE_INITIAL, + S_DATA = 1 << CMD_STATE_DATA, + S_INPUT_PROGRAM = 1 << CMD_STATE_INPUT_PROGRAM, + S_FILE_TYPE = 1 << CMD_STATE_FILE_TYPE, + S_NESTED_DATA = 1 << CMD_STATE_NESTED_DATA, + S_NESTED_INPUT_PROGRAM = 1 << CMD_STATE_NESTED_INPUT_PROGRAM, + + S_NESTED_ANY = S_NESTED_DATA | S_NESTED_INPUT_PROGRAM, + S_ANY = S_INITIAL | S_DATA | S_INPUT_PROGRAM | S_FILE_TYPE | S_NESTED_ANY, }; /* Other command requirements. */ enum flags { - F_ENHANCED = 0x10, /* Allowed only in enhanced syntax mode. */ - F_TESTING = 0x20, /* Allowed only in testing mode. */ - F_ABBREV = 0x80 /* Not a candidate for name completion. */ + F_ENHANCED = 1 << 0, /* Allowed only in enhanced syntax mode. */ + F_TESTING = 1 << 1, /* Allowed only in testing mode. */ + F_ABBREV = 1 << 2 /* Not a candidate for name completion. */ }; /* A single command. */ @@ -123,10 +124,10 @@ static const struct command commands[] = #undef DEF_CMD #undef UNIMPL_CMD -static const size_t command_cnt = sizeof commands / sizeof *commands; +static const size_t n_commands = sizeof commands / sizeof *commands; static bool in_correct_state (const struct command *, enum cmd_state); -static bool report_state_mismatch (const struct command *, enum cmd_state); +static char *report_state_mismatch (const struct command *, enum cmd_state); static void set_completion_state (enum cmd_state); /* Command parser. */ @@ -162,7 +163,7 @@ cmd_parse (struct lexer *lexer, struct dataset *ds) const struct dictionary *dict = dataset_dict (ds); return cmd_parse_in_state (lexer, ds, dataset_has_source (ds) && - dict_get_var_cnt (dict) > 0 ? + dict_get_n_vars (dict) > 0 ? CMD_STATE_DATA : CMD_STATE_INITIAL); } @@ -204,25 +205,32 @@ do_parse_command (struct lexer *lexer, utf8_to_title (command->name), utf8_to_title (command->name))); + int end = n_tokens - 1; if (command->function == NULL) { - msg (SE, _("%s is not yet implemented."), command->name); + lex_ofs_error (lexer, 0, end, _("%s is not yet implemented."), + command->name); result = CMD_NOT_IMPLEMENTED; } else if ((command->flags & F_TESTING) && !settings_get_testing_mode ()) { - msg (SE, _("%s may be used only in testing mode."), command->name); + lex_ofs_error (lexer, 0, end, _("%s may be used only in testing mode."), + command->name); result = CMD_FAILURE; } else if ((command->flags & F_ENHANCED) && settings_get_syntax () != ENHANCED) { - msg (SE, _("%s may be used only in enhanced syntax mode."), - command->name); + lex_ofs_error (lexer, 0, end, + _("%s may be used only in enhanced syntax mode."), + command->name); result = CMD_FAILURE; } else if (!in_correct_state (command, state)) { - report_state_mismatch (command, state); + char *message = report_state_mismatch (command, state); + lex_ofs_error (lexer, 0, end, "%s", message); + free (message); + result = CMD_FAILURE; } else @@ -262,7 +270,7 @@ find_best_match (struct substring s, const struct command **matchp) int missing_words; command_matcher_init (&cm, s); - for (cmd = commands; cmd < &commands[command_cnt]; cmd++) + for (cmd = commands; cmd < &commands[n_commands]; cmd++) command_matcher_add (&cm, ss_cstr (cmd->name), CONST_CAST (void *, cmd)); *matchp = command_matcher_get_match (&cm); @@ -341,17 +349,18 @@ parse_command_name (struct lexer *lexer, int *n_tokens) ds_truncate (&s, ds_length (&s) - 2); } + *n_tokens = (word + 1) + missing_words; if (command == NULL) { if (ds_is_empty (&s)) - lex_error (lexer, _("expecting command name")); + lex_error (lexer, _("Syntax error expecting command name.")); else - msg (SE, _("Unknown command `%s'."), ds_cstr (&s)); + lex_ofs_error (lexer, 0, *n_tokens - 1, + _("Unknown command `%s'."), ds_cstr (&s)); } ds_destroy (&s); - *n_tokens = (word + 1) + missing_words; return command; } @@ -360,75 +369,68 @@ parse_command_name (struct lexer *lexer, int *n_tokens) static bool in_correct_state (const struct command *command, enum cmd_state state) { - return ((state == CMD_STATE_INITIAL && command->states & S_INITIAL) - || (state == CMD_STATE_DATA && command->states & S_DATA) - || (state == CMD_STATE_INPUT_PROGRAM - && command->states & S_INPUT_PROGRAM) - || (state == CMD_STATE_FILE_TYPE && command->states & S_FILE_TYPE)); + return command->states & (1 << state); } -/* Emits an appropriate error message for trying to invoke +/* Returns an appropriate error message for trying to invoke COMMAND in STATE. */ -static bool +static char * report_state_mismatch (const struct command *command, enum cmd_state state) { assert (!in_correct_state (command, state)); - if (state == CMD_STATE_INITIAL || state == CMD_STATE_DATA) + + switch (state) { - switch ((int) command->states) + case CMD_STATE_INITIAL: + case CMD_STATE_DATA: + switch ((int) command->states + & (S_INITIAL | S_DATA | S_INPUT_PROGRAM | S_FILE_TYPE)) { /* One allowed state. */ case S_INITIAL: - msg (SE, _("%s is allowed only before the active dataset has " - "been defined."), command->name); - break; + return xasprintf (_("%s is allowed only before the active dataset has " + "been defined."), command->name); case S_DATA: - msg (SE, _("%s is allowed only after the active dataset has " - "been defined."), command->name); - break; + return xasprintf (_("%s is allowed only after the active dataset has " + "been defined."), command->name); case S_INPUT_PROGRAM: - msg (SE, _("%s is allowed only inside %s."), - command->name, "INPUT PROGRAM"); - break; + return xasprintf (_("%s is allowed only inside %s."), + command->name, "INPUT PROGRAM"); case S_FILE_TYPE: - msg (SE, _("%s is allowed only inside %s."), command->name, "FILE TYPE"); - break; + return xasprintf (_("%s is allowed only inside %s."), command->name, "FILE TYPE"); /* Two allowed states. */ case S_INITIAL | S_DATA: NOT_REACHED (); case S_INITIAL | S_INPUT_PROGRAM: - msg (SE, _("%s is allowed only before the active dataset has been defined or inside %s."), - command->name, "INPUT PROGRAM"); - break; + return xasprintf (_("%s is allowed only before the active dataset " + "has been defined or inside %s."), + command->name, "INPUT PROGRAM"); case S_INITIAL | S_FILE_TYPE: - msg (SE, _("%s is allowed only before the active dataset has been defined or inside %s."), - command->name, "FILE TYPE"); - break; + return xasprintf (_("%s is allowed only before the active dataset " + "has been defined or inside %s."), + command->name, "FILE TYPE"); case S_DATA | S_INPUT_PROGRAM: - msg (SE, _("%s is allowed only after the active dataset has been defined or inside %s."), - command->name, "INPUT PROGRAM"); - break; + return xasprintf (_("%s is allowed only after the active dataset " + "has been defined or inside %s."), + command->name, "INPUT PROGRAM"); case S_DATA | S_FILE_TYPE: - msg (SE, _("%s is allowed only after the active dataset has been defined or inside %s."), - command->name, "FILE TYPE"); - break; + return xasprintf (_("%s is allowed only after the active dataset " + "has been defined or inside %s."), + command->name, "FILE TYPE"); case S_INPUT_PROGRAM | S_FILE_TYPE: - msg (SE, _("%s is allowed only inside %s or inside %s."), command->name, - "INPUT PROGRAM", "FILE TYPE"); - break; + return xasprintf (_("%s is allowed only inside %s or inside %s."), + command->name, "INPUT PROGRAM", "FILE TYPE"); /* Three allowed states. */ case S_DATA | S_INPUT_PROGRAM | S_FILE_TYPE: - msg (SE, _("%s is allowed only after the active dataset has " - "been defined, inside INPUT PROGRAM, or inside " - "FILE TYPE."), command->name); - break; + return xasprintf (_("%s is allowed only after the active dataset has " + "been defined, inside INPUT PROGRAM, or inside " + "FILE TYPE."), command->name); case S_INITIAL | S_INPUT_PROGRAM | S_FILE_TYPE: - msg (SE, _("%s is allowed only before the active dataset has " - "been defined, inside INPUT PROGRAM, or inside " - "FILE TYPE."), command->name); - break; + return xasprintf (_("%s is allowed only before the active dataset " + "has been defined, inside INPUT PROGRAM, or " + "inside FILE TYPE."), command->name); case S_INITIAL | S_DATA | S_FILE_TYPE: NOT_REACHED (); case S_INITIAL | S_DATA | S_INPUT_PROGRAM: @@ -438,17 +440,38 @@ report_state_mismatch (const struct command *command, enum cmd_state state) case S_INITIAL | S_DATA | S_INPUT_PROGRAM | S_FILE_TYPE: NOT_REACHED (); + default: + NOT_REACHED (); + } + break; + + case CMD_STATE_INPUT_PROGRAM: + return xasprintf (_("%s is not allowed inside %s."), + command->name, "INPUT PROGRAM"); + + case CMD_STATE_FILE_TYPE: + return xasprintf (_("%s is not allowed inside %s."), + command->name, "FILE TYPE"); + + case CMD_STATE_NESTED_DATA: + case CMD_STATE_NESTED_INPUT_PROGRAM: + switch ((int) command->states & S_NESTED_ANY) + { + case 0: + return xasprintf (_("%s is not allowed inside DO IF or LOOP."), + command->name); + + case S_NESTED_DATA: + return xasprintf (_("In INPUT PROGRAM, " + "%s is not allowed inside DO IF or LOOP."), + command->name); + default: NOT_REACHED (); } } - else if (state == CMD_STATE_INPUT_PROGRAM) - msg (SE, _("%s is not allowed inside %s."), - command->name, "INPUT PROGRAM"); - else if (state == CMD_STATE_FILE_TYPE) - msg (SE, _("%s is not allowed inside %s."), command->name, "FILE TYPE"); - return false; + NOT_REACHED (); } /* Command name completion. */ @@ -471,7 +494,7 @@ cmd_complete (const char *prefix, const struct command **cmd) if (*cmd == NULL) *cmd = commands; - for (; *cmd < commands + command_cnt; (*cmd)++) + for (; *cmd < commands + n_commands; (*cmd)++) if (!memcasecmp ((*cmd)->name, prefix, strlen (prefix)) && (!((*cmd)->flags & F_TESTING) || settings_get_testing_mode ()) && (!((*cmd)->flags & F_ENHANCED) || settings_get_syntax () == ENHANCED) @@ -525,7 +548,9 @@ cmd_erase (struct lexer *lexer, struct dataset *ds UNUSED) if (settings_get_safer_mode ()) { - msg (SE, _("This command not allowed when the %s option is set."), "SAFER"); + lex_ofs_error (lexer, 0, 0, + _("This command not allowed when the %s option is set."), + "SAFER"); return CMD_FAILURE; }