#define _TRANS_SUBR_C
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "gb_common.h"
#include "gb_error.h"
#include "gbc_compile.h"
#include "gbc_trans.h"
#include "gb_code.h"
#include "gb_limit.h"
typedef
struct {
char *name;
SUBR_INFO *info;
}
TRANS_SUBR_INFO;
PRIVATE void trans_subr(int subr, int nparam)
{
static TRANS_SUBR_INFO subr_info[] =
{
{ "Print" }, { "Input" }, { "Write" }, { "Read" }, { "Open" },
{ "Close" }, { "Seek" }, { "Type" }, { "LineInput" }, { "Flush" },
{ "Exec" }, { "Shell" }, { "Wait" }, { "Kill" }, { "Rename" },
{ "Mkdir" }, { "Rmdir" }, { "Array" }, { "Use" }, { "Copy" },
{ "Link" }, { "Error" }, { "Lock" }, { "Unlock" }
};
TRANS_SUBR_INFO *tsi = &subr_info[subr];
if (tsi->info == NULL)
tsi->info = SUBR_get(tsi->name);
CODE_subr(tsi->info->opcode, nparam, tsi->info->optype, FALSE, tsi->info->min_param == tsi->info->max_param);
}
PRIVATE boolean 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);
}
return FALSE;
}
else
{
CODE_push_number(default_stream);
return TRUE;
}
}
PUBLIC void TRANS_print(void)
{
int nparam = 1;
boolean semicolon = FALSE;
trans_stream(TS_STDOUT);
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();
}
PUBLIC 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();
}
PUBLIC void TRANS_input(void)
{
boolean stream = TRUE;
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++;
}
}
PUBLIC void TRANS_read(void)
{
int nparam = 2;
PATTERN *save_return;
PATTERN *save_current;
trans_stream(TS_STDIN);
save_return = JOB->current;
TRANS_expression(FALSE);
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;
}
PUBLIC void TRANS_open(void)
{
int mode = TS_MODE_READ;
TRANS_expression(FALSE);
if (TRANS_is(RS_FOR))
{
if (TRANS_is(RS_READ))
mode |= TS_MODE_READ;
if (TRANS_is(RS_WRITE))
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;
}
CODE_push_number(mode);
trans_subr(TS_SUBR_OPEN, 2);
TRANS_want(RS_AS, NULL);
TRANS_ignore(RS_SHARP);
TRANS_reference();
}
PUBLIC 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();
}
static void trans_lock_unlock(bool unlock)
{
if (PATTERN_is_newline(*JOB->current))
THROW(E_SYNTAX);
TRANS_ignore(RS_SHARP);
TRANS_expression(FALSE);
trans_subr(unlock ? TS_SUBR_UNLOCK : TS_SUBR_LOCK, 1);
CODE_drop();
}
PUBLIC void TRANS_lock(void)
{
trans_lock_unlock(FALSE);
}
PUBLIC void TRANS_unlock(void)
{
trans_lock_unlock(TRUE);
}
PUBLIC void TRANS_seek(void)
{
int nparam;
if (trans_stream(TS_STDIN))
THROW("Syntax error. '#' expected");
TRANS_expression(FALSE);
nparam = 2;
trans_subr(TS_SUBR_SEEK, nparam);
CODE_drop();
}
PUBLIC void TRANS_line_input(void)
{
trans_stream(TS_STDIN);
trans_subr(TS_SUBR_LINE_INPUT, 1);
TRANS_reference();
}
PUBLIC void TRANS_flush(void)
{
trans_stream(TS_STDOUT);
trans_subr(TS_SUBR_FLUSH, 1);
CODE_drop();
}
PUBLIC void TRANS_stop(void)
{
if (TRANS_is(RS_EVENT))
CODE_stop_event();
else
CODE_stop();
}
PUBLIC void TRANS_quit(void)
{
CODE_quit();
}
PRIVATE void trans_exec_shell(bool shell)
{
int mode = 0;
bool wait = FALSE;
TRANS_expression(FALSE);
wait = TRANS_is(RS_WAIT);
CODE_push_boolean(wait);
if (TRANS_is(RS_FOR))
{
if (wait)
THROW("Cannot use WAIT with FOR READ / WRITE");
if (TRANS_is(RS_READ))
mode |= TS_EXEC_READ;
if (TRANS_is(RS_WRITE))
mode |= TS_EXEC_WRITE;
}
CODE_push_number(mode);
trans_subr(shell ? TS_SUBR_SHELL : TS_SUBR_EXEC, 3);
if (TRANS_is(RS_AS))
TRANS_reference();
else
CODE_drop();
}
PUBLIC void TRANS_exec(void)
{
trans_exec_shell(FALSE);
}
PUBLIC void TRANS_shell(void)
{
trans_exec_shell(TRUE);
}
PUBLIC 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();
}
PUBLIC void TRANS_kill(void)
{
TRANS_expression(FALSE);
trans_subr(TS_SUBR_KILL, 1);
CODE_drop();
}
PUBLIC void TRANS_rename(void)
{
TRANS_expression(FALSE);
TRANS_want(RS_AS, NULL);
TRANS_expression(FALSE);
trans_subr(TS_SUBR_RENAME, 2);
CODE_drop();
}
PUBLIC void TRANS_copy(void)
{
TRANS_expression(FALSE);
TRANS_want(RS_TO, NULL);
TRANS_expression(FALSE);
trans_subr(TS_SUBR_COPY, 2);
CODE_drop();
}
PUBLIC void TRANS_link(void)
{
TRANS_expression(FALSE);
TRANS_want(RS_TO, NULL);
TRANS_expression(FALSE);
trans_subr(TS_SUBR_LINK, 2);
CODE_drop();
}
PUBLIC 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();
}
PUBLIC 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();
}
PUBLIC 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;
}
PUBLIC void TRANS_mkdir(void)
{
TRANS_expression(FALSE);
trans_subr(TS_SUBR_MKDIR, 1);
CODE_drop();
}
PUBLIC void TRANS_rmdir(void)
{
TRANS_expression(FALSE);
trans_subr(TS_SUBR_RMDIR, 1);
CODE_drop();
}
PUBLIC void TRANS_use(void)
{
TRANS_expression(FALSE);
trans_subr(TS_SUBR_USE, 1);
CODE_drop();
}
PUBLIC void TRANS_subr(int subr, int nparam)
{
trans_subr(subr, nparam);
}