/* XXX ensure parent and child are properly set in all nodes */
struct ec_tk *parent;
unsigned int refcnt;
+#define EC_TK_F_INITIALIZED 0x0001
+ unsigned int flags;
TAILQ_ENTRY(ec_tk) next;
struct ec_tk_list children;
#include <string.h>
#include <assert.h>
#include <stdarg.h>
+#include <limits.h>
#include <errno.h>
#include <ecoli_malloc.h>
#include <ecoli_strvec.h>
#include <ecoli_tk.h>
#include <ecoli_tk_str.h>
+#include <ecoli_tk_int.h>
#include <ecoli_tk_seq.h>
#include <ecoli_tk_many.h>
+#include <ecoli_tk_or.h>
#include <ecoli_tk_expr.h>
struct ec_tk_expr {
struct ec_tk **bin_ops;
unsigned int bin_ops_len;
+
struct ec_tk **pre_ops;
unsigned int pre_ops_len;
+
struct ec_tk **post_ops;
unsigned int post_ops_len;
+
+ struct ec_tk **open_ops;
+ struct ec_tk **close_ops;
+ unsigned int paren_len;
};
static struct ec_parsed_tk *ec_tk_expr_parse(const struct ec_tk *gen_tk,
// XXX check tk type
- /* XXX use assert or check like this ? */
if (tk == NULL || op == NULL)
return -EINVAL;
+ if (gen_tk->flags & EC_TK_F_INITIALIZED)
+ return -EPERM;
bin_ops = ec_realloc(tk->bin_ops,
(tk->bin_ops_len + 1) * sizeof(*tk->bin_ops));
// XXX check tk type
- /* XXX use assert or check like this ? */
if (tk == NULL || op == NULL)
return -EINVAL;
+ if (gen_tk->flags & EC_TK_F_INITIALIZED)
+ return -EPERM;
pre_ops = ec_realloc(tk->pre_ops,
(tk->pre_ops_len + 1) * sizeof(*tk->pre_ops));
// XXX check tk type
- /* XXX use assert or check like this ? */
if (tk == NULL || op == NULL)
return -EINVAL;
+ if (gen_tk->flags & EC_TK_F_INITIALIZED)
+ return -EPERM;
post_ops = ec_realloc(tk->post_ops,
(tk->post_ops_len + 1) * sizeof(*tk->post_ops));
return 0;
}
+int ec_tk_expr_add_parenthesis(struct ec_tk *gen_tk,
+ struct ec_tk *open, struct ec_tk *close)
+{
+ struct ec_tk_expr *tk = (struct ec_tk_expr *)gen_tk;
+ struct ec_tk **open_ops, **close_ops;
+
+ // XXX check tk type
+
+ if (tk == NULL || open == NULL || close == NULL)
+ return -EINVAL;
+ if (gen_tk->flags & EC_TK_F_INITIALIZED)
+ return -EPERM;
+
+ open_ops = ec_realloc(tk->open_ops,
+ (tk->paren_len + 1) * sizeof(*tk->open_ops));
+ if (open_ops == NULL)
+ return -1;
+ close_ops = ec_realloc(tk->close_ops,
+ (tk->paren_len + 1) * sizeof(*tk->close_ops));
+ if (close_ops == NULL)
+ return -1;
+
+ tk->open_ops = open_ops;
+ tk->close_ops = close_ops;
+ open_ops[tk->paren_len] = open;
+ close_ops[tk->paren_len] = close;
+ tk->paren_len++;
+
+ return 0;
+}
+
int ec_tk_expr_start(struct ec_tk *gen_tk)
{
struct ec_tk_expr *tk = (struct ec_tk_expr *)gen_tk;
+ struct ec_tk *term = NULL, *prev = NULL, *expr = NULL,
+ *val = NULL, *pre_op = NULL, *post_op = NULL,
+ *post = NULL, *final = NULL, *next = NULL;
+ unsigned int i;
if (tk->val_tk == NULL)
return -EINVAL;
- if (tk->bin_ops_len == 0 || tk->pre_ops_len == 0 ||
+ if (gen_tk->flags & EC_TK_F_INITIALIZED)
+ return -EPERM;
+ if (tk->bin_ops_len == 0 && tk->pre_ops_len == 0 &&
tk->post_ops_len == 0)
return -EINVAL;
- return 0;
-}
+ /* create the object, we will initialize it later: this is
+ * needed because we have a circular dependency */
+ expr = ec_tk_seq_new("expr");
-struct ec_tk *ec_tk_expr(const char *id, struct ec_tk *val_tk,
- const char *bin_ops)
-{
- struct ec_tk_expr *tk = NULL;
- struct ec_tk *gen_tk = NULL, *child = NULL, *sub_expr = NULL;
- char *op = NULL;
+ val = ec_tk_int("val", 0, UCHAR_MAX, 0);
- gen_tk = ec_tk_expr_new(id);
- if (gen_tk == NULL)
+ /* prefix unary operators */
+ pre_op = ec_tk_or_new("pre-op");
+ for (i = 0; i < tk->pre_ops_len; i++) {
+ if (ec_tk_or_add(pre_op, ec_tk_clone(tk->pre_ops[i])) < 0)
+ goto fail;
+ }
+ if (ec_tk_or_start(pre_op) < 0)
goto fail;
- tk = (struct ec_tk_expr *)gen_tk;
- if (bin_ops == NULL || bin_ops[0] == '\0') {
- child = val_tk;
- } else {
- /* recursively create an expr tk without the first operator */
- sub_expr = ec_tk_expr(NULL,
- ec_tk_clone(val_tk),
- &bin_ops[1]);
- if (sub_expr == NULL)
+ /* suffix unary operators */
+ post_op = ec_tk_or_new("post-op");
+ for (i = 0; i < tk->post_ops_len; i++) {
+ if (ec_tk_or_add(post_op, ec_tk_clone(tk->post_ops[i])) < 0)
goto fail;
+ }
+ if (ec_tk_or_start(post_op) < 0)
+ goto fail;
- op = ec_strdup(bin_ops);
- if (op == NULL)
+ term = ec_tk_or_new("term");
+ if (ec_tk_or_add(term, ec_tk_clone(val)) < 0)
+ goto fail;
+ if (ec_tk_or_add(term,
+ ec_tk_seq(NULL,
+ ec_tk_clone(pre_op),
+ ec_tk_clone(expr),
+ EC_TK_ENDLIST)) < 0)
+ goto fail;
+ for (i = 0; i < tk->paren_len; i++) {
+ if (ec_tk_or_add(term, ec_tk_seq(NULL,
+ ec_tk_clone(tk->open_ops[i]),
+ ec_tk_clone(expr),
+ ec_tk_clone(tk->close_ops[i]),
+ EC_TK_ENDLIST)) < 0)
goto fail;
- op[1] = '\0';
+ }
- /* we match:
- * <subexpr> (<op> <subexpr>)*
- */
- child = ec_tk_seq_new_list(NULL,
- ec_tk_clone(sub_expr),
+ prev = term;
+ term = NULL;
+ for (i = 0; i < tk->bin_ops_len; i++) {
+ next = ec_tk_seq("next",
+ ec_tk_clone(prev),
ec_tk_many_new(NULL,
- ec_tk_seq_new_list(NULL,
- ec_tk_str_new(NULL, op),
- ec_tk_clone(sub_expr),
+ ec_tk_seq(NULL,
+ ec_tk_clone(tk->bin_ops[i]),
+ ec_tk_clone(prev),
EC_TK_ENDLIST
),
0, 0
),
EC_TK_ENDLIST
);
- ec_free(op);
- op = NULL;
-
- /* remove initial reference */
- ec_tk_free(sub_expr);
+ prev = next;
+ }
- if (child == NULL)
- goto fail;
+ final = ec_tk_seq("final",
+ ec_tk_clone(next),
+ ec_tk_many_new(NULL, ec_tk_clone(post_op), 0, 0),
+ EC_TK_ENDLIST
+ );
- ec_tk_free(val_tk);
- }
+ tk->child = final;
- tk->child = child;
+ gen_tk->flags |= EC_TK_F_INITIALIZED;
- return &tk->gen;
+ return 0;
fail:
- ec_free(op);
- ec_tk_free(child);
- ec_tk_free(val_tk);
- ec_tk_free(gen_tk);
- return NULL;
+ ec_tk_free(val);
+ ec_tk_free(pre_op);
+ ec_tk_free(post_op);
+ ec_tk_free(term);
+ ec_tk_free(post);
+ return -1;
}
static int ec_tk_expr_testcase(void)
{
- struct ec_tk *tk, *tk2, *val_tk;
+ struct ec_tk *term, *factor, *expr, *tk, *val,
+ *pre_op, *post_op, *post, *final;
int ret = 0;
- val_tk = ec_tk_str_new(NULL, "val");
- tk = ec_tk_seq_new_list(NULL,
- ec_tk_clone(val_tk),
+ // XXX check all APIs: pointers are "moved", they are freed by
+ // the callee
+
+ /* Example that generates an expression "manually". We keep it
+ * here for reference. */
+
+ /* create the object, we will initialize it later: this is
+ * needed because we have a circular dependency */
+ expr = ec_tk_seq_new("expr");
+
+ val = ec_tk_int("val", 0, UCHAR_MAX, 0);
+
+ /* reverse bits */
+ pre_op = ec_tk_or("pre-op",
+ ec_tk_str(NULL, "~"),
+ EC_TK_ENDLIST
+ );
+
+ /* factorial */
+ post_op = ec_tk_or("post-op",
+ ec_tk_str(NULL, "!"),
+ EC_TK_ENDLIST
+ );
+
+ term = ec_tk_or("term",
+ ec_tk_clone(val),
+ ec_tk_seq(NULL,
+ ec_tk_str(NULL, "("),
+ ec_tk_clone(expr),
+ ec_tk_str(NULL, ")"),
+ EC_TK_ENDLIST
+ ),
+ ec_tk_seq(NULL,
+ ec_tk_clone(pre_op),
+ ec_tk_clone(expr),
+ EC_TK_ENDLIST
+ ),
+ EC_TK_ENDLIST
+ );
+
+ factor = ec_tk_seq("factor",
+ ec_tk_clone(term),
ec_tk_many_new(NULL,
- ec_tk_seq_new_list(NULL,
- ec_tk_str_new(NULL, "*"),
- ec_tk_clone(val_tk),
+ ec_tk_seq(NULL,
+ ec_tk_str(NULL, "+"),
+ ec_tk_clone(term),
EC_TK_ENDLIST
),
0, 0
),
EC_TK_ENDLIST
);
- ec_tk_free(val_tk);
- val_tk = NULL;
- tk2 = ec_tk_seq_new_list(NULL,
- ec_tk_clone(tk),
+ post = ec_tk_seq("post",
+ ec_tk_clone(factor),
ec_tk_many_new(NULL,
- ec_tk_seq_new_list(NULL,
- ec_tk_str_new(NULL, "+"),
- ec_tk_clone(tk),
+ ec_tk_seq(NULL,
+ ec_tk_str(NULL, "*"),
+ ec_tk_clone(factor),
EC_TK_ENDLIST
),
0, 0
EC_TK_ENDLIST
);
+ final = ec_tk_seq("final",
+ ec_tk_clone(post),
+ ec_tk_many_new(NULL, ec_tk_clone(post_op), 0, 0),
+ EC_TK_ENDLIST
+ );
-// "/*-+");
- if (tk2 == NULL) {
- ec_log(EC_LOG_ERR, "cannot create tk\n");
+ /* free the initial references */
+ ec_tk_free(val);
+ ec_tk_free(pre_op);
+ ec_tk_free(post_op);
+ ec_tk_free(term);
+ ec_tk_free(factor);
+ ec_tk_free(post);
+
+ if (ec_tk_seq_add(expr, ec_tk_clone(final)) < 0) {
+ ec_tk_free(final);
+ ec_tk_free(expr);
return -1;
}
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "val", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "val", "*", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 3, "val", "*", "val", EC_TK_ENDLIST);
+ ec_tk_free(final);
- ret |= EC_TEST_CHECK_TK_PARSE(tk2, 1, "val", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk2, 1, "val", "*", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk2, 3, "val", "*", "val", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk2, 3, "val", "+", "val", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk2, 5, "val", "*", "val", "+", "val",
+ ret |= EC_TEST_CHECK_TK_PARSE(expr, 1, "1", EC_TK_ENDLIST);
+ ret |= EC_TEST_CHECK_TK_PARSE(expr, 1, "1", "*", EC_TK_ENDLIST);
+ ret |= EC_TEST_CHECK_TK_PARSE(expr, 3, "1", "*", "1", EC_TK_ENDLIST);
+ ret |= EC_TEST_CHECK_TK_PARSE(expr, 3, "1", "+", "1", EC_TK_ENDLIST);
+ ret |= EC_TEST_CHECK_TK_PARSE(expr, 5, "1", "*", "1", "+", "1",
+ EC_TK_ENDLIST);
+ ret |= EC_TEST_CHECK_TK_PARSE(
+ expr, 10, "~", "(", "1", "*", "(", "1", "+", "1", ")", ")",
+ EC_TK_ENDLIST);
+ ret |= EC_TEST_CHECK_TK_PARSE(expr, 4, "1", "+", "~", "1",
EC_TK_ENDLIST);
- ec_tk_free(tk);
- ec_tk_free(tk2);
-
- tk = ec_tk_expr(NULL, ec_tk_str_new(NULL, "val"), "*+");
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 5, "val", "*", "val", "+", "val",
+ ec_tk_free(expr);
+
+ tk = ec_tk_expr_new(NULL);
+ ec_tk_expr_set_val_tk(tk, ec_tk_int(NULL, 0, UCHAR_MAX, 0));
+ ec_tk_expr_add_bin_op(tk, ec_tk_str(NULL, "+"));
+ ec_tk_expr_add_bin_op(tk, ec_tk_str(NULL, "*"));
+ ec_tk_expr_add_pre_op(tk, ec_tk_str(NULL, "~"));
+ ec_tk_expr_add_pre_op(tk, ec_tk_str(NULL, "!"));
+ ec_tk_expr_add_parenthesis(tk, ec_tk_str(NULL, "("),
+ ec_tk_str(NULL, ")"));
+ ec_tk_expr_start(tk);
+
+ ret |= EC_TEST_CHECK_TK_PARSE(expr, 1, "1", EC_TK_ENDLIST);
+ ret |= EC_TEST_CHECK_TK_PARSE(expr, 1, "1", "*", EC_TK_ENDLIST);
+ ret |= EC_TEST_CHECK_TK_PARSE(expr, 3, "1", "*", "1", EC_TK_ENDLIST);
+ ret |= EC_TEST_CHECK_TK_PARSE(expr, 3, "1", "+", "1", EC_TK_ENDLIST);
+ ret |= EC_TEST_CHECK_TK_PARSE(expr, 5, "1", "*", "1", "+", "1",
+ EC_TK_ENDLIST);
+ ret |= EC_TEST_CHECK_TK_PARSE(
+ expr, 10, "~", "(", "1", "*", "(", "1", "+", "1", ")", ")",
+ EC_TK_ENDLIST);
+ ret |= EC_TEST_CHECK_TK_PARSE(expr, 4, "1", "+", "~", "1",
EC_TK_ENDLIST);
ec_tk_free(tk);
int ec_tk_expr_add_bin_op(struct ec_tk *gen_tk, struct ec_tk *op);
int ec_tk_expr_add_pre_op(struct ec_tk *gen_tk, struct ec_tk *op);
int ec_tk_expr_add_post_op(struct ec_tk *gen_tk, struct ec_tk *op);
+int ec_tk_expr_add_parenthesis(struct ec_tk *gen_tk,
+ struct ec_tk *open, struct ec_tk *close);
#endif
.complete = ec_tk_default_complete,
};
-struct ec_tk *ec_tk_int_new(const char *id, long long int min,
+struct ec_tk *ec_tk_int(const char *id, long long int min,
long long int max, unsigned int base)
{
+ struct ec_tk *gen_tk = NULL;
struct ec_tk_int *tk = NULL;
- tk = (struct ec_tk_int *)ec_tk_new(id, &ec_tk_int_ops, sizeof(*tk));
- if (tk == NULL)
+ gen_tk = ec_tk_new(id, &ec_tk_int_ops, sizeof(*tk));
+ if (gen_tk == NULL)
return NULL;
+ tk = (struct ec_tk_int *)gen_tk;
tk->min = min;
tk->max = max;
tk->base = base;
+ gen_tk->flags |= EC_TK_F_INITIALIZED;
return &tk->gen;
}
const char *s;
int ret = 0;
- tk = ec_tk_int_new(NULL, 0, 256, 0);
+ tk = ec_tk_int(NULL, 0, 256, 0);
if (tk == NULL) {
ec_log(EC_LOG_ERR, "cannot create tk\n");
return -1;
ec_parsed_tk_free(p);
ec_tk_free(tk);
- tk = ec_tk_int_new(NULL, -1, LLONG_MAX, 16);
+ tk = ec_tk_int(NULL, -1, LLONG_MAX, 16);
if (tk == NULL) {
ec_log(EC_LOG_ERR, "cannot create tk\n");
return -1;
ec_parsed_tk_free(p);
ec_tk_free(tk);
- tk = ec_tk_int_new(NULL, LLONG_MIN, 0, 10);
+ tk = ec_tk_int(NULL, LLONG_MIN, 0, 10);
if (tk == NULL) {
ec_log(EC_LOG_ERR, "cannot create tk\n");
return -1;
ec_tk_free(tk);
/* test completion */
- tk = ec_tk_int_new(NULL, 0, 10, 0);
+ tk = ec_tk_int(NULL, 0, 10, 0);
if (tk == NULL) {
ec_log(EC_LOG_ERR, "cannot create tk\n");
return -1;
#include <ecoli_tk.h>
-struct ec_tk *ec_tk_int_new(const char *id, long long int min,
+struct ec_tk *ec_tk_int(const char *id, long long int min,
long long int max, unsigned int base);
long long ec_tk_int_getval(struct ec_tk *tk, const char *str);
struct ec_tk *tk;
int ret = 0;
- tk = ec_tk_many_new(NULL, ec_tk_str_new(NULL, "foo"), 0, 0);
+ tk = ec_tk_many_new(NULL, ec_tk_str(NULL, "foo"), 0, 0);
if (tk == NULL) {
ec_log(EC_LOG_ERR, "cannot create tk\n");
return -1;
ret |= EC_TEST_CHECK_TK_PARSE(tk, 0, EC_TK_ENDLIST);
ec_tk_free(tk);
- tk = ec_tk_many_new(NULL, ec_tk_str_new(NULL, "foo"), 1, 0);
+ tk = ec_tk_many_new(NULL, ec_tk_str(NULL, "foo"), 1, 0);
if (tk == NULL) {
ec_log(EC_LOG_ERR, "cannot create tk\n");
return -1;
ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, EC_TK_ENDLIST);
ec_tk_free(tk);
- tk = ec_tk_many_new(NULL, ec_tk_str_new(NULL, "foo"), 1, 2);
+ tk = ec_tk_many_new(NULL, ec_tk_str(NULL, "foo"), 1, 2);
if (tk == NULL) {
ec_log(EC_LOG_ERR, "cannot create tk\n");
return -1;
struct ec_tk *tk;
int ret = 0;
- tk = ec_tk_option_new(NULL, ec_tk_str_new(NULL, "foo"));
+ tk = ec_tk_option_new(NULL, ec_tk_str(NULL, "foo"));
if (tk == NULL) {
ec_log(EC_LOG_ERR, "cannot create tk\n");
return -1;
ec_tk_free(tk);
/* test completion */
- tk = ec_tk_option_new(NULL, ec_tk_str_new(NULL, "foo"));
+ tk = ec_tk_option_new(NULL, ec_tk_str(NULL, "foo"));
if (tk == NULL) {
ec_log(EC_LOG_ERR, "cannot create tk\n");
return -1;
#include <string.h>
#include <assert.h>
#include <stdarg.h>
+#include <errno.h>
#include <ecoli_malloc.h>
#include <ecoli_log.h>
return &tk->gen;
}
-struct ec_tk *ec_tk_or_new_list(const char *id, ...)
+int ec_tk_or_add(struct ec_tk *gen_tk, struct ec_tk *child)
+{
+ struct ec_tk_or *tk = (struct ec_tk_or *)gen_tk;
+ struct ec_tk **table;
+
+ assert(tk != NULL);
+ assert(child != NULL);
+
+ if (gen_tk->flags & EC_TK_F_INITIALIZED)
+ return -EPERM;
+
+ table = ec_realloc(tk->table, (tk->len + 1) * sizeof(*tk->table));
+ if (table == NULL)
+ return -1;
+
+ tk->table = table;
+ table[tk->len] = child;
+ tk->len++;
+
+ child->parent = gen_tk;
+ TAILQ_INSERT_TAIL(&gen_tk->children, child, next);
+
+ return 0;
+}
+
+int ec_tk_or_start(struct ec_tk *gen_tk)
+{
+ if (gen_tk->flags & EC_TK_F_INITIALIZED)
+ return -EPERM;
+
+ gen_tk->flags |= EC_TK_F_INITIALIZED;
+
+ return 0;
+}
+
+struct ec_tk *ec_tk_or(const char *id, ...)
{
struct ec_tk_or *tk = NULL;
struct ec_tk *child;
tk = (struct ec_tk_or *)ec_tk_or_new(id);
if (tk == NULL)
- goto fail;
+ fail = 1;
for (child = va_arg(ap, struct ec_tk *);
child != EC_TK_ENDLIST;
return NULL;
}
-int ec_tk_or_add(struct ec_tk *gen_tk, struct ec_tk *child)
-{
- struct ec_tk_or *tk = (struct ec_tk_or *)gen_tk;
- struct ec_tk **table;
-
- assert(tk != NULL);
- assert(child != NULL);
-
- table = ec_realloc(tk->table, (tk->len + 1) * sizeof(*tk->table));
- if (table == NULL)
- return -1;
-
- tk->table = table;
- table[tk->len] = child;
- tk->len ++;
-
- child->parent = gen_tk;
- TAILQ_INSERT_TAIL(&gen_tk->children, child, next);
-
- return 0;
-}
-
static int ec_tk_or_testcase(void)
{
struct ec_tk *tk;
int ret = 0;
- tk = ec_tk_or_new_list(NULL,
- ec_tk_str_new(NULL, "foo"),
- ec_tk_str_new(NULL, "bar"),
+ tk = ec_tk_or(NULL,
+ ec_tk_str(NULL, "foo"),
+ ec_tk_str(NULL, "bar"),
EC_TK_ENDLIST);
if (tk == NULL) {
ec_log(EC_LOG_ERR, "cannot create tk\n");
ec_tk_free(tk);
/* test completion */
- tk = ec_tk_or_new_list(NULL,
- ec_tk_str_new(NULL, "foo"),
- ec_tk_str_new(NULL, "bar"),
- ec_tk_str_new(NULL, "bar2"),
- ec_tk_str_new(NULL, "toto"),
- ec_tk_str_new(NULL, "titi"),
+ tk = ec_tk_or(NULL,
+ ec_tk_str(NULL, "foo"),
+ ec_tk_str(NULL, "bar"),
+ ec_tk_str(NULL, "bar2"),
+ ec_tk_str(NULL, "toto"),
+ ec_tk_str(NULL, "titi"),
EC_TK_ENDLIST);
if (tk == NULL) {
ec_log(EC_LOG_ERR, "cannot create tk\n");
#include <ecoli_tk.h>
-struct ec_tk *ec_tk_or_new(const char *id);
-
/* list must be terminated with EC_TK_ENDLIST */
/* all token given in the list will be freed when freeing this one */
-struct ec_tk *ec_tk_or_new_list(const char *id, ...);
+struct ec_tk *ec_tk_or(const char *id, ...);
+struct ec_tk *ec_tk_or_new(const char *id);
/* all token given in the list will be freed when freeing this one */
int ec_tk_or_add(struct ec_tk *tk, struct ec_tk *child);
+int ec_tk_or_start(struct ec_tk *tk);
#endif
#include <string.h>
#include <assert.h>
#include <stdarg.h>
+#include <errno.h>
#include <ecoli_malloc.h>
#include <ecoli_log.h>
return &tk->gen;
}
-struct ec_tk *ec_tk_seq_new_list(const char *id, ...)
+int ec_tk_seq_add(struct ec_tk *gen_tk, struct ec_tk *child)
+{
+ struct ec_tk_seq *tk = (struct ec_tk_seq *)gen_tk;
+ struct ec_tk **table;
+
+ // XXX check tk type
+
+ assert(tk != NULL);
+ assert(child != NULL);
+
+ if (gen_tk->flags & EC_TK_F_INITIALIZED)
+ return -EPERM;
+
+ table = ec_realloc(tk->table, (tk->len + 1) * sizeof(*tk->table));
+ if (table == NULL)
+ return -1;
+
+ tk->table = table;
+ table[tk->len] = child;
+ tk->len++;
+
+ child->parent = gen_tk;
+ TAILQ_INSERT_TAIL(&gen_tk->children, child, next); // XXX really needed?
+
+ return 0;
+}
+
+int ec_tk_seq_start(struct ec_tk *gen_tk)
+{
+ if (gen_tk->flags & EC_TK_F_INITIALIZED)
+ return -EPERM;
+
+ gen_tk->flags |= EC_TK_F_INITIALIZED;
+
+ return 0;
+}
+
+struct ec_tk *ec_tk_seq(const char *id, ...)
{
struct ec_tk_seq *tk = NULL;
struct ec_tk *child;
return NULL;
}
-int ec_tk_seq_add(struct ec_tk *gen_tk, struct ec_tk *child)
-{
- struct ec_tk_seq *tk = (struct ec_tk_seq *)gen_tk;
- struct ec_tk **table;
-
- // XXX check tk type
-
- assert(tk != NULL);
- assert(child != NULL);
-
- table = ec_realloc(tk->table, (tk->len + 1) * sizeof(*tk->table));
- if (table == NULL)
- return -1;
-
- tk->table = table;
- table[tk->len] = child;
- tk->len++;
-
- child->parent = gen_tk;
- TAILQ_INSERT_TAIL(&gen_tk->children, child, next); // XXX really needed?
-
- return 0;
-}
-
static int ec_tk_seq_testcase(void)
{
struct ec_tk *tk;
int ret = 0;
- tk = ec_tk_seq_new_list(NULL,
- ec_tk_str_new(NULL, "foo"),
- ec_tk_str_new(NULL, "bar"),
+ tk = ec_tk_seq(NULL,
+ ec_tk_str(NULL, "foo"),
+ ec_tk_str(NULL, "bar"),
EC_TK_ENDLIST);
if (tk == NULL) {
ec_log(EC_LOG_ERR, "cannot create tk\n");
ec_tk_free(tk);
/* test completion */
- tk = ec_tk_seq_new_list(NULL,
- ec_tk_str_new(NULL, "foo"),
- ec_tk_option_new(NULL, ec_tk_str_new(NULL, "toto")),
- ec_tk_str_new(NULL, "bar"),
+ tk = ec_tk_seq(NULL,
+ ec_tk_str(NULL, "foo"),
+ ec_tk_option_new(NULL, ec_tk_str(NULL, "toto")),
+ ec_tk_str(NULL, "bar"),
EC_TK_ENDLIST);
if (tk == NULL) {
ec_log(EC_LOG_ERR, "cannot create tk\n");
#include <ecoli_tk.h>
-struct ec_tk *ec_tk_seq_new(const char *id);
/* list must be terminated with EC_TK_ENDLIST */
-struct ec_tk *ec_tk_seq_new_list(const char *id, ...);
+struct ec_tk *ec_tk_seq(const char *id, ...);
+struct ec_tk *ec_tk_seq_new(const char *id);
int ec_tk_seq_add(struct ec_tk *tk, struct ec_tk *child);
+int ec_tk_seq_start(struct ec_tk *tk);
+
#endif
int ret = 0;
tk = ec_tk_shlex_new(NULL,
- ec_tk_seq_new_list(NULL,
- ec_tk_str_new(NULL, "foo"),
+ ec_tk_seq(NULL,
+ ec_tk_str(NULL, "foo"),
ec_tk_option_new(NULL,
- ec_tk_str_new(NULL, "toto")
+ ec_tk_str(NULL, "toto")
),
- ec_tk_str_new(NULL, "bar"),
+ ec_tk_str(NULL, "bar"),
EC_TK_ENDLIST
)
);
/* test completion */
tk = ec_tk_shlex_new(NULL,
- ec_tk_seq_new_list(NULL,
- ec_tk_str_new(NULL, "foo"),
+ ec_tk_seq(NULL,
+ ec_tk_str(NULL, "foo"),
ec_tk_option_new(NULL,
- ec_tk_str_new(NULL, "toto")
+ ec_tk_str(NULL, "toto")
),
- ec_tk_str_new(NULL, "bar"),
- ec_tk_str_new(NULL, "titi"),
+ ec_tk_str(NULL, "bar"),
+ ec_tk_str(NULL, "titi"),
EC_TK_ENDLIST
)
);
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <errno.h>
#include <ecoli_log.h>
#include <ecoli_malloc.h>
.free_priv = ec_tk_str_free_priv,
};
-struct ec_tk *ec_tk_str_new(const char *id, const char *str)
+struct ec_tk *ec_tk_str_new(const char *id)
{
struct ec_tk *gen_tk = NULL;
- struct ec_tk_str *tk = NULL;
- char *s = NULL;
- gen_tk = ec_tk_new(id, &ec_tk_str_ops, sizeof(*tk));
+ gen_tk = ec_tk_new(id, &ec_tk_str_ops, sizeof(struct ec_tk_str));
+ if (gen_tk == NULL)
+ return NULL;
+
+ return gen_tk;
+}
+
+int ec_tk_str_set_str(struct ec_tk *gen_tk, const char *str)
+{
+ struct ec_tk_str *tk = (struct ec_tk_str *)gen_tk;
+
+ if (str == NULL)
+ return -EINVAL;
+ if (tk->string != NULL)
+ return -EEXIST;
+ if (gen_tk->flags & EC_TK_F_INITIALIZED)
+ return -EPERM;
+
+ tk->string = ec_strdup(str);
+ if (tk->string == NULL)
+ return -ENOMEM;
+
+ tk->len = strlen(tk->string);
+
+ return 0;
+}
+
+int ec_tk_str_start(struct ec_tk *gen_tk)
+{
+ if (gen_tk->flags & EC_TK_F_INITIALIZED)
+ return -EPERM;
+
+ gen_tk->flags |= EC_TK_F_INITIALIZED;
+
+ return 0;
+}
+
+struct ec_tk *ec_tk_str(const char *id, const char *str)
+{
+ struct ec_tk *gen_tk = NULL;
+
+ gen_tk = ec_tk_str_new(id);
if (gen_tk == NULL)
goto fail;
- s = ec_strdup(str);
- if (s == NULL)
+ if (ec_tk_str_set_str(gen_tk, str) < 0)
goto fail;
- tk = (struct ec_tk_str *)gen_tk;
- tk->string = s;
- tk->len = strlen(s);
+ if (ec_tk_str_start(gen_tk) < 0)
+ goto fail;
return gen_tk;
fail:
- ec_free(s);
ec_tk_free(gen_tk);
return NULL;
}
struct ec_tk *tk;
int ret = 0;
- tk = ec_tk_str_new(NULL, "foo");
+ tk = ec_tk_str(NULL, "foo");
if (tk == NULL) {
ec_log(EC_LOG_ERR, "cannot create tk\n");
return -1;
ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "", EC_TK_ENDLIST);
ec_tk_free(tk);
- tk = ec_tk_str_new(NULL, "Здравствуйте");
+ tk = ec_tk_str(NULL, "Здравствуйте");
if (tk == NULL) {
ec_log(EC_LOG_ERR, "cannot create tk\n");
return -1;
ec_tk_free(tk);
/* an empty token string always matches */
- tk = ec_tk_str_new(NULL, "");
+ tk = ec_tk_str(NULL, "");
if (tk == NULL) {
ec_log(EC_LOG_ERR, "cannot create tk\n");
return -1;
ec_tk_free(tk);
/* test completion */
- tk = ec_tk_str_new(NULL, "foo");
+ tk = ec_tk_str(NULL, "foo");
if (tk == NULL) {
ec_log(EC_LOG_ERR, "cannot create tk\n");
return -1;
#include <ecoli_tk.h>
-struct ec_tk *ec_tk_str_new(const char *id, const char *str);
+struct ec_tk *ec_tk_str(const char *id, const char *str);
+
+struct ec_tk *ec_tk_str_new(const char *id);
+int ec_tk_str_set_str(struct ec_tk *tk, const char *str);
+int ec_tk_str_start(struct ec_tk *tk);
#endif
if (cmdlist == NULL)
goto fail;
- cmd = ec_tk_seq_new_list(NULL,
- ec_tk_str_new(NULL, "hello"),
- ec_tk_or_new_list(NULL,
- ec_tk_or_new_list("name",
- ec_tk_str_new(NULL, "john"),
- ec_tk_str_new(NULL, "johnny"),
- ec_tk_str_new(NULL, "mike"),
+ cmd = ec_tk_seq(NULL,
+ ec_tk_str(NULL, "hello"),
+ ec_tk_or(NULL,
+ ec_tk_or("name",
+ ec_tk_str(NULL, "john"),
+ ec_tk_str(NULL, "johnny"),
+ ec_tk_str(NULL, "mike"),
EC_TK_ENDLIST
),
- ec_tk_int_new("int", 0, 10, 10),
+ ec_tk_int("int", 0, 10, 10),
EC_TK_ENDLIST
),
EC_TK_ENDLIST
if (ec_tk_or_add(cmdlist, cmd) < 0)
goto fail;
- cmd = ec_tk_seq_new_list(NULL,
- ec_tk_str_new(NULL, "bye"),
+ cmd = ec_tk_seq(NULL,
+ ec_tk_str(NULL, "bye"),
EC_TK_ENDLIST
);
ec_keyval_set(ec_tk_attrs(cmd), "help", "say bye to someone", NULL);