/*************************************************************************** gbc_trans_subr.c (c) 2000-2009 BenoƮt Minisini This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ***************************************************************************/ #define _TRANS_SUBR_C #include #include #include #include "gb_common.h" #include "gb_error.h" #include "gbc_compile.h" #include "gbc_trans.h" #include "gb_code.h" #include "gb_limit.h" /*#define DEBUG*/ typedef struct { char *name; SUBR_INFO *info; } TRANS_SUBR_INFO; static void trans_subr(int subr, int nparam) { static TRANS_SUBR_INFO subr_info[] = { { ".Print" }, { ".Input" }, { ".Write" }, { ".Read" }, { ".Open" }, { ".Close" }, { "Seek" }, { ".LineInput" }, { ".Flush" }, { ".Exec" }, { ".Shell" }, { ".Wait" }, { ".Kill" }, { ".Move" }, { ".Mkdir" }, { ".Rmdir" }, { ".Array" }, {".Collection" }, { ".Copy" }, { ".Link" }, { ".Error" }, { ".Lock" }, { ".Unlock" }, { ".InputFrom" }, { ".OutputTo" }, { ".Debug" }, { ".Sleep" }, { ".Randomize" }, { ".ErrorTo" }, { "Left" }, { "Mid" } }; TRANS_SUBR_INFO *tsi = &subr_info[subr]; if (tsi->info == NULL) { tsi->info = SUBR_get(tsi->name); if (!tsi->info) ERROR_panic("Unknown intern subroutine: %s", tsi->name); } CODE_subr(tsi->info->opcode, nparam, tsi->info->optype, FALSE, tsi->info->min_param == tsi->info->max_param); } static bool trans_stream(int default_stream) { if (TRANS_is(RS_SHARP)) { TRANS_expression(FALSE); if (PATTERN_is(*JOB->current, RS_COMMA)) { JOB->current++; if (PATTERN_is_newline(*JOB->current)) THROW(E_SYNTAX); } else { if (!PATTERN_is_newline(*JOB->current)) THROW(E_SYNTAX); } return FALSE; } else { if (default_stream == TS_NONE) THROW("Syntax error. '#' expected"); CODE_push_number(default_stream); return TRUE; } } static void trans_print_debug() { int nparam = 1; bool semicolon = FALSE; for(;;) { if (PATTERN_is_newline(*JOB->current)) break; TRANS_expression(FALSE); nparam++; semicolon = FALSE; if (PATTERN_is_newline(*JOB->current)) break; if (TRANS_is(RS_SCOLON)) { if (TRANS_is(RS_SCOLON)) { CODE_push_char(' '); nparam++; } semicolon = TRUE; } else if (TRANS_is(RS_COMMA)) { CODE_push_char('\t'); nparam++; semicolon = FALSE; } else THROW(E_SYNTAX); } if (!semicolon) { CODE_push_char('\n'); nparam++; } trans_subr(TS_SUBR_PRINT, nparam); CODE_drop(); } void TRANS_print(void) { trans_stream(TS_STDOUT); trans_print_debug(); } void TRANS_debug(void) { if (!JOB->debug) { while (!PATTERN_is_newline(*JOB->current)) JOB->current++; return; } trans_subr(TS_SUBR_DEBUG, 0); CODE_drop(); CODE_push_number(2); // stderr trans_print_debug(); } void TRANS_error(void) { if (TRANS_is(RS_TO)) { if (TRANS_is(RS_DEFAULT)) CODE_push_null(); else trans_stream(TS_NONE); trans_subr(TS_SUBR_ERROR_TO, 1); if (TRANS_in_affectation == 0) CODE_drop(); } else { CODE_push_number(2); // stderr trans_print_debug(); } } void TRANS_write(void) { int nparam = 1; trans_stream(TS_STDOUT); TRANS_expression(FALSE); nparam++; if (TRANS_is(RS_COMMA)) { TRANS_expression(FALSE); nparam++; } trans_subr(TS_SUBR_WRITE, nparam); CODE_drop(); } void TRANS_output_to() { TRANS_want(RS_TO, NULL); if (TRANS_is(RS_DEFAULT)) CODE_push_null(); else trans_stream(TS_NONE); trans_subr(TS_SUBR_OUTPUT_TO, 1); if (TRANS_in_affectation == 0) CODE_drop(); } void TRANS_input_from() { if (TRANS_is(RS_DEFAULT)) CODE_push_null(); else trans_stream(TS_NONE); trans_subr(TS_SUBR_INPUT_FROM, 1); if (TRANS_in_affectation == 0) CODE_drop(); } void TRANS_input(void) { bool stream = TRUE; if (TRANS_is(RS_FROM)) { TRANS_input_from(); return; } trans_stream(TS_STDIN); for(;;) { trans_subr(TS_SUBR_INPUT, (stream ? 1 : 0)); stream = FALSE; TRANS_reference(); if (PATTERN_is_newline(*JOB->current)) break; if (!PATTERN_is(*JOB->current, RS_COMMA) && !PATTERN_is(*JOB->current, RS_SCOLON)) THROW(E_SYNTAX); JOB->current++; } } void TRANS_read(void) { int nparam = 2; PATTERN *save_return; PATTERN *save_current; trans_stream(TS_STDIN); save_return = JOB->current; TRANS_expression(FALSE); /*trans_calc_type();*/ if (TRANS_is(RS_COMMA)) { TRANS_expression(FALSE); nparam++; } trans_subr(TS_SUBR_READ, nparam); save_current = JOB->current; JOB->current = save_return; TRANS_reference(); JOB->current = save_current; } void TRANS_open(void) { int mode = TS_MODE_READ; /* Nom du fichier */ TRANS_expression(FALSE); /* mode d'ouverture */ if (TRANS_is(RS_FOR)) { if (TRANS_is(RS_READ)) mode |= TS_MODE_READ | TS_MODE_DIRECT; else if (TRANS_is(RS_INPUT)) mode |= TS_MODE_READ; if (TRANS_is(RS_WRITE)) mode |= TS_MODE_WRITE | TS_MODE_DIRECT; else if (TRANS_is(RS_OUTPUT)) mode |= TS_MODE_WRITE; if (TRANS_is(RS_CREATE)) mode |= TS_MODE_CREATE; else if (TRANS_is(RS_APPEND)) mode |= TS_MODE_APPEND; //if (TRANS_is(RS_DIRECT)) // mode |= TS_MODE_DIRECT; if (TRANS_is(RS_WATCH)) mode |= TS_MODE_WATCH; /*if (TRANS_is(RS_BIG)) mode |= TS_MODE_BIG; else if (TRANS_is(RS_LITTLE)) mode |= TS_MODE_LITTLE;*/ /*JOB->current--; if (PATTERN_is(*JOB->current, RS_FOR)) THROW("Syntax error in file open mode"); JOB->current++;*/ } CODE_push_number(mode); trans_subr(TS_SUBR_OPEN, 2); if (TRANS_in_affectation == 0) { //CODE_drop(); /* handle du fichier */ TRANS_want(RS_AS, NULL); TRANS_ignore(RS_SHARP); TRANS_reference(); } } void TRANS_pipe(void) { int mode = TS_MODE_READ; /* Nom du fichier */ TRANS_expression(FALSE); /* mode d'ouverture */ if (TRANS_is(RS_FOR)) { if (TRANS_is(RS_READ)) mode |= TS_MODE_READ | TS_MODE_DIRECT; else if (TRANS_is(RS_INPUT)) mode |= TS_MODE_READ; if (TRANS_is(RS_WRITE)) mode |= TS_MODE_WRITE | TS_MODE_DIRECT; else if (TRANS_is(RS_OUTPUT)) mode |= TS_MODE_WRITE; /*if (TRANS_is(RS_CREATE)) mode |= TS_MODE_CREATE; else if (TRANS_is(RS_APPEND)) mode |= TS_MODE_APPEND;*/ //if (TRANS_is(RS_DIRECT)) // mode |= TS_MODE_DIRECT; if (TRANS_is(RS_WATCH)) mode |= TS_MODE_WATCH; /*if (TRANS_is(RS_BIG)) mode |= TS_MODE_BIG; else if (TRANS_is(RS_LITTLE)) mode |= TS_MODE_LITTLE;*/ /*JOB->current--; if (PATTERN_is(*JOB->current, RS_FOR)) THROW("Syntax error in file open mode"); JOB->current++;*/ } CODE_push_number(mode | TS_MODE_PIPE); trans_subr(TS_SUBR_OPEN, 2); if (TRANS_in_affectation == 0) { //CODE_drop(); /* handle du fichier */ TRANS_want(RS_AS, NULL); TRANS_ignore(RS_SHARP); TRANS_reference(); } } void TRANS_close(void) { if (PATTERN_is_newline(*JOB->current)) THROW(E_SYNTAX); TRANS_ignore(RS_SHARP); TRANS_expression(FALSE); trans_subr(TS_SUBR_CLOSE, 1); CODE_drop(); } void TRANS_lock(void) { if (PATTERN_is_newline(*JOB->current)) THROW(E_SYNTAX); if (!TRANS_in_affectation) THROW("Useless LOCK"); TRANS_expression(FALSE); trans_subr(TS_SUBR_LOCK, 1); } void TRANS_unlock(void) { if (PATTERN_is_newline(*JOB->current)) THROW(E_SYNTAX); TRANS_ignore(RS_SHARP); TRANS_expression(FALSE); trans_subr(TS_SUBR_UNLOCK, 1); CODE_drop(); } void TRANS_seek(void) { int nparam; trans_stream(TS_NONE); TRANS_expression(FALSE); nparam = 2; /* if (TRANS_is(RS_COMMA)) { TRANS_expression(FALSE); nparam++; } */ trans_subr(TS_SUBR_SEEK, nparam); CODE_drop(); } void TRANS_line_input(void) { if (TRANS_is(RS_INPUT)) { trans_stream(TS_STDIN); trans_subr(TS_SUBR_LINE_INPUT, 1); TRANS_reference(); } else THROW(E_SYNTAX); } void TRANS_flush(void) { trans_stream(TS_STDOUT); trans_subr(TS_SUBR_FLUSH, 1); CODE_drop(); } void TRANS_stop(void) { if (TRANS_is(RS_EVENT)) CODE_stop_event(); else CODE_stop(); } void TRANS_quit(void) { CODE_quit(); } void TRANS_randomize(void) { if (PATTERN_is_newline(*JOB->current)) { trans_subr(TS_SUBR_RANDOMIZE, 0); } else { TRANS_expression(FALSE); trans_subr(TS_SUBR_RANDOMIZE, 1); } CODE_drop(); } static void trans_exec_shell(bool shell) { int mode = TS_EXEC_NONE; bool wait; bool as = TRUE; TRANS_expression(FALSE); if (TRANS_is(RS_WITH)) TRANS_expression(FALSE); else CODE_push_null(); wait = TRANS_is(RS_WAIT); if (TRANS_is(RS_FOR)) { if (TRANS_is(RS_READ)) mode |= TS_EXEC_READ; if (TRANS_is(RS_WRITE)) mode |= TS_EXEC_WRITE; if (mode == 0) { mode |= TS_EXEC_TERM; if (TRANS_is(RS_INPUT)) mode |= TS_EXEC_READ; if (TRANS_is(RS_OUTPUT)) mode |= TS_EXEC_WRITE; } } else if (TRANS_is(RS_TO)) { if (TRANS_in_affectation) THROW("Syntax error. Cannot use this syntax in affectation."); mode = TS_EXEC_STRING; wait = TRUE; as = FALSE; } if (wait) mode |= TS_EXEC_WAIT; CODE_push_number(mode); if (as && TRANS_is(RS_AS)) TRANS_expression(FALSE); else CODE_push_null(); trans_subr(shell ? TS_SUBR_SHELL : TS_SUBR_EXEC, 4); if (mode & TS_EXEC_STRING) TRANS_reference(); else if (TRANS_in_affectation == 0) CODE_drop(); } void TRANS_exec(void) { trans_exec_shell(FALSE); } void TRANS_shell(void) { trans_exec_shell(TRUE); } void TRANS_wait(void) { int nparam = 0; if (!PATTERN_is_newline(*JOB->current)) { TRANS_expression(FALSE); nparam = 1; } trans_subr(TS_SUBR_WAIT, nparam); CODE_drop(); } void TRANS_sleep(void) { TRANS_expression(FALSE); trans_subr(TS_SUBR_SLEEP, 1); CODE_drop(); } void TRANS_kill(void) { TRANS_expression(FALSE); trans_subr(TS_SUBR_KILL, 1); CODE_drop(); } void TRANS_move(void) { TRANS_expression(FALSE); TRANS_want(RS_TO, NULL); TRANS_expression(FALSE); trans_subr(TS_SUBR_MOVE, 2); CODE_drop(); } void TRANS_copy(void) { TRANS_expression(FALSE); TRANS_want(RS_TO, NULL); TRANS_expression(FALSE); trans_subr(TS_SUBR_COPY, 2); CODE_drop(); } void TRANS_link(void) { TRANS_expression(FALSE); TRANS_want(RS_TO, NULL); TRANS_expression(FALSE); trans_subr(TS_SUBR_LINK, 2); CODE_drop(); } void TRANS_inc(void) { PATTERN *save = JOB->current; TRANS_expression(FALSE); CODE_push_number(1); CODE_op(C_ADD, 2, TRUE); JOB->current = save; TRANS_reference(); } void TRANS_dec(void) { PATTERN *save = JOB->current; TRANS_expression(FALSE); CODE_push_number(1); CODE_op(C_SUB, 2, TRUE); JOB->current = save; TRANS_reference(); } void TRANS_swap(void) { PATTERN *sa; PATTERN *sb; PATTERN *current; sa = JOB->current; TRANS_expression(FALSE); TRANS_want(RS_COMMA, "Comma"); sb = JOB->current; TRANS_expression(FALSE); current = JOB->current; JOB->current = sa; TRANS_reference(); JOB->current = sb; TRANS_reference(); JOB->current = current; } void TRANS_mkdir(void) { TRANS_expression(FALSE); trans_subr(TS_SUBR_MKDIR, 1); CODE_drop(); } void TRANS_rmdir(void) { TRANS_expression(FALSE); trans_subr(TS_SUBR_RMDIR, 1); CODE_drop(); } void TRANS_mid() { PATTERN *str; PATTERN *pos; PATTERN *len; PATTERN *save; TRANS_want(RS_LBRA, "Left brace"); str = JOB->current; TRANS_expression(FALSE); TRANS_want(RS_COMMA, "Comma"); pos = JOB->current; TRANS_expression(FALSE); CODE_push_number(1); CODE_op(C_SUB, 2, TRUE); TRANS_subr(TS_SUBR_LEFT, 2); if (TRANS_is(RS_COMMA)) { len = JOB->current; TRANS_ignore_expression(); } else { len = NULL; } TRANS_want(RS_RBRA, "Right brace"); TRANS_want(RS_EQUAL, "Equal"); TRANS_expression(FALSE); save = JOB->current; if (len) { JOB->current = str; TRANS_expression(FALSE); JOB->current = pos; TRANS_expression(FALSE); JOB->current = len; TRANS_expression(FALSE); CODE_op(C_ADD, 2, TRUE); TRANS_subr(TS_SUBR_MID, 2); } CODE_op(C_CAT, len ? 3 : 2, FALSE); JOB->current = str; TRANS_reference(); JOB->current = save; } #if 0 void TRANS_scan(void) { PATTERN *save; int noutput = 0; TRANS_expression(FALSE); TRANS_want(RS_WITH, NULL); TRANS_expression(FALSE); TRANS_want(RS_TO, NULL); save = JOB->current; for(;;) { TRANS_expression(FALSE); noutput++; if (!TRANS_is(RS_COMMA)) break; } JOB->current = save; trans_subr_output(TSO_SUBR_SCAN, 2 + noutput, noutput); for(;;) { TRANS_reference(); if (!TRANS_is(RS_COMMA)) break; } } #endif void TRANS_subr(int subr, int nparam) { trans_subr(subr, nparam); }