diff --git a/ase/awk/awk.c b/ase/awk/awk.c index 46e5c144..65894c74 100644 --- a/ase/awk/awk.c +++ b/ase/awk/awk.c @@ -1,5 +1,5 @@ /* - * $Id: awk.c,v 1.14 2006-01-30 14:45:12 bacon Exp $ + * $Id: awk.c,v 1.15 2006-01-31 16:57:45 bacon Exp $ */ #include @@ -31,14 +31,15 @@ xp_awk_t* xp_awk_open (xp_awk_t* awk) return XP_NULL; } - if (xp_awk_tab_open(&awk->parse.funcs) == XP_NULL) { + if (xp_awk_tab_open(&awk->parse.params) == XP_NULL) { xp_str_close (&awk->token.name); xp_awk_hash_close (&awk->tree.funcs); if (awk->__dynamic) xp_free (awk); return XP_NULL; } - awk->opt = 0; + awk->opt.parse = 0; + awk->opt.run = 0; awk->errnum = XP_AWK_ENOERR; awk->src_func = XP_NULL; @@ -65,13 +66,58 @@ int xp_awk_close (xp_awk_t* awk) if (xp_awk_detsrc(awk) == -1) return -1; xp_awk_hash_close (&awk->tree.funcs); - xp_awk_tab_close (&awk->parse.funcs); + xp_awk_tab_close (&awk->parse.params); xp_str_close (&awk->token.name); if (awk->__dynamic) xp_free (awk); return 0; } +int xp_awk_geterrnum (xp_awk_t* awk) +{ + return awk->errnum; +} + +const xp_char_t* xp_awk_geterrstr (xp_awk_t* awk) +{ + static const xp_char_t* __errstr[] = + { + XP_TEXT("no error"), + XP_TEXT("out of memory"), + + XP_TEXT("cannot open source"), + XP_TEXT("cannot close source"), + XP_TEXT("cannot read source"), + + XP_TEXT("invalid character"), + XP_TEXT("cannot unget character"), + + XP_TEXT("unexpected end of source"), + XP_TEXT("left brace expected"), + XP_TEXT("left parenthesis expected"), + XP_TEXT("right parenthesis expected"), + XP_TEXT("right bracket expected"), + XP_TEXT("comma expected"), + XP_TEXT("semicolon expected"), + XP_TEXT("expression expected"), + + XP_TEXT("keyword 'while' expected"), + XP_TEXT("assignment statement expected"), + XP_TEXT("identifier expected"), + XP_TEXT("duplicate BEGIN"), + XP_TEXT("duplicate END"), + XP_TEXT("duplicate function name"), + XP_TEXT("duplicate parameter name"), + XP_TEXT("duplicate name"), + }; + + if (awk->errnum >= 0 && awk->errnum < xp_countof(__errstr)) { + return __errstr[awk->errnum]; + } + + return XP_TEXT("unknown error"); +} + // TODO: write a function to clear awk->parse data structure. // this would be need either as a separate function or as a part of xp_awk_clear... // do i have to pass an option to xp_awk_clear to do this??? @@ -148,3 +194,4 @@ static void __free_func (void* func) xp_awk_clrpt (f->body); xp_free (f); } + diff --git a/ase/awk/awk.h b/ase/awk/awk.h index 0106d4c9..d20d42a2 100644 --- a/ase/awk/awk.h +++ b/ase/awk/awk.h @@ -1,5 +1,5 @@ /* - * $Id: awk.h,v 1.22 2006-01-30 14:34:47 bacon Exp $ + * $Id: awk.h,v 1.23 2006-01-31 16:57:45 bacon Exp $ */ #ifndef _XP_AWK_AWK_H_ @@ -21,6 +21,7 @@ enum { XP_AWK_ENOERR, XP_AWK_ENOMEM, /* out of memory */ + XP_AWK_ESRCOP, XP_AWK_ESRCCL, XP_AWK_ESRCDT, /* error in reading source */ @@ -43,6 +44,7 @@ enum XP_AWK_EDUPBEGIN, /* duplicate BEGIN */ XP_AWK_EDUPEND, /* duplicate END */ XP_AWK_EDUPFUNC, /* duplicate function name */ + XP_AWK_EDUPPARAM, /* duplicate parameter name */ XP_AWK_EDUPNAME /* duplicate name - function, variable, etc */ }; @@ -65,16 +67,21 @@ enum XP_AWK_IO_DATA }; -/* options */ +/* parse options */ enum { - XP_AWK_ASSIGN_ONLY /* a non-assignment expression cannot be used as a statement */ + XP_AWK_EXPLICIT = (1 << 0), /* variable requires explicit declaration */ + XP_AWK_UNIQUE = (1 << 1) /* a function name should not coincide to be a variable name */ }; struct xp_awk_t { /* options */ - int opt; + struct + { + int parse; + int run; + } opt; /* io functions */ xp_awk_io_t src_func; @@ -97,10 +104,9 @@ struct xp_awk_t /* temporary information that the parser needs */ struct { - xp_awk_tab_t funcs; // TODO: locals, globals??? - xp_char_t* vars; /* global and local variable names... */ - xp_char_t* args; /* function arguments */ + //xp_awk_tab_t vars; /* global and local variable names... */ + xp_awk_tab_t params; } parse; /* source buffer management */ @@ -137,6 +143,10 @@ xp_awk_t* xp_awk_open (xp_awk_t* awk); */ int xp_awk_close (xp_awk_t* awk); + +int xp_awk_geterrnum (xp_awk_t* awk); +const xp_char_t* xp_awk_geterrstr (xp_awk_t* awk); + /* * FUNCTION: xp_awk_clear */ diff --git a/ase/awk/parse.c b/ase/awk/parse.c index 02f93136..a762f11e 100644 --- a/ase/awk/parse.c +++ b/ase/awk/parse.c @@ -1,5 +1,5 @@ /* - * $Id: parse.c,v 1.40 2006-01-30 14:45:12 bacon Exp $ + * $Id: parse.c,v 1.41 2006-01-31 16:57:45 bacon Exp $ */ #include @@ -118,10 +118,6 @@ static int __classfy_ident (const xp_char_t* ident); static xp_long_t __str_to_long (const xp_char_t* name); -static INLINE xp_size_t __add_func_name (xp_awk_t* awk, const xp_char_t* name); -static INLINE xp_size_t __find_func_name (xp_awk_t* awk, const xp_char_t* name); -static INLINE int __remove_func_name (xp_awk_t* awk, xp_size_t index); - static INLINE xp_size_t __find_func_arg (xp_awk_t* awk, const xp_char_t* name); static INLINE xp_size_t __find_variable (xp_awk_t* awk, const xp_char_t* name); @@ -233,9 +229,8 @@ int xp_awk_parse (xp_awk_t* awk) if (MATCH(awk,TOKEN_EOF)) break; if (__parse_progunit(awk) == XP_NULL) { - // TODO: cleanup the parse tree created so far.... - // function tables also etc... -xp_printf (XP_TEXT("error - %d\n"), awk->errnum); +// TODO: cleanup the parse tree created so far.... +// function tables also etc... return -1; } } @@ -294,62 +289,60 @@ static xp_awk_node_t* __parse_function (xp_awk_t* awk) xp_char_t* name_dup; xp_awk_node_t* body; xp_awk_func_t* func; - xp_size_t fnpos; - xp_size_t nargs = 0; + xp_size_t nargs; + /* eat up the keyword 'function' and get the next token */ if (__get_token(awk) == -1) return XP_NULL; - /* function name */ - if (!MATCH(awk,TOKEN_IDENT)) PANIC (awk, XP_AWK_EIDENT); + /* match a function name */ + if (!MATCH(awk,TOKEN_IDENT)) { + /* cannot find a valid identifier for a function name */ + PANIC (awk, XP_AWK_EIDENT); + } name = XP_STR_BUF(&awk->token.name); - if (__find_func_name(awk,name) != (xp_size_t)-1) { -// TODO: do i have to tell DUPFUNC from DUPNAME??? - //PANIC (awk, XP_AWK_EDUPFUNC); - PANIC (awk, XP_AWK_EDUPNAME); - } - -// TODO: make this feature optional.. -// find in the global variable list... - if (__find_variable(awk,name) != (xp_size_t)-1) { - PANIC (awk, XP_AWK_EDUPNAME); + if (xp_awk_hash_get(&awk->tree.funcs, name) != XP_NULL) { + /* the function is defined previously */ + PANIC (awk, XP_AWK_EDUPFUNC); } - fnpos = __add_func_name (awk, name); - if (fnpos == -1) PANIC (awk, XP_AWK_ENOMEM); + if (awk->opt.parse & XP_AWK_UNIQUE) { + /* check if it coincides to be a variable name */ + if (__find_variable(awk,name) != (xp_size_t)-1) { + PANIC (awk, XP_AWK_EDUPNAME); + } + } - // TODO: move this strdup down the function.... - // maybe just before func_t is allocated... + /* clone the function name before it is overwritten */ name_dup = xp_strdup (name); - if (name_dup == XP_NULL) { - __remove_func_name (awk, fnpos); - PANIC (awk, XP_AWK_ENOMEM); - } + if (name_dup == XP_NULL) PANIC (awk, XP_AWK_ENOMEM); - /* skip the function name */ + /* get the next token */ if (__get_token(awk) == -1) { - __remove_func_name (awk, fnpos); xp_free (name_dup); return XP_NULL; } + /* match a left parenthesis */ if (!MATCH(awk,TOKEN_LPAREN)) { - __remove_func_name (awk, fnpos); + /* a function name is not followed by a left parenthesis */ xp_free (name_dup); PANIC (awk, XP_AWK_ELPAREN); } + /* get the next token */ if (__get_token(awk) == -1) { - __remove_func_name (awk, fnpos); xp_free (name_dup); return XP_NULL; } - /* parameter name list */ + /* make sure that parameter table is empty */ + xp_assert (xp_awk_tab_getsize(&awk->parse.params) == 0); + + /* read parameter list */ if (MATCH(awk,TOKEN_RPAREN)) { - /* no function parameter */ + /* no function parameter found. get the next token */ if (__get_token(awk) == -1) { - __remove_func_name (awk, fnpos); xp_free (name_dup); return XP_NULL; } @@ -357,70 +350,83 @@ static xp_awk_node_t* __parse_function (xp_awk_t* awk) else { while (1) { if (!MATCH(awk,TOKEN_IDENT)) { - __remove_func_name (awk, fnpos); xp_free (name_dup); + xp_awk_tab_clear (&awk->parse.params); PANIC (awk, XP_AWK_EIDENT); } - nargs++; - // TODO: push args to param list... +// TODO: check duplicates againt variables if shading is not supported +// global x; function f (x) { print x; } -> x in print x is a parameter + + if (xp_awk_tab_find (&awk->parse.params, + XP_STR_BUF(&awk->token.name), 0) != (xp_size_t)-1) { + xp_free (name_dup); + xp_awk_tab_clear (&awk->parse.params); + PANIC (awk, XP_AWK_EDUPPARAM); + } + + if (xp_awk_tab_adddatum (&awk->parse.params, + XP_STR_BUF(&awk->token.name)) == (xp_size_t)-1) { + xp_free (name_dup); + xp_awk_tab_clear (&awk->parse.params); + PANIC (awk, XP_AWK_ENOMEM); + } if (__get_token(awk) == -1) { - __remove_func_name (awk, fnpos); xp_free (name_dup); + xp_awk_tab_clear (&awk->parse.params); return XP_NULL; } if (MATCH(awk,TOKEN_RPAREN)) break; if (!MATCH(awk,TOKEN_COMMA)) { - __remove_func_name (awk, fnpos); xp_free (name_dup); + xp_awk_tab_clear (&awk->parse.params); PANIC (awk, XP_AWK_ECOMMA); } if (__get_token(awk) == -1) { - __remove_func_name (awk, fnpos); xp_free (name_dup); + xp_awk_tab_clear (&awk->parse.params); return XP_NULL; } } if (__get_token(awk) == -1) { - __remove_func_name (awk, fnpos); -// TODO: cleanup parameter name list xp_free (name_dup); + xp_awk_tab_clear (&awk->parse.params); return XP_NULL; } } /* check if the function body starts with a left brace */ if (!MATCH(awk,TOKEN_LBRACE)) { - __remove_func_name (awk, fnpos); -// TODO: cleanup parameter name list xp_free (name_dup); + xp_awk_tab_clear (&awk->parse.params); PANIC (awk, XP_AWK_ELBRACE); } if (__get_token(awk) == -1) { - __remove_func_name (awk, fnpos); -// TODO: cleanup parameter name list xp_free (name_dup); + xp_awk_tab_clear (&awk->parse.params); return XP_NULL; } /* actual function body */ body = __parse_block (awk); if (body == XP_NULL) { - __remove_func_name (awk, fnpos); -// TODO: cleanup parameter name list xp_free (name_dup); + xp_awk_tab_clear (&awk->parse.params); return XP_NULL; } +// TODO: consider if the parameters should be saved for some reasons.. + nargs = xp_awk_tab_getsize(&awk->parse.params); + /* parameter names are not required anymore. clear them */ + xp_awk_tab_clear (&awk->parse.params); + func = (xp_awk_func_t*) xp_malloc (xp_sizeof(xp_awk_func_t)); if (func == XP_NULL) { - __remove_func_name (awk, fnpos); -// TODO: cleanup parameter name list xp_free (name_dup); xp_awk_clrpt (body); return XP_NULL; @@ -432,7 +438,6 @@ static xp_awk_node_t* __parse_function (xp_awk_t* awk) xp_assert (xp_awk_hash_get(&awk->tree.funcs, name_dup) == XP_NULL); if (xp_awk_hash_put(&awk->tree.funcs, name_dup, func) == XP_NULL) { - __remove_func_name (awk, fnpos); xp_free (name_dup); xp_awk_clrpt (body); xp_free (func); @@ -696,10 +701,11 @@ static xp_awk_node_t* __parse_expression (xp_awk_t* awk) if (!MATCH(awk,TOKEN_ASSIGN)) return x; xp_assert (x->next == XP_NULL); - if (x->type != XP_AWK_NODE_VAR && + if (x->type != XP_AWK_NODE_ARG && + x->type != XP_AWK_NODE_ARGIDX && + x->type != XP_AWK_NODE_VAR && x->type != XP_AWK_NODE_VARIDX && x->type != XP_AWK_NODE_POS) { -// TODO: XP_AWK_NODE_ARG, XP_AWK_NODE_ARGIDX xp_awk_clrpt (x); PANIC (awk, XP_AWK_EASSIGN); } @@ -880,27 +886,27 @@ static xp_awk_node_t* __parse_unary (xp_awk_t* awk) static xp_awk_node_t* __parse_primary (xp_awk_t* awk) { if (MATCH(awk,TOKEN_IDENT)) { - xp_char_t* name; + xp_char_t* name_dup; - name = (xp_char_t*)xp_strdup(XP_STR_BUF(&awk->token.name)); - if (name == XP_NULL) PANIC (awk, XP_AWK_ENOMEM); + name_dup = (xp_char_t*)xp_strdup(XP_STR_BUF(&awk->token.name)); + if (name_dup == XP_NULL) PANIC (awk, XP_AWK_ENOMEM); if (__get_token(awk) == -1) { - xp_free (name); + xp_free (name_dup); return XP_NULL; } if (MATCH(awk,TOKEN_LBRACK)) { xp_awk_node_t* node; - node = __parse_hashidx (awk, name); - if (node == XP_NULL) xp_free (name); + node = __parse_hashidx (awk, name_dup); + if (node == XP_NULL) xp_free (name_dup); return (xp_awk_node_t*)node; } else if (MATCH(awk,TOKEN_LPAREN)) { /* function call */ xp_awk_node_t* node; - node = __parse_funcall (awk, name); - if (node == XP_NULL) xp_free (name); + node = __parse_funcall (awk, name_dup); + if (node == XP_NULL) xp_free (name_dup); return (xp_awk_node_t*)node; } else { @@ -910,24 +916,37 @@ static xp_awk_node_t* __parse_primary (xp_awk_t* awk) node = (xp_awk_node_var_t*)xp_malloc(xp_sizeof(xp_awk_node_var_t)); if (node == XP_NULL) { - xp_free (name); + xp_free (name_dup); PANIC (awk, XP_AWK_ENOMEM); } + /* search the parameter name list */ + idxa = xp_awk_tab_find (&awk->parse.params, name_dup, 0); + if (idxa != (xp_size_t)-1) { + node->type = XP_AWK_NODE_ARG; + node->next = XP_NULL; + //node->id.name = XP_NULL; + node->id.name = name_dup; + node->id.idxa = idxa; + + return (xp_awk_node_t*)node; + } + + /* search the variable name list */ // TODO: - idxa = __find_variable (awk, name); + idxa = __find_variable (awk, name_dup); if (idxa == (xp_size_t)-1) { - idxa = __find_func_arg (awk, name); + idxa = __find_func_arg (awk, name_dup); if (idxa == (xp_size_t)-1) { node->type = XP_AWK_NODE_VAR; node->next = XP_NULL; - node->id.name = name; + node->id.name = name_dup; } else { node->type = XP_AWK_NODE_ARG; node->next = XP_NULL; // TODO: do i need to store the name here??? - node->id.name = name; + node->id.name = name_dup; node->id.idxa = idxa; } } @@ -936,7 +955,7 @@ static xp_awk_node_t* __parse_primary (xp_awk_t* awk) node->type = XP_AWK_NODE_VAR; node->next = XP_NULL; // TODO: do i need to store the name here??? - node->id.name = name; + node->id.name = name_dup; node->id.idxa = idxa; } @@ -1040,6 +1059,7 @@ static xp_awk_node_t* __parse_hashidx (xp_awk_t* awk, xp_char_t* name) { xp_awk_node_t* idx; xp_awk_node_idx_t* node; + xp_size_t idxa; if (__get_token(awk) == -1) return XP_NULL; @@ -1062,6 +1082,20 @@ static xp_awk_node_t* __parse_hashidx (xp_awk_t* awk, xp_char_t* name) PANIC (awk, XP_AWK_ENOMEM); } + /* search the parameter name list */ + idxa = xp_awk_tab_find (&awk->parse.params, name, 0); + if (idxa != (xp_size_t)-1) { + node->type = XP_AWK_NODE_ARGIDX; + node->next = XP_NULL; + //node->id.name = XP_NULL; + node->id.name = name; + node->id.idxa = idxa; + node->idx = idx; + + return (xp_awk_node_t*)node; + } + + // TODO: search variable list node->type = XP_AWK_NODE_VARIDX; node->next = XP_NULL; node->id.name = name; @@ -1770,23 +1804,6 @@ static xp_long_t __str_to_long (const xp_char_t* name) return n; } -static INLINE xp_size_t __add_func_name (xp_awk_t* awk, const xp_char_t* name) -{ - xp_assert (__find_func_name(awk,name) == (xp_size_t)-1); - - return xp_awk_tab_adddatum(&awk->parse.funcs, name); -} - -static INLINE int __remove_func_name (xp_awk_t* awk, xp_size_t index) -{ - return xp_awk_tab_remrange (&awk->parse.funcs, index, 1); -} - -static INLINE xp_size_t __find_func_name (xp_awk_t* awk, const xp_char_t* name) -{ - return xp_awk_tab_find(&awk->parse.funcs, name, 0); -} - static INLINE xp_size_t __find_func_arg (xp_awk_t* awk, const xp_char_t* name) { /* diff --git a/ase/awk/tree.c b/ase/awk/tree.c index ad168576..6fa46417 100644 --- a/ase/awk/tree.c +++ b/ase/awk/tree.c @@ -1,5 +1,5 @@ /* - * $Id: tree.c,v 1.13 2006-01-28 06:38:01 bacon Exp $ + * $Id: tree.c,v 1.14 2006-01-31 16:57:45 bacon Exp $ */ #include @@ -65,6 +65,18 @@ static int __print_expr_node (xp_awk_node_t* node) xp_printf (XP_TEXT("%s"), ((xp_awk_node_term_t*)node)->value); break; + case XP_AWK_NODE_ARG: + xp_printf (XP_TEXT("__arg%u"), + (unsigned int)((xp_awk_node_var_t*)node)->id.idxa); + break; + + case XP_AWK_NODE_ARGIDX: + xp_printf (XP_TEXT("__arg%u["), + (unsigned int)((xp_awk_node_idx_t*)node)->id.idxa); + __print_expr_node (((xp_awk_node_idx_t*)node)->idx); + xp_printf (XP_TEXT("]")); + break; + case XP_AWK_NODE_VAR: xp_printf (XP_TEXT("%s"), ((xp_awk_node_var_t*)node)->id.name); break; @@ -360,14 +372,29 @@ void xp_awk_clrpt (xp_awk_node_t* tree) xp_free (p); break; + case XP_AWK_NODE_ARG: + if (((xp_awk_node_var_t*)p)->id.name != XP_NULL) + xp_free (((xp_awk_node_var_t*)p)->id.name); + xp_free (p); + break; + + case XP_AWK_NODE_ARGIDX: + xp_awk_clrpt (((xp_awk_node_idx_t*)p)->idx); + if (((xp_awk_node_var_t*)p)->id.name != XP_NULL) + xp_free (((xp_awk_node_var_t*)p)->id.name); + xp_free (p); + break; + case XP_AWK_NODE_VAR: - xp_free (((xp_awk_node_var_t*)p)->id.name); + if (((xp_awk_node_var_t*)p)->id.name != XP_NULL) + xp_free (((xp_awk_node_var_t*)p)->id.name); xp_free (p); break; case XP_AWK_NODE_VARIDX: xp_awk_clrpt (((xp_awk_node_idx_t*)p)->idx); - xp_free (((xp_awk_node_idx_t*)p)->id.name); + if (((xp_awk_node_var_t*)p)->id.name != XP_NULL) + xp_free (((xp_awk_node_var_t*)p)->id.name); xp_free (p); break; diff --git a/ase/test/awk/awk.c b/ase/test/awk/awk.c index 7b77d880..49552bf9 100644 --- a/ase/test/awk/awk.c +++ b/ase/test/awk/awk.c @@ -79,8 +79,10 @@ int xp_main (int argc, xp_char_t* argv[]) } if (xp_awk_parse(&awk) == -1) { + xp_printf ( + XP_TEXT("error: cannot parse program - [%d] %s\n"), + xp_awk_geterrnum(&awk), xp_awk_geterrstr(&awk)); xp_awk_close (&awk); - xp_printf (XP_TEXT("error: cannot parse program\n")); return -1; }