Commit 2233fe22 2233fe22de4e6ff71d711b833cff595bd98b2b09 by Sergey Poznyakoff

Added basic code generation and debugging

1 parent 0ba30cb1
......@@ -16,11 +16,15 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <sys/types.h>
#include <stdarg.h>
#include <mailutils/mailutils.h>
typedef struct sieve_machine sieve_machine_t;
typedef int (*sieve_instr_t) __P((sieve_machine_t *mach, list_t *args));
typedef int (*sieve_handler_t) __P((sieve_machine_t *mach,
list_t args, list_t tags));
typedef int (*sieve_printf_t) __P((void *data, const char *fmt, va_list ap));
typedef int (*sieve_vprintf_t) __P((void *data, const char *fmt, va_list ap));
typedef enum {
SVT_VOID,
......@@ -32,12 +36,15 @@ typedef enum {
SVT_VALUE_LIST
} sieve_data_type;
typedef struct sieve_runtime_tag sieve_runtime_tag_t;
typedef struct {
sieve_data_type type;
union {
char *string;
long number;
list_t list;
sieve_runtime_tag_t *tag;
} v;
} sieve_value_t;
......@@ -47,10 +54,15 @@ typedef struct {
sieve_data_type argtype;
} sieve_tag_def_t;
struct sieve_runtime_tag {
int tag;
sieve_value_t *arg;
};
typedef struct {
char *name;
int required;
sieve_instr_t instr;
sieve_handler_t handler;
int num_req_args;
sieve_data_type *req_args;
int num_tags;
......@@ -59,18 +71,28 @@ typedef struct {
void *sieve_alloc __P((size_t size));
int sieve_open_source __P((const char *name));
int sieve_parse __P((const char *name));
void *sieve_palloc __P((list_t *pool, size_t size));
void *sieve_prealloc __P((list_t *pool, void *ptr, size_t size));
void sieve_pfree __P((list_t *pool, void *ptr));
char *sieve_pstrdup __P((list_t *pool, const char *str));
int sieve_compile __P((sieve_machine_t *mach, const char *name, void *data,
sieve_printf_t errfn));
void sieve_set_debug __P((sieve_machine_t *mach, sieve_printf_t debug,
int level));
sieve_value_t * sieve_value_create __P((sieve_data_type type, void *data));
sieve_register_t *sieve_test_lookup __P((const char *name));
sieve_register_t *sieve_action_lookup __P((const char *name));
int sieve_register_test __P((const char *name, sieve_instr_t instr,
int sieve_register_test __P((const char *name, sieve_handler_t handler,
sieve_data_type *arg_types,
sieve_tag_def_t *tags, int required));
int sieve_register_action __P((const char *name, sieve_instr_t instr,
int sieve_register_action __P((const char *name, sieve_handler_t handler,
sieve_data_type *arg_types,
sieve_tag_def_t *tags, int required));
void sieve_slist_destroy __P((list_t *plist));
void sieve_require __P((list_t slist));
void sieve_abort __P((sieve_machine_t *mach));
......
......@@ -26,33 +26,39 @@
#include <sieve.h>
int
sieve_action_stop (sieve_machine_t *mach, list_t *args)
sieve_action_stop (sieve_machine_t *mach, list_t args, list_t tags)
{
return 0;
}
int
sieve_action_keep (sieve_machine_t *mach, list_t *args)
sieve_action_keep (sieve_machine_t *mach, list_t args, list_t tags)
{
return 0;
}
int
sieve_action_discard (sieve_machine_t *mach, list_t *args)
sieve_action_discard (sieve_machine_t *mach, list_t args, list_t tags)
{
return 0;
}
int
sieve_action_fileinto (sieve_machine_t *mach, list_t *args)
sieve_action_fileinto (sieve_machine_t *mach, list_t args, list_t tags)
{
return 0;
}
int
sieve_action_reject (sieve_machine_t *mach, list_t *args)
sieve_action_reject (sieve_machine_t *mach, list_t args, list_t tags)
{
return 0;
}
int
sieve_action_redirect (sieve_machine_t *mach, list_t *args)
sieve_action_redirect (sieve_machine_t *mach, list_t args, list_t tags)
{
return 0;
}
sieve_data_type fileinto_args[] = {
......
......@@ -35,7 +35,7 @@ sieve_lookup (list_t list, const char *name)
sieve_register_t *reg;
if (!list || iterator_create (&itr, list))
return;
return NULL;
for (iterator_first (itr); !iterator_is_done (itr); iterator_next (itr))
{
......@@ -63,7 +63,7 @@ sieve_action_lookup (const char *name)
static int
sieve_register (list_t *list,
const char *name, sieve_instr_t instr,
const char *name, sieve_handler_t handler,
sieve_data_type *arg_types,
sieve_tag_def_t *tags, int required)
{
......@@ -73,7 +73,7 @@ sieve_register (list_t *list,
if (!reg)
return ENOMEM;
reg->name = name;
reg->instr = instr;
reg->handler = handler;
if (arg_types)
{
......@@ -111,17 +111,17 @@ sieve_register (list_t *list,
int
sieve_register_test (const char *name, sieve_instr_t instr,
sieve_register_test (const char *name, sieve_handler_t handler,
sieve_data_type *arg_types,
sieve_tag_def_t *tags, int required)
{
return sieve_register (&test_list, name, instr, arg_types, tags, required);
return sieve_register (&test_list, name, handler, arg_types, tags, required);
}
int
sieve_register_action (const char *name, sieve_instr_t instr,
sieve_register_action (const char *name, sieve_handler_t handler,
sieve_data_type *arg_types,
sieve_tag_def_t *tags, int required)
{
return sieve_register (&action_list, name, instr, arg_types, tags, required);
return sieve_register (&action_list, name, handler, arg_types, tags, required);
}
......
......@@ -16,20 +16,78 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <mailutils/libsieve.h>
#include <setjmp.h>
#define SIEVE_CODE_INCR 128
typedef void (*sieve_instr_t) __P((sieve_machine_t *mach));
typedef union {
sieve_instr_t instr;
sieve_value_t val;
sieve_handler_t handler;
sieve_value_t *val;
list_t list;
long number;
char *string;
} sieve_op_t;
struct sieve_machine {
size_t progsize;
sieve_op_t *prog;
list_t memory_pool; /* Pool of allocated memory objects */
size_t progsize; /* Number of allocated program cells */
size_t pc; /* Current program counter */
sieve_op_t *prog; /* Compiled program */
long reg; /* Numeric register */
list_t stack; /* Runtime stack */
int debug_level;
sieve_printf_t error_printer;
sieve_printf_t debug_printer;
void *data;
jmp_buf errbuf;
};
extern char *sieve_filename;
extern int sieve_line_num;
extern int sieve_yydebug;
extern sieve_machine_t *sieve_machine;
extern int sieve_error_count;
void sieve_error __P((const char *fmt, ...));
void sieve_debug_internal __P((sieve_printf_t printer, void *data,
const char *fmt, ...));
void sieve_debug __P((sieve_machine_t *mach, const char *fmt, ...));
void sieve_print_value __P((sieve_value_t *val, sieve_printf_t printer,
void *data));
void sieve_print_value_list __P((list_t list, sieve_printf_t printer,
void *data));
void sieve_print_tag_list __P((list_t list, sieve_printf_t printer,
void *data));
int _sieve_default_error_printer __P((void*data, const char *fmt, va_list ap));
int sieve_lex_begin __P((const char *name));
void sieve_lex_finish __P((void));
void sieve_register_standard_actions __P((void));
void sieve_register_standard_tests __P((void));
#define sieve_error mu_error
int sieve_code __P((sieve_op_t *op));
int sieve_code_instr __P((sieve_instr_t instr));
int sieve_code_handler __P((sieve_handler_t handler));
int sieve_code_list __P((list_t list));
int sieve_code_number __P((long num));
int sieve_code_test __P((sieve_register_t *reg, list_t arglist));
int sieve_code_action __P((sieve_register_t *reg, list_t arglist));
void instr_action __P((sieve_machine_t *mach));
void instr_test __P((sieve_machine_t *mach));
void instr_push __P((sieve_machine_t *mach));
void instr_pop __P((sieve_machine_t *mach));
void instr_allof __P((sieve_machine_t *mach));
void instr_anyof __P((sieve_machine_t *mach));
void instr_not __P((sieve_machine_t *mach));
......
......@@ -283,6 +283,7 @@ pop_source ()
{
struct buffer_ctx *ctx;
if (yyin)
fclose (yyin);
#ifndef FLEX_SCANNER
lex_delete_buffer (current_buffer);
......@@ -402,11 +403,18 @@ sieve_include ()
}
int
sieve_open_source (const char *name)
sieve_lex_begin (const char *name)
{
return push_source (name);
}
void
sieve_lex_finish ()
{
while (pop_source () == 0)
;
}
int
number ()
{
......@@ -434,7 +442,7 @@ number ()
int
string ()
{
yylval.string = sieve_alloc (yyleng - 1);
yylval.string = sieve_palloc (&sieve_machine->memory_pool, yyleng - 1);
memcpy (yylval.string, yytext + 1, yyleng - 2);
yylval.string[yyleng - 2] = 0;
return STRING;
......@@ -486,7 +494,7 @@ multiline_finish ()
}
/* Copy the contents */
yylval.string = sieve_alloc (length + 1);
yylval.string = sieve_palloc (&sieve_machine->memory_pool, length + 1);
p = yylval.string;
for (iterator_first (itr); !iterator_is_done (itr); iterator_next (itr))
{
......
......@@ -23,6 +23,9 @@
#include <stdlib.h>
#include <assert.h>
#include <sieve.h>
sieve_machine_t *sieve_machine;
int sieve_error_count;
%}
%union {
......@@ -31,6 +34,7 @@
sieve_instr_t instr;
sieve_value_t *value;
list_t list;
size_t pc;
struct {
char *ident;
list_t args;
......@@ -45,11 +49,14 @@
%type <value> arg
%type <list> slist stringlist arglist maybe_arglist
%type <command> command
%type <number> testlist
%type <pc> action test statement list
%%
input : /* empty */
| list
{ /* to placate bison */ }
;
list : statement
......@@ -59,10 +66,15 @@ list : statement
statement : REQUIRE stringlist ';'
{
sieve_require ($2);
sieve_slist_destroy ($2);
sieve_slist_destroy (&$2);
$$ = sieve_machine->pc;
}
| action ';'
| IF cond block maybe_elsif maybe_else
{
/* FIXME!! */
$$ = sieve_machine->pc;
}
;
maybe_elsif : /* empty */
......@@ -82,18 +94,45 @@ block : '{' list '}'
testlist : cond
{
if (sieve_code_instr (instr_push))
YYERROR;
$$ = 1;
}
| testlist ',' cond
{
if (sieve_code_instr (instr_push))
YYERROR;
$$ = $1 + 1;
}
;
cond : test
{ /* to placate bison */ }
| ANYOF '(' testlist ')'
{
if (sieve_code_instr (instr_anyof)
|| sieve_code_number ($3))
YYERROR;
}
| ALLOF '(' testlist ')'
{
if (sieve_code_instr (instr_allof)
|| sieve_code_number ($3))
YYERROR;
}
| NOT cond
{
if (sieve_code_instr (instr_not))
YYERROR;
}
;
test : command
{
sieve_register_t *reg = sieve_test_lookup ($1.ident);
$$ = sieve_machine->pc;
if (!reg)
sieve_error ("%s:%d: unknown test: %s",
sieve_filename, sieve_line_num,
......@@ -102,7 +141,8 @@ test : command
sieve_error ("%s:%d: test `%s' has not been required",
sieve_filename, sieve_line_num,
$1.ident);
/*free unneeded memory */
if (sieve_code_test (reg, $1.args))
YYERROR;
}
;
......@@ -116,6 +156,8 @@ command : IDENT maybe_arglist
action : command
{
sieve_register_t *reg = sieve_action_lookup ($1.ident);
$$ = sieve_machine->pc;
if (!reg)
sieve_error ("%s:%d: unknown action: %s",
sieve_filename, sieve_line_num,
......@@ -124,7 +166,8 @@ action : command
sieve_error ("%s:%d: action `%s' has not been required",
sieve_filename, sieve_line_num,
$1.ident);
/*free unneeded memory */
if (sieve_code_action (reg, $1.args))
YYERROR;
}
;
......@@ -138,11 +181,11 @@ maybe_arglist: /* empty */
arglist : arg
{
list_create (&$$);
list_append ($$, &$1);
list_append ($$, $1);
}
| arglist arg
{
list_append ($1, &$2);
list_append ($1, $2);
$$ = $1;
}
;
......@@ -197,12 +240,42 @@ yyerror (char *s)
return 0;
}
/* FIXME: When posix thread support is added, sieve_machine_begin() should
aquire the global mutex, locking the current compilation session, and
sieve_machine_finish() should release it */
void
sieve_machine_begin (sieve_machine_t *mach, sieve_printf_t err, void *data)
{
memset (mach, 0, sizeof (*mach));
mach->error_printer = err ? err : _sieve_default_error_printer;
mach->data = data;
sieve_machine = mach;
sieve_error_count = 0;
sieve_code_instr (NULL);
}
void
sieve_machine_finish (sieve_machine_t *mach)
{
sieve_code_instr (NULL);
}
int
sieve_parse (const char *name)
sieve_compile (sieve_machine_t *mach, const char *name,
void *extra_data, sieve_printf_t err)
{
int rc;
sieve_machine_begin (mach, err, extra_data);
sieve_register_standard_actions ();
sieve_register_standard_tests ();
sieve_open_source (name);
return yyparse ();
sieve_lex_begin (name);
rc = yyparse ();
sieve_lex_finish ();
sieve_machine_finish (mach);
if (sieve_error_count)
rc = 1;
return rc;
}
......
......@@ -24,18 +24,34 @@
#include <sieve.h>
int
debug_printer (void *unused, const char *fmt, va_list ap)
{
return vfprintf (stderr, fmt, ap);
}
int
main (int argc, char **argv)
{
int n;
int n, rc, debug = 0;
sieve_machine_t mach;
assert (argc > 1);
if (strcmp (argv[1], "-d") == 0)
{
sieve_yydebug++;
n = 2;
debug++;
assert (argc > 2);
}
else
n = 1;
return sieve_parse (argv[n]);
rc = sieve_compile (&mach, argv[n], NULL, NULL);
if (rc == 0)
{
if (debug)
sieve_set_debug (&mach, debug_printer, 100);
sieve_run (&mach);
}
return rc;
}
......
......@@ -37,38 +37,45 @@
#define TAG_OVER 9
int
sieve_test_address (sieve_machine_t *mach, list_t *args)
sieve_test_address (sieve_machine_t *mach, list_t args, list_t tags)
{
return 0;
}
int
sieve_test_header (sieve_machine_t *mach, list_t *args)
sieve_test_header (sieve_machine_t *mach, list_t args, list_t tags)
{
return 0;
}
int
sieve_test_envelope (sieve_machine_t *mach, list_t *args)
sieve_test_envelope (sieve_machine_t *mach, list_t args, list_t tags)
{
return 0;
}
int
sieve_test_size (sieve_machine_t *mach, list_t *args)
sieve_test_size (sieve_machine_t *mach, list_t args, list_t tags)
{
return 0;
}
int
sieve_test_true (sieve_machine_t *mach, list_t *args)
sieve_test_true (sieve_machine_t *mach, list_t args, list_t tags)
{
return 0;
}
int
sieve_test_false (sieve_machine_t *mach, list_t *args)
sieve_test_false (sieve_machine_t *mach, list_t args, list_t tags)
{
return 0;
}
int
sieve_test_exists (sieve_machine_t *mach, list_t *args)
sieve_test_exists (sieve_machine_t *mach, list_t args, list_t tags)
{
return 0;
}
#define ADDRESS_PART \
......
......@@ -21,12 +21,13 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <sieve.h>
void *
sieve_alloc (size_t size)
{
char *p = malloc (size);
void *p = malloc (size);
if (!p)
{
mu_error ("not enough memory");
......@@ -35,6 +36,70 @@ sieve_alloc (size_t size)
return p;
}
void *
sieve_palloc (list_t *pool, size_t size)
{
void *p = malloc (size);
if (p)
{
if (!*pool && list_create (pool))
{
free (p);
return NULL;
}
list_append (*pool, p);
}
return p;
}
char *
sieve_pstrdup (list_t *pool, const char *str)
{
size_t len;
char *p;
if (!str)
return NULL;
len = strlen (str);
p = sieve_palloc (pool, len + 1);
if (p)
{
memcpy (p, str, len);
p[len] = 0;
}
return p;
}
void *
sieve_prealloc (list_t *pool, void *ptr, size_t size)
{
void *newptr;
if (*pool)
list_remove (*pool, ptr);
newptr = realloc (ptr, size);
if (newptr)
{
if (!*pool && list_create (pool))
{
free (newptr);
return NULL;
}
list_append (*pool, newptr);
}
return newptr;
}
void
sieve_pfree (list_t *pool, void *ptr)
{
if (*pool)
list_remove (*pool, ptr);
free (ptr);
}
void
sieve_slist_destroy (list_t *plist)
{
......@@ -85,3 +150,164 @@ sieve_value_create (sieve_data_type type, void *data)
return val;
}
void
sieve_error (const char *fmt, ...)
{
va_list ap;
va_start (ap, fmt);
sieve_error_count++;
sieve_machine->error_printer (sieve_machine->data, fmt, ap);
va_end (ap);
}
void
sieve_debug_internal (sieve_printf_t printer, void *data, const char *fmt, ...)
{
va_list ap;
va_start (ap, fmt);
printer (data, fmt, ap);
va_end (ap);
}
void
sieve_debug (sieve_machine_t *mach, const char *fmt, ...)
{
va_list ap;
va_start (ap, fmt);
mach->debug_printer (mach->data, fmt, ap);
va_end (ap);
}
int
_sieve_default_error_printer (void *unused, const char *fmt, va_list ap)
{
return mu_verror (fmt, ap);
}
char *
sieve_type_str (sieve_data_type type)
{
switch (type)
{
case SVT_VOID:
return "void";
case SVT_NUMBER:
return "number";
case SVT_STRING:
return "string";
case SVT_STRING_LIST:
return "string-list";
case SVT_TAG:
return "tag";
case SVT_IDENT:
return "ident";
case SVT_VALUE_LIST:
return "value-list";
}
return "unknown";
}
struct debug_data {
sieve_printf_t printer;
void *data;
};
static int
string_printer (char *s, struct debug_data *dbg)
{
sieve_debug_internal (dbg->printer, dbg->data, "\"%s\" ", s);
return 0;
}
static int
value_printer (sieve_value_t *val, struct debug_data *dbg)
{
sieve_print_value (val, dbg->printer, dbg->data);
sieve_debug_internal (dbg->printer, dbg->data, " ");
return 0;
}
void
sieve_print_value (sieve_value_t *val, sieve_printf_t printer, void *data)
{
struct debug_data dbg;
dbg.printer = printer;
dbg.data = data;
sieve_debug_internal (printer, data, "%s(", sieve_type_str (val->type));
switch (val->type)
{
case SVT_VOID:
break;
case SVT_NUMBER:
sieve_debug_internal (printer, data, "%ld", val->v.number);
break;
case SVT_TAG:
case SVT_IDENT:
case SVT_STRING:
sieve_debug_internal (printer, data, "%s", val->v.string);
break;
case SVT_STRING_LIST:
list_do (val->v.list, (list_action_t*) string_printer, &dbg);
break;
case SVT_VALUE_LIST:
list_do (val->v.list, (list_action_t*) value_printer, &dbg);
}
sieve_debug_internal (printer, data, ")");
}
void
sieve_print_value_list (list_t list, sieve_printf_t printer, void *data)
{
sieve_value_t val;
val.type = SVT_VALUE_LIST;
val.v.list = list;
sieve_print_value (&val, printer, data);
}
static int
tag_printer (sieve_runtime_tag_t *val, struct debug_data *dbg)
{
sieve_debug_internal (dbg->printer, dbg->data, "%d", val->tag);
if (val->arg)
{
sieve_debug_internal (dbg->printer, dbg->data, "(");
sieve_print_value (val->arg, dbg->printer, dbg->data);
sieve_debug_internal (dbg->printer, dbg->data, ")");
}
sieve_debug_internal (dbg->printer, dbg->data, " ");
}
void
sieve_print_tag_list (list_t list, sieve_printf_t printer, void *data)
{
struct debug_data dbg;
dbg.printer = printer;
dbg.data = data;
list_do (list, (list_action_t*) tag_printer, &dbg);
}
void
sieve_set_debug (sieve_machine_t *mach, sieve_printf_t debug, int level)
{
mach->debug_printer = debug;
mach->debug_level = level;
}
......