From: Michael Wallner Date: Wed, 14 Oct 2015 18:47:17 +0000 (+0200) Subject: flush X-Git-Url: https://git.m6w6.name/?a=commitdiff_plain;h=f1a387482a9270a34ae684109ad8be7c104148d6;p=m6w6%2Fext-psi flush --- diff --git a/.gitignore b/.gitignore index 8ec9003..70680cf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,43 @@ *.dSYM /idl/main -/idl/parser.c -/idl/lemon.c -/idl/lempar.c -/idl/lemon -/idl/parser_proc.out -/idl/parser_proc.c +/lemon.c +/lempar.c +/lemon +/src/parser.c +/src/parser_proc.out +/src/parser_proc.c +.deps +*.lo +*.la +.libs +acinclude.m4 +aclocal.m4 +autom4te.cache +build +config.guess +config.h +config.h.in +config.log +config.nice +config.status +config.sub +configure +configure.in +include +install-sh +libtool +ltmain.sh +Makefile +Makefile.fragments +Makefile.global +Makefile.objects +missing +mkinstalldirs +modules +run-tests.php +tests/*/*.diff +tests/*/*.out +tests/*/*.php +tests/*/*.exp +tests/*/*.log +tests/*/*.sh diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..67bbd91 --- /dev/null +++ b/AUTHORS @@ -0,0 +1 @@ +Michael Wallner diff --git a/BUGS b/BUGS new file mode 100644 index 0000000..ebbf227 --- /dev/null +++ b/BUGS @@ -0,0 +1 @@ +Yay, no known and unresolved issues yet! diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..968bd44 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,39 @@ +# Contributor Code of Conduct + +As contributors and maintainers of this project, and in the interest of +fostering an open and welcoming community, we pledge to respect all people who +contribute through reporting issues, posting feature requests, updating +documentation, submitting pull requests or patches, and other activities. + +We are committed to making participation in this project a harassment-free +experience for everyone, regardless of level of experience, gender, gender +identity and expression, sexual orientation, disability, personal appearance, +body size, race, ethnicity, age, religion, or nationality. + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery +* Personal attacks +* Trolling or insulting/derogatory comments +* Public or private harassment +* Publishing other's private information, such as physical or electronic + addresses, without explicit permission +* Other unethical or unprofessional conduct. + +Project maintainers have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct. By adopting this Code of Conduct, project +maintainers commit themselves to fairly and consistently applying these +principles to every aspect of managing this project. Project maintainers who do +not follow or enforce the Code of Conduct may be permanently removed from the +project team. + +This code of conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by opening an issue or contacting one or more of the project maintainers. + +This Code of Conduct is adapted from the +[Contributor Covenant](http://contributor-covenant.org), version 1.2.0, +available at http://contributor-covenant.org/version/1/2/0/. diff --git a/CREDITS b/CREDITS new file mode 100644 index 0000000..7c8d2da --- /dev/null +++ b/CREDITS @@ -0,0 +1,2 @@ +psi +Michael Wallner diff --git a/EXPERIMENTAL b/EXPERIMENTAL new file mode 100644 index 0000000..e69de29 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f52c89a --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2015, Michael Wallner . +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Makefile.frag b/Makefile.frag new file mode 100644 index 0000000..fbf6c9c --- /dev/null +++ b/Makefile.frag @@ -0,0 +1,30 @@ +# provide headers in builddir, so they do not end up in /usr/include/ext/psi/src + +PHP_PSI_HEADERS := $(addprefix $(PHP_PSI_BUILDDIR)/,$(PHP_PSI_HEADERS)) + +$(PHP_PSI_BUILDDIR)/%.h: $(PHP_PSI_SRCDIR)/src/%.h + @cat >$@ <$< + +all: psi-build-headers +clean: psi-clean-headers + +.PHONY: psi-build-headers +psi-build-headers: $(PHP_PSI_HEADERS) + +.PHONY: psi-clean-headers +psi-clean-headers: + -rm -f $(PHP_PSI_HEADERS) + +lempar.c: + curl -sSo $@ "http://www.sqlite.org/src/raw/tool/lempar.c?name=3617143ddb9b176c3605defe6a9c798793280120" + +lemon.c: + curl -sSo $@ "http://www.sqlite.org/src/raw/tool/lemon.c?name=039f813b520b9395740c52f9cbf36c90b5d8df03" + +./lemon: lemon.c | lempar.c + +$(PHP_PSI_BUILDDIR)/src/parser_proc.c: $(PHP_PSI_SRCDIR)/src/parser_proc.y $(LEMON) + $(LEMON) -c $< + +$(PHP_PSI_BUILDDIR)/src/parser.c: $(PHP_PSI_SRCDIR)/src/parser.re + $(RE2C) -o $@ $< diff --git a/README.md b/README.md new file mode 100644 index 0000000..46956de --- /dev/null +++ b/README.md @@ -0,0 +1,48 @@ +# psi + +[![Build Status](https://travis-ci.org/m6w6/psi.svg?branch=master)](https://travis-ci.org/m6w6/psi) + +... + +## Documentation + +See the [online markdown reference](https://mdref.m6w6.name/psi). + +Known issues are listed in [BUGS](./BUGS) and future ideas can be found in [TODO](./TODO). + +## Installing + +### PECL + + pecl install psi + +### PHARext + +Watch out for [PECL replicates](https://replicator.pharext.org?psi) +and pharext packages attached to [releases](./releases). + +### Checkout + + git clone github.com:m6w6/psi + cd psi + /path/to/phpize + ./configure --with-php-config=/path/to/php-config + make + sudo make install + +## ChangeLog + +A comprehensive list of changes can be obtained from the +[PECL website](https://pecl.php.net/package-changelog.php?package=psi). + +## License + +psi is licensed under the 2-Clause-BSD license, which can be found in +the accompanying [LICENSE](./LICENSE) file. + +## Contributing + +All forms of contribution are welcome! Please see the bundled +[CONTRIBUTING](./CONTRIBUTING.md) note for the general principles followed. + +The list of past and current contributors is maintained in [THANKS](./THANKS). diff --git a/THANKS b/THANKS new file mode 100644 index 0000000..d0eae43 --- /dev/null +++ b/THANKS @@ -0,0 +1 @@ +Thanks go to the following people, who have contributed to this project: diff --git a/TODO b/TODO index 09344d0..22c7d40 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,4 @@ * move numbers to the lexer * avoid allocs inside structures by reallocating the whole structure * let the various list types be hashtables where appropriate +* check out jit-dynamic diff --git a/config.m4 b/config.m4 new file mode 100644 index 0000000..999f61c --- /dev/null +++ b/config.m4 @@ -0,0 +1,43 @@ +PHP_ARG_ENABLE(psi, whether to enable psi support, +[ --with-psi[[=path to libjit]] + Enable PHP System Interface support]) + +if test "$PHP_PSI" != "no"; then + AC_ARG_VAR(LEMON, The lemon parser generator of the SQLite project) + AC_PATH_PROG(LEMON, lemon, ./lemon) + PHP_SUBST(LEMON) + + AC_CACHE_CHECK(for libjit install root, PSI_cv_LIBJIT_DIR, [ + for PSI_cv_LIBJIT_DIR in {/usr{,/local},/opt}{,libjit} + do + if test -e $PSI_cv_LIBJIT_DIR/include/jit/jit.h + then + break + fi + PSI_cv_LIBJIT_DIR= + done]) + if test -z "$PSI_cv_LIBJIT_DIR" + then + AC_MSG_ERROR([Could not find libjit, please provide the base install path]) + fi + + PHP_PSI_SRCDIR=PHP_EXT_SRCDIR(psi) + PHP_PSI_BUILDDIR=PHP_EXT_BUILDDIR(psi) + + PHP_ADD_INCLUDE($PHP_PSI_SRCDIR/src) + PHP_ADD_BUILD_DIR($PHP_PSI_BUILDDIR/src) + + PHP_PSI_HEADERS=`(cd $PHP_PSI_SRCDIR/src && echo *.h)` + PHP_PSI_SOURCES=`(cd $PHP_PSI_SRCDIR && echo src/*.c)` + + PHP_NEW_EXTENSION(psi, $PHP_PSI_SOURCES, $ext_shared) + PHP_INSTALL_HEADERS(ext/psi, php_psi.h $PHP_PSI_HEADERS) + + PHP_SUBST(PHP_PSI_HEADERS) + PHP_SUBST(PHP_PSI_SOURCES) + + PHP_SUBST(PHP_PSI_SRCDIR) + PHP_SUBST(PHP_PSI_BUILDDIR) + + PHP_ADD_MAKEFILE_FRAGMENT +fi diff --git a/idl/compiler.c b/idl/compiler.c deleted file mode 100644 index 02f3867..0000000 --- a/idl/compiler.c +++ /dev/null @@ -1,14 +0,0 @@ -#include - -#include "compiler.h" - -PSI_Compiler *PSI_CompilerInit(PSI_Compiler *C, PSI_Validator *V) -{ - if (!C) { - C = malloc(sizeof(*C)); - } - memset(C, 0, sizeof(*C)); - - PSI_DataExchange((PSI_Data *) C, (PSI_Data *) V); - return C; -} diff --git a/idl/compiler.h b/idl/compiler.h deleted file mode 100644 index c5e447f..0000000 --- a/idl/compiler.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef _PSI_COMPILER_H -#define _PSI_COMPILER_H - -#include "validator.h" - -typedef struct PSI_Compiler { - decl_typedefs *defs; - decls *decls; - impls *impls; - char *lib; - char *fn; -} PSI_Compiler; - -PSI_Compiler *PSI_CompilerInit(PSI_Compiler *C, PSI_Validator *V); - -#endif diff --git a/idl/parser.h b/idl/parser.h deleted file mode 100644 index dcb464b..0000000 --- a/idl/parser.h +++ /dev/null @@ -1,672 +0,0 @@ -#ifndef _PSI_PARSER_H -#define _PSI_PARSER_H - -#include -#include -#include - -#include "parser_proc.h" - -#define BSIZE 256 - -typedef int token_t; - -typedef struct PSI_Token { - token_t type; - unsigned line; - size_t size; - char text[1]; -} PSI_Token; - -typedef struct decl_type { - char *name; - token_t type; - struct decl_type *real; -} decl_type; - -static inline decl_type *init_decl_type(token_t type, char *name) { - decl_type *t = malloc(sizeof(*t)); - t->type = type; - t->name = strdup(name); - return t; -} - -static inline void free_decl_type(decl_type *type) { - free(type->name); - free(type); -} - -typedef struct decl_typedef { - char *alias; - decl_type *type; -} decl_typedef; - -static inline decl_typedef *init_decl_typedef(char *name, decl_type *type) { - decl_typedef *t = malloc(sizeof(*t)); - t->alias = strdup(name); - t->type = type; - return t; -} - -static inline void free_decl_typedef(decl_typedef *t) { - free(t->alias); - free_decl_type(t->type); - free(t); -} - -typedef struct decl_typedefs { - size_t count; - decl_typedef **list; -} decl_typedefs; - -static decl_typedefs *add_decl_typedef(decl_typedefs *defs, decl_typedef *def) { - if (!defs) { - defs = calloc(1, sizeof(*defs)); - } - defs->list = realloc(defs->list, ++defs->count * sizeof(*defs->list)); - defs->list[defs->count-1] = def; - return defs; -} - -static void free_decl_typedefs(decl_typedefs *defs) { - size_t i; - - for (i = 0; i < defs->count; ++i) { - free_decl_typedef(defs->list[i]); - } - free(defs->list); - free(defs); -} - -typedef struct decl_var { - char *name; - unsigned pointer_level; -} decl_var; - -static inline decl_var *init_decl_var(char *name, unsigned pl) { - decl_var *v = malloc(sizeof(*v)); - v->name = (char *) strdup((const char *) name); - v->pointer_level = pl; - return v; -} - -static inline void free_decl_var(decl_var *var) { - free(var->name); - free(var); -} - -typedef struct decl_arg { - decl_type *type; - decl_var *var; -} decl_arg; - -static inline decl_arg *init_decl_arg(decl_type *type, decl_var *var) { - decl_arg *arg = malloc(sizeof(*arg)); - arg->type = type; - arg->var = var; - return arg; -} - -static inline void free_decl_arg(decl_arg *arg) { - free_decl_type(arg->type); - free_decl_var(arg->var); - free(arg); -} - -typedef struct decl_vars { - decl_var **vars; - size_t count; -} decl_vars; - -static inline decl_vars *init_decl_vars(decl_var *var) { - decl_vars *vars = malloc(sizeof(*vars)); - vars->count = 1; - vars->vars = malloc(sizeof(*vars->vars)); - vars->vars[0] = var; - return vars; -} - -static inline decl_vars *add_decl_var(decl_vars *vars, decl_var *var) { - vars->vars = realloc(vars->vars, ++vars->count * sizeof(*vars->vars)); - vars->vars[vars->count-1] = var; - return vars; -} - -static inline void free_decl_vars(decl_vars *vars) { - size_t i; - - for (i = 0; i < vars->count; ++i) { - free_decl_var(vars->vars[i]); - } - free(vars->vars); - free(vars); -} - -typedef struct decl_args { - decl_arg **args; - size_t count; -} decl_args; - -static inline decl_args *init_decl_args(decl_arg *arg) { - decl_args *args = malloc(sizeof(*args)); - args->count = 1; - args->args = malloc(sizeof(*args->args)); - args->args[0] = arg; - return args; -} - -static inline decl_args *add_decl_arg(decl_args *args, decl_arg *arg) { - args->args = realloc(args->args, ++args->count * sizeof(*args->args)); - args->args[args->count-1] = arg; - return args; -} - -static inline void free_decl_args(decl_args *args) { - size_t i; - - for (i = 0; i < args->count; ++i) { - free_decl_arg(args->args[i]); - } - free(args->args); - free(args); -} - -typedef struct decl_abi { - char *convention; -} decl_abi; - -static inline decl_abi *init_decl_abi(char *convention) { - decl_abi *abi = malloc(sizeof(*abi)); - abi->convention = strdup(convention); - return abi; -} - -static inline void free_decl_abi(decl_abi *abi) { - free(abi->convention); - free(abi); -} - -typedef struct decl { - decl_abi *abi; - decl_arg *func; - decl_args *args; - void *dlptr; -} decl; - -static inline decl* init_decl(decl_abi *abi, decl_arg *func, decl_args *args) { - decl *d = malloc(sizeof(*d)); - d->abi = abi; - d->func = func; - d->args = args; - return d; -} - -static inline void free_decl(decl *d) { - free_decl_abi(d->abi); - free_decl_arg(d->func); - free_decl_args(d->args); - free(d); -} - -typedef struct decls { - size_t count; - decl **list; -} decls; - -static inline decls *add_decl(decls *decls, decl *decl) { - if (!decls) { - decls = calloc(1, sizeof(*decls)); - } - decls->list = realloc(decls->list, ++decls->count * sizeof(*decls->list)); - decls->list[decls->count-1] = decl; - return decls; -} - -static inline void free_decls(decls *decls) { - size_t i; - - for (i = 0; i < decls->count; ++i) { - free_decl(decls->list[i]); - } - free(decls->list); - free(decls); -} - -typedef struct impl_type { - char *name; - token_t type; -} impl_type; - -static inline impl_type *init_impl_type(token_t type, char *name) { - impl_type *t = malloc(sizeof(*t)); - - t->type = type; - t->name = (char *) strdup((const char *) name); - return t; -} - -static inline void free_impl_type(impl_type *type) { - free(type->name); - free(type); -} - -typedef struct impl_var { - char *name; - unsigned reference:1; -} impl_var; - -static inline impl_var *init_impl_var(char *name, int is_reference) { - impl_var *var = malloc(sizeof(*var)); - var->name = (char *) strdup((const char *) name); - var->reference = is_reference; - return var; -} - -static inline void free_impl_var(impl_var *var) { - free(var->name); - free(var); -} - -typedef struct impl_def_val { - token_t type; - union { - int64_t digits; - double decimals; - } v; - unsigned is_null:1; -} impl_def_val; - -static inline impl_def_val *init_impl_def_val() { - impl_def_val *def = malloc(sizeof(*def)); - def->type = 0; - def->is_null = 1; - return def; -} - -static inline void free_impl_def_val(impl_def_val *def) { - free(def); -} - -typedef struct impl_arg { - impl_type *type; - impl_var *var; - impl_def_val *def; -} impl_arg; - -static inline impl_arg *init_impl_arg(impl_type *type, impl_var *var, impl_def_val *def) { - impl_arg *arg = malloc(sizeof(*arg)); - arg->type = type; - arg->var = var; - arg->def = def; - return arg; -} - -static inline void free_impl_arg(impl_arg *arg) { - free_impl_type(arg->type); - free_impl_var(arg->var); - if (arg->def) { - free_impl_def_val(arg->def); - } - free(arg); -} - -typedef struct impl_args { - impl_arg **args; - size_t count; -} impl_args; - -static inline impl_args *init_impl_args(impl_arg *arg) { - impl_args *args = malloc(sizeof(*args)); - args->args = malloc(sizeof(*args->args)); - if (arg) { - args->count = 1; - args->args[0] = arg; - } else { - args->count = 0; - args->args = NULL; - } - return args; -} - -static inline impl_args *add_impl_arg(impl_args *args, impl_arg *arg) { - args->args = realloc(args->args, ++args->count * sizeof(*args->args)); - args->args[args->count-1] = arg; - return args; -} - -static inline void free_impl_args(impl_args *args) { - size_t i; - - for (i = 0; i < args->count; ++i) { - free_impl_arg(args->args[i]); - } - free(args->args); - free(args); -} - -typedef struct impl_func { - char *name; - impl_args *args; - impl_type *return_type; -} impl_func; - -static inline impl_func *init_impl_func(char *name, impl_args *args, impl_type *type) { - impl_func *func = malloc(sizeof(*func)); - func->name = strdup(name); - func->args = args ? args : init_impl_args(NULL); - func->return_type = type; - return func; -} - -static inline void free_impl_func(impl_func *f) { - free_impl_type(f->return_type); - free_impl_args(f->args); - free(f->name); - free(f); -} - -typedef struct let_func { - token_t type; - char *name; -} let_func; - -static inline let_func *init_let_func(token_t type, char *name) { - let_func *func = malloc(sizeof(*func)); - func->type = type; - func->name = (char *) strdup((const char *) name); - return func; -} - -static inline void free_let_func(let_func *func) { - free(func->name); - free(func); -} - -typedef struct let_value { - let_func *func; - impl_var *var; - unsigned null_pointer_ref:1; -} let_value; - -static inline let_value *init_let_value(let_func *func, impl_var *var, int null_pointer_ref) { - let_value *val = malloc(sizeof(*val)); - val->null_pointer_ref = null_pointer_ref; - val->func = func; - val->var = var; - return val; -} - -static inline void free_let_value(let_value *val) { - if (val->func) { - free_let_func(val->func); - } - if (val->var) { - free_impl_var(val->var); - } - free(val); -} - -typedef struct let_stmt { - decl_var *var; - let_value *val; -} let_stmt; - -static inline let_stmt *init_let_stmt(decl_var *var, let_value *val) { - let_stmt *let = malloc(sizeof(*let)); - let->var = var; - let->val = val; - return let; -} - -static inline void free_let_stmt(let_stmt *stmt) { - free_decl_var(stmt->var); - free_let_value(stmt->val); - free(stmt); -} - -typedef struct set_func { - token_t type; - char *name; -} set_func; - -static inline set_func *init_set_func(token_t type, char *name) { - set_func *func = malloc(sizeof(*func)); - func->type = type; - func->name = (char *) strdup((const char *) name); - return func; -} - -static inline void free_set_func(set_func *func) { - free(func->name); - free(func); -} - -typedef struct set_value { - set_func *func; - decl_vars *vars; -} set_value; - -static inline set_value *init_set_value(set_func *func, decl_vars *vars) { - set_value *val = malloc(sizeof(*val)); - val->func = func; - val->vars = vars; - return val; -} - -static inline void free_set_value(set_value *val) { - free_set_func(val->func); - free_decl_vars(val->vars); - free(val); -} - -typedef struct set_stmt { - impl_var *var; - set_value *val; -} set_stmt; - -static inline set_stmt *init_set_stmt(impl_var *var, set_value *val) { - set_stmt *set = malloc(sizeof(*set)); - set->var = var; - set->val = val; - return set; -} - -static inline void free_set_stmt(set_stmt *set) { - free_impl_var(set->var); - free_set_value(set->val); - free(set); -} - -typedef struct ret_stmt { - set_func *func; - decl_var *decl; -} ret_stmt; - -static inline ret_stmt *init_ret_stmt(set_func *func, decl_var *decl) { - ret_stmt *ret = malloc(sizeof(*ret)); - ret->func = func; - ret->decl = decl; - return ret; -} - -static inline void free_ret_stmt(ret_stmt *ret) { - free_set_func(ret->func); - free_decl_var(ret->decl); - free(ret); -} - -typedef struct impl_stmt { - token_t type; - union { - let_stmt *let; - set_stmt *set; - ret_stmt *ret; - void *ptr; - } s; -} impl_stmt; - -static inline impl_stmt *init_impl_stmt(token_t type, void *ptr) { - impl_stmt *stmt = malloc(sizeof(*stmt)); - stmt->type = type; - stmt->s.ptr = ptr; - return stmt; -} - -static inline void free_impl_stmt(impl_stmt *stmt) { - switch (stmt->type) { - case PSI_T_LET: - free_let_stmt(stmt->s.let); - break; - case PSI_T_SET: - free_set_stmt(stmt->s.set); - break; - case PSI_T_RET: - free_ret_stmt(stmt->s.ret); - break; - } - free(stmt); -} - -typedef struct impl_stmts { - impl_stmt **stmts; - size_t count; -} impl_stmts; - -static inline impl_stmts *init_impl_stmts(impl_stmt *stmt) { - impl_stmts *stmts = malloc(sizeof(*stmts)); - stmts->count = 1; - stmts->stmts = malloc(sizeof(*stmts->stmts)); - stmts->stmts[0] = stmt; - return stmts; -} - -static inline impl_stmts *add_impl_stmt(impl_stmts *stmts, impl_stmt *stmt) { - stmts->stmts = realloc(stmts->stmts, ++stmts->count * sizeof(*stmts->stmts)); - stmts->stmts[stmts->count-1] = stmt; - return stmts; -} - -static inline void free_impl_stmts(impl_stmts *stmts) { - size_t i; - - for (i = 0; i < stmts->count; ++i) { - free_impl_stmt(stmts->stmts[i]); - } - free(stmts->stmts); - free(stmts); -} - -typedef struct impl { - impl_func *func; - impl_stmts *stmts; -} impl; - -static inline impl *init_impl(impl_func *func, impl_stmts *stmts) { - impl *i = malloc(sizeof(*i)); - i->func = func; - i->stmts = stmts; - return i; -} - -static inline void free_impl(impl *impl) { - free_impl_func(impl->func); - free_impl_stmts(impl->stmts); - free(impl); -} - -typedef struct impls { - size_t count; - impl **list; -} impls; - -static impls *add_impl(impls *impls, impl *impl) { - if (!impls) { - impls = calloc(1, sizeof(*impls)); - } - impls->list = realloc(impls->list, ++impls->count * sizeof(*impls->list)); - impls->list[impls->count-1] = impl; - return impls; -} - -static void free_impls(impls *impls) { - size_t i; - - for (i = 0; i < impls->count; ++i) { - free_impl(impls->list[i]); - } - free(impls->list); - free(impls); -} - -typedef struct PSI_Data { - decl_typedefs *defs; - decls *decls; - impls *impls; - char *lib; - char *fn; -} PSI_Data; - -static inline void PSI_DataExchange(PSI_Data *dest, PSI_Data *src) { - memcpy(dest, src, sizeof(*dest)); - memset(src, 0, sizeof(*src)); -} - -static inline void PSI_DataDtor(PSI_Data *data) { - if (data->defs) { - free_decl_typedefs(data->defs); - } - if (data->decls) { - free_decls(data->decls); - } - if (data->impls) { - free_impls(data->impls); - } - if (data->lib) { - free(data->lib); - } - if (data->fn) { - free(data->fn); - } -} - -typedef struct PSI_Parser { - decl_typedefs *defs; - decls *decls; - impls *impls; - char *lib; - char *fn; - FILE *fp; - void *proc; - size_t line; - token_t num; - char *cur, *tok, *lim, *eof, *ctx, *mrk, buf[BSIZE]; -} PSI_Parser; - -static inline PSI_Token *PSI_TokenAlloc(PSI_Parser *P) { - PSI_Token *T; - size_t token_len; - - if (P->cur <= P->tok) { - return NULL; - } - - token_len = P->cur - P->tok; - - T = malloc(sizeof(*T) + token_len); - T->type = P->num; - T->line = P->line; - T->size = token_len; - T->text[token_len] = 0; - memcpy(T->text, P->tok, token_len); - - return T; -} - -PSI_Parser *PSI_ParserInit(PSI_Parser *P, const char *filename); -size_t PSI_ParserFill(PSI_Parser *P, size_t n); -token_t PSI_ParserScan(PSI_Parser *P); -void PSI_ParserParse(PSI_Parser *P, PSI_Token *T); -void PSI_ParserDtor(PSI_Parser *P); -void PSI_ParserFree(PSI_Parser **P); - -#endif diff --git a/idl/parser.re b/idl/parser.re deleted file mode 100644 index 5a06023..0000000 --- a/idl/parser.re +++ /dev/null @@ -1,224 +0,0 @@ -#include -#include - -#include "parser.h" -#include "parser_proc.h" - -void *PSI_ParserProcAlloc(void*(unsigned long)); -void PSI_ParserProcFree(void*, void(*)(void*)); -void PSI_ParserProc(void *, token_t, PSI_Token *, PSI_Parser *); - -PSI_Parser *PSI_ParserInit(PSI_Parser *P, const char *filename) -{ - FILE *fp; - - if (!P) { - P = malloc(sizeof(*P)); - } - memset(P, 0, sizeof(*P)); - - fp = fopen(filename, "r"); - - if (!fp) { - perror(filename); - return NULL; - } - - if (!P) { - P = malloc(sizeof(*P)); - } - memset(P, 0, sizeof(*P)); - - P->fp = fp; - P->fn = strdup(filename); - P->line = 1; - - P->proc = PSI_ParserProcAlloc(malloc); - - PSI_ParserFill(P, 0); - - return P; -} - -size_t PSI_ParserFill(PSI_Parser *P, size_t n) -{ - // printf("+ Fill: n=%zu\n", n); - if (!n) { - P->cur = P->tok = P->lim = P->mrk = P->buf; - P->eof = NULL; - } - - if (!P->eof) { - size_t consumed = P->tok - P->buf; - size_t reserved = P->lim - P->tok; - size_t available = BSIZE - reserved; - size_t didread; - - if (consumed) { - memmove(P->buf, P->tok, reserved); - P->tok -= consumed; - P->cur -= consumed; - P->lim -= consumed; - P->mrk -= consumed; - } - - didread = fread(P->lim, 1, available, P->fp); - P->lim += didread; - if (didread < available) { - P->eof = P->lim; - } - - // printf("+ Fill: consumed=%zu reserved=%zu available=%zu didread=%zu\n", - // consumed, reserved, available, didread); - } - // printf("+ Fill: avail=%zu\n", P->lim - P->cur); - return P->lim - P->cur; -} - -void PSI_ParserParse(PSI_Parser *P, PSI_Token *T) -{ - if (T) { - PSI_ParserProc(P->proc, T->type, T, P); - } else { - PSI_ParserProc(P->proc, 0, NULL, P); - } -} - -void PSI_ParserDtor(PSI_Parser *P) -{ - PSI_ParserProcFree(P->proc, free); - - if (P->fp) { - fclose(P->fp); - } - - PSI_DataDtor((PSI_Data *) P); - - memset(P, 0, sizeof(*P)); -} - -void PSI_ParserFree(PSI_Parser **P) -{ - if (*P) { - PSI_ParserDtor(*P); - free(*P); - *P = NULL; - } -} - -/*!max:re2c*/ -#define BSIZE 256 - -#if BSIZE < YYMAXFILL -# error BSIZE must be greater than YYMAXFILL -#endif - -#define RETURN(t) do { \ - P->num = t; \ - return t; \ -} while(1) - -token_t PSI_ParserScan(PSI_Parser *P) -{ - for (;;) { - P->tok = P->cur; - /*!re2c - re2c:indent:top = 2; - re2c:define:YYCTYPE = "unsigned char"; - re2c:define:YYCURSOR = P->cur; - re2c:define:YYLIMIT = P->lim; - re2c:define:YYMARKER = P->mrk; - re2c:define:YYFILL = "{ if (!PSI_ParserFill(P,@@)) RETURN(-1); }"; - re2c:yyfill:parameter = 0; - - B = [^a-zA-Z0-9_]; - W = [a-zA-Z0-9_]; - NAME = W+; - NSNAME = (NAME)? ("\\" NAME)+; - QUOTED_STRING = "\"" ([^\"])+ "\""; - NULL = 'NULL'; - MIXED = 'mixed'; - VOID = 'void'; - BOOL = 'bool'; - INT = 'int'; - FLOAT = 'float'; - DOUBLE = 'double'; - SINT8 = 'sint8'; - UINT8 = 'uint8'; - SINT16 = 'sint16'; - UINT16 = 'uint16'; - SINT32 = 'sint32'; - UINT32 = 'uint32'; - SINT64 = 'sint64'; - UINT64 = 'uint64'; - STRING = 'string'; - ARRAY = 'array'; - FUNCTION = 'function'; - TYPEDEF = 'typedef'; - LIB = 'lib'; - LET = 'let'; - SET = 'set'; - RET = 'ret'; - STRVAL = 'strval'; - INTVAL = 'intval'; - FLOATVAL = 'floatval'; - BOOLVAL = 'boolval'; - TO_STRING = 'to_string'; - TO_INT = 'to_int'; - TO_FLOAT = 'to_float'; - TO_BOOL = 'to_bool'; - - "#" .* "\n" { ++P->line; RETURN(PSI_T_COMMENT);} - "(" {RETURN(PSI_T_LPAREN);} - ")" {RETURN(PSI_T_RPAREN);} - ";" {RETURN(PSI_T_EOS);} - "," {RETURN(PSI_T_COMMA);} - ":" {RETURN(PSI_T_COLON);} - "{" {RETURN(PSI_T_LBRACE);} - "}" {RETURN(PSI_T_RBRACE);} - "." {RETURN(PSI_T_DOT);} - "=" {RETURN(PSI_T_EQUALS);} - "$" {RETURN(PSI_T_DOLLAR);} - "*" {RETURN(PSI_T_POINTER);} - "&" {RETURN(PSI_T_REFERENCE);} - [\r\n] { ++P->line; continue; } - [\t ]+ { continue; } - NULL {RETURN(PSI_T_NULL);} - MIXED {RETURN(PSI_T_MIXED);} - VOID {RETURN(PSI_T_VOID);} - BOOL {RETURN(PSI_T_BOOL);} - INT {RETURN(PSI_T_INT);} - FLOAT {RETURN(PSI_T_FLOAT);} - DOUBLE {RETURN(PSI_T_DOUBLE);} - SINT8 {RETURN(PSI_T_SINT8);} - UINT8 {RETURN(PSI_T_UINT8);} - SINT16 {RETURN(PSI_T_SINT16);} - UINT16 {RETURN(PSI_T_UINT16);} - SINT32 {RETURN(PSI_T_SINT32);} - UINT32 {RETURN(PSI_T_UINT32);} - SINT64 {RETURN(PSI_T_SINT64);} - UINT64 {RETURN(PSI_T_UINT64);} - STRING {RETURN(PSI_T_STRING);} - ARRAY {RETURN(PSI_T_ARRAY);} - FUNCTION {RETURN(PSI_T_FUNCTION);} - TYPEDEF {RETURN(PSI_T_TYPEDEF);} - LIB {RETURN(PSI_T_LIB);} - LET {RETURN(PSI_T_LET);} - SET {RETURN(PSI_T_SET);} - RET {RETURN(PSI_T_RET);} - STRVAL {RETURN(PSI_T_STRVAL);} - INTVAL {RETURN(PSI_T_INTVAL);} - FLOATVAL {RETURN(PSI_T_FLOATVAL);} - BOOLVAL {RETURN(PSI_T_BOOLVAL);} - TO_STRING {RETURN(PSI_T_TO_STRING);} - TO_INT {RETURN(PSI_T_TO_INT);} - TO_FLOAT {RETURN(PSI_T_TO_FLOAT);} - TO_BOOL {RETURN(PSI_T_TO_BOOL);} - [0-9] {RETURN(PSI_T_DIGIT);} - NAME {RETURN(PSI_T_NAME);} - NSNAME {RETURN(PSI_T_NSNAME);} - QUOTED_STRING {RETURN(PSI_T_QUOTED_STRING);} - */ - } - return -1; -} diff --git a/idl/parser_proc.h b/idl/parser_proc.h deleted file mode 100644 index 3be3c66..0000000 --- a/idl/parser_proc.h +++ /dev/null @@ -1,50 +0,0 @@ -#define PSI_T_COMMENT 1 -#define PSI_T_LIB 2 -#define PSI_T_QUOTED_STRING 3 -#define PSI_T_EOS 4 -#define PSI_T_TYPEDEF 5 -#define PSI_T_NAME 6 -#define PSI_T_LPAREN 7 -#define PSI_T_RPAREN 8 -#define PSI_T_COMMA 9 -#define PSI_T_VOID 10 -#define PSI_T_INT 11 -#define PSI_T_FLOAT 12 -#define PSI_T_DOUBLE 13 -#define PSI_T_SINT8 14 -#define PSI_T_UINT8 15 -#define PSI_T_SINT16 16 -#define PSI_T_UINT16 17 -#define PSI_T_SINT32 18 -#define PSI_T_UINT32 19 -#define PSI_T_SINT64 20 -#define PSI_T_UINT64 21 -#define PSI_T_LBRACE 22 -#define PSI_T_RBRACE 23 -#define PSI_T_FUNCTION 24 -#define PSI_T_NSNAME 25 -#define PSI_T_COLON 26 -#define PSI_T_NULL 27 -#define PSI_T_DOLLAR 28 -#define PSI_T_REFERENCE 29 -#define PSI_T_EQUALS 30 -#define PSI_T_LET 31 -#define PSI_T_STRVAL 32 -#define PSI_T_INTVAL 33 -#define PSI_T_FLOATVAL 34 -#define PSI_T_BOOLVAL 35 -#define PSI_T_SET 36 -#define PSI_T_TO_STRING 37 -#define PSI_T_TO_INT 38 -#define PSI_T_TO_FLOAT 39 -#define PSI_T_TO_BOOL 40 -#define PSI_T_RET 41 -#define PSI_T_MIXED 42 -#define PSI_T_BOOL 43 -#define PSI_T_STRING 44 -#define PSI_T_ARRAY 45 -#define PSI_T_DIGIT 46 -#define PSI_T_DOT 47 -#define PSI_T_PLUS 48 -#define PSI_T_MINUS 49 -#define PSI_T_POINTER 50 diff --git a/idl/parser_proc.y b/idl/parser_proc.y deleted file mode 100644 index 47de153..0000000 --- a/idl/parser_proc.y +++ /dev/null @@ -1,339 +0,0 @@ -%include { -#include -#include -#include -#include - -#include "parser.h" - - static void syntax_error(const char *fn, size_t ln, const char *msg, ...) { - fprintf(stderr, "WARNING: Syntax error on line %zu in '%s'%s", ln, fn, msg ? ": ": "\n"); - if (msg) { - va_list argv; - - va_start(argv, msg); - vfprintf(stderr, msg, argv); - va_end(argv); - } - } -} - -%name PSI_ParserProc -%token_prefix PSI_T_ -%token_type {PSI_Token *} -%token_destructor {free($$);} -%extra_argument {PSI_Parser *P} -/* TOKEN is defined inside syntax_error */ -%syntax_error { - syntax_error(P->fn, P->line, "Unexpected token '%s'.\n", TOKEN->text); -} -file ::= blocks. - -blocks ::= block. -blocks ::= blocks block. - -block ::= COMMENT. - -block ::= LIB(T) QUOTED_STRING(libname) EOS. { - if (P->lib) { - syntax_error(P->fn, T->line, "Extra 'lib %s' statement has no effect.\n", libname->text); - } else { - P->lib = strndup(libname->text + 1, libname->size - 2); - } - free(libname); - free(T); -} - -block ::= decl(decl). { - P->decls = add_decl(P->decls, decl); -} -block ::= impl(impl). { - P->impls = add_impl(P->impls, impl); -} -block ::= decl_typedef(def). { - P->defs = add_decl_typedef(P->defs, def); -} - -%type decl_typedef {decl_typedef*} -decl_typedef(def) ::= TYPEDEF NAME(ALIAS) decl_type(type) EOS. { - def = init_decl_typedef(ALIAS->text, type); - free(ALIAS); -} - -%type decl {decl*} -decl(decl) ::= decl_abi(abi) decl_arg(func) LPAREN decl_args(args) RPAREN EOS. { - decl = init_decl(abi, func, args); -} - -%type decl_abi {decl_abi*} -decl_abi(abi) ::= NAME(T). { - abi = init_decl_abi(T->text); -} - -%type decl_var {decl_var*} -decl_var(var) ::= NAME(T). { - var = init_decl_var(T->text, 0); - free(T); -} -decl_var(var) ::= pointers(p) NAME(T). { - var = init_decl_var(T->text, p); - free(T); -} - -%type decl_vars {decl_vars*} -decl_vars(vars) ::= decl_var(var). { - vars = init_decl_vars(var); -} -decl_vars(vars) ::= decl_vars(vars_) COMMA decl_var(var). { - vars = add_decl_var(vars_, var); -} - -%type decl_arg {decl_arg*} -decl_arg(arg) ::= decl_type(type) decl_var(var). { - arg = init_decl_arg(type, var); -} - -%type decl_args {decl_args*} -decl_args(args) ::= decl_arg(arg). { - args = init_decl_args(arg); -} -decl_args(args) ::= decl_args(args_) COMMA decl_arg(arg). { - args = add_decl_arg(args_, arg); -} - -%type decl_type {decl_type*} -decl_type(type_) ::= VOID(T). { - type_ = init_decl_type(T->type, T->text); - free(T); -} -decl_type(type_) ::= INT(T). { - type_ = init_decl_type(T->type, T->text); - free(T); -} -decl_type(type_) ::= FLOAT(T). { - type_ = init_decl_type(T->type, T->text); - free(T); -} -decl_type(type_) ::= DOUBLE(T). { - type_ = init_decl_type(T->type, T->text); - free(T); -} -decl_type(type_) ::= SINT8(T). { - type_ = init_decl_type(T->type, T->text); - free(T); -} -decl_type(type_) ::= UINT8(T). { - type_ = init_decl_type(T->type, T->text); - free(T); -} -decl_type(type_) ::= SINT16(T). { - type_ = init_decl_type(T->type, T->text); - free(T); -} -decl_type(type_) ::= UINT16(T). { - type_ = init_decl_type(T->type, T->text); - free(T); -} -decl_type(type_) ::= SINT32(T). { - type_ = init_decl_type(T->type, T->text); - free(T); -} -decl_type(type_) ::= UINT32(T). { - type_ = init_decl_type(T->type, T->text); - free(T); -} -decl_type(type_) ::= SINT64(T). { - type_ = init_decl_type(T->type, T->text); - free(T); -} -decl_type(type_) ::= UINT64(T). { - type_ = init_decl_type(T->type, T->text); - free(T); -} -decl_type(type_) ::= NAME(T). { - type_ = init_decl_type(T->type, T->text); - free(T); -} - -%type impl {impl*} -impl(impl) ::= impl_func(func) LBRACE impl_stmts(stmts) RBRACE. { - impl = init_impl(func, stmts); -} - -%type impl_func {impl_func*} -impl_func(func) ::= FUNCTION NSNAME(NAME) LPAREN impl_args(args) RPAREN COLON impl_type(type). { - func = init_impl_func(NAME->text, args, type); - free(NAME); -} -impl_func(func) ::= FUNCTION NSNAME(NAME) LPAREN RPAREN COLON impl_type(type). { - func = init_impl_func(NAME->text, NULL, type); - free(NAME); -} - -%type impl_def_val {impl_def_val*} -impl_def_val(def) ::= NULL. { - /* FIXME */ - def = init_impl_def_val(); -} -impl_def_val(def) ::= number. { - /* FIXME */ - def = init_impl_def_val(); -} - -%type impl_var {impl_var*} -impl_var(var) ::= DOLLAR NAME(T). { - var = init_impl_var(T->text, 0); - free(T); -} -impl_var(var) ::= REFERENCE DOLLAR NAME(T). { - var = init_impl_var(T->text, 1); - free(T); -} - -%type impl_arg {impl_arg*} -impl_arg(arg) ::= impl_type(type) impl_var(var). { - arg = init_impl_arg(type, var, NULL); -} -impl_arg(arg) ::= impl_type(type) impl_var(var) EQUALS impl_def_val(def). { - arg = init_impl_arg(type, var, def); -} - -%type impl_args {impl_args*} -impl_args(args) ::= impl_arg(arg). { - args = init_impl_args(arg); -} -impl_args(args) ::= impl_args(args_) COMMA impl_arg(arg). { - args = add_impl_arg(args_, arg); -} - -%type impl_stmts {impl_stmts*} -impl_stmts(stmts) ::= impl_stmt(stmt). { - stmts = init_impl_stmts(stmt); -} -impl_stmts(stmts) ::= impl_stmts(stmts_) impl_stmt(stmt). { - stmts = add_impl_stmt(stmts_, stmt); -} - -%type impl_stmt {impl_stmt*} -impl_stmt(stmt) ::= let_stmt(let). { - stmt = init_impl_stmt(PSI_T_LET, let); -} -impl_stmt(stmt) ::= set_stmt(set). { - stmt = init_impl_stmt(PSI_T_SET, set); -} -impl_stmt(stmt) ::= ret_stmt(ret). { - stmt = init_impl_stmt(PSI_T_RET, ret); -} - -%type let_stmt {let_stmt*} -let_stmt(let) ::= LET decl_var(var) EQUALS let_value(val) EOS. { - let = init_let_stmt(var, val); -} - -%type let_value {let_value*} -let_value(val) ::= let_func(func) LPAREN impl_var(var) RPAREN. { - val = init_let_value(func, var, 0); -} -let_value(val) ::= REFERENCE NULL. { - val = init_let_value(NULL, NULL, 1); -} -let_value(val) ::= NULL. { - val = init_let_value(NULL, NULL, 0); -} - -%type let_func {let_func*} -let_func(func) ::= STRVAL(T). { - func = init_let_func(T->type, T->text); - free(T); -} -let_func(func) ::= INTVAL(T). { - func = init_let_func(T->type, T->text); - free(T); -} -let_func(func) ::= FLOATVAL(T). { - func = init_let_func(T->type, T->text); - free(T); -} -let_func(func) ::= BOOLVAL(T). { - func = init_let_func(T->type, T->text); - free(T); -} - -%type set_stmt {set_stmt*} -set_stmt(set) ::= SET impl_var(var) EQUALS set_value(val) EOS. { - set = init_set_stmt(var, val); -} - -%type set_value {set_value*} -set_value(val) ::= set_func(func) LPAREN decl_vars(vars) RPAREN. { - val = init_set_value(func, vars); -} - -%type set_func {set_func*} -set_func(func) ::= TO_STRING(T). { - func = init_set_func(T->type, T->text); - free(T); -} -set_func(func) ::= TO_INT(T). { - func = init_set_func(T->type, T->text); - free(T); -} -set_func(func) ::= TO_FLOAT(T). { - func = init_set_func(T->type, T->text); - free(T); -} -set_func(func) ::= TO_BOOL(T). { - func = init_set_func(T->type, T->text); - free(T); -} - -%type ret_stmt {ret_stmt*} -ret_stmt(ret) ::= RET set_func(func) LPAREN decl_var(var) RPAREN EOS. { - ret = init_ret_stmt(func, var); -} - -%type impl_type {impl_type*} -impl_type(type_) ::= VOID(T). { - type_ = init_impl_type(T->type, T->text); - free(T); -} -impl_type(type_) ::= MIXED(T). { - type_ = init_impl_type(T->type, T->text); - free(T); -} -impl_type(type_) ::= BOOL(T). { - type_ = init_impl_type(T->type, T->text); - free(T); -} -impl_type(type_) ::= INT(T). { - type_ = init_impl_type(T->type, T->text); - free(T); -} -impl_type(type_) ::= FLOAT(T). { - type_ = init_impl_type(T->type, T->text); - free(T); -} -impl_type(type_) ::= STRING(T). { - type_ = init_impl_type(T->type, T->text); - free(T); -} -impl_type(type_) ::= ARRAY(T). { - type_ = init_impl_type(T->type, T->text); - free(T); -} - -digits ::= DIGIT. -digits ::= digits DIGIT. -decimals ::= digits DOT digits. -decimals ::= DOT digits. -decimals ::= digits DOT. -number ::= digits. -number ::= PLUS digits. -number ::= MINUS digits. -number ::= decimals. -number ::= MINUS decimals. -number ::= PLUS decimals. - -%type pointers {unsigned} -pointers(p) ::= POINTER. {++p;} -pointers(p) ::= pointers(P) POINTER. {p = ++P;} diff --git a/idl/validator.c b/idl/validator.c deleted file mode 100644 index 87951eb..0000000 --- a/idl/validator.c +++ /dev/null @@ -1,239 +0,0 @@ -#include -#include -#include -#include -#include - -#include "validator.h" - -PSI_Validator *PSI_ValidatorInit(PSI_Validator *V, PSI_Parser *P) -{ - if (!V) { - V = malloc(sizeof(*V)); - } - memset(V, 0, sizeof(*V)); - - PSI_DataExchange((PSI_Data *) V, (PSI_Data *) P); - - return V; -} - -void PSI_ValidatorDtor(PSI_Validator *V) -{ - PSI_DataDtor((PSI_Data *) V); - memset(V, 0, sizeof(*V)); -} - -void PSI_ValidatorFree(PSI_Validator **V) -{ - if (*V) { - PSI_ValidatorDtor(*V); - free(*V); - *V = NULL; - } -} - -static inline int validate_lib(PSI_Validator *V) { - char lib[MAXPATHLEN]; - const char *ptr = V->lib; - size_t len; - - if (!ptr) { - /* FIXME: assume stdlib */ - return 1; - fprintf(stderr, "No import library defined;" - " use 'lib \"\";' statement.\n"); - } else if (!strchr(ptr, '/')) { -#ifdef DARWIN - len = snprintf(lib, MAXPATHLEN, "lib%s.dylib", ptr); -#else - len = snprintf(lib, MAXPATHLEN, "lib%s.so", ptr); -#endif - if (MAXPATHLEN == len) { - fprintf(stderr, "Library name too long: '%s'\n", ptr); - } - lib[len] = 0; - ptr = lib; - } - if (!(V->dlopened = dlopen(ptr, RTLD_LAZY|RTLD_LOCAL))) { - perror(ptr); - return 0; - } - return 1; -} -static inline int locate_decl_type_alias(decl_typedefs *defs, decl_type *type) { - size_t i; - - if (type->real) { - return 1; - } - for (i = 0; i < defs->count; ++i) { - if (!strcmp(defs->list[i]->alias, type->name)) { - type->real = defs->list[i]->type; - return 1; - } - } - return 0; -} -static inline int validate_decl_type(PSI_Validator *V, decl_arg *arg, decl_type *type) { - if (type->type == PSI_T_NAME) { - size_t i; - - if (!V->defs || !locate_decl_type_alias(V->defs, type)) { - fprintf(stderr, "Cannot use '%s' as type for '%s';" - " Use 'typedef ;' statement.\n", - type->name, arg->var->name); - } - } - return 1; -} -static inline int validate_typedef(PSI_Validator *V, decl_typedef *def) { - /* FIXME: check def->alias */ - if (def->type->type == PSI_T_NAME) { - fprintf(stderr, "Type '%s' cannot be aliased to '%s'\n", - def->type->name, def->alias); - return 0; - } - return 1; -} -static inline int validate_typedefs(PSI_Validator *V) { - size_t i; - - for (i = 0; i < V->defs->count; ++i) { - if (!validate_typedef(V, V->defs->list[i])) { - return 0; - } - } - - return 1; -} -static inline int validate_decl_func(PSI_Validator *V, decl *decl, decl_arg *func) -{ - void *dlptr; - - if (!strcmp(func->var->name, "dlsym")) { - fprintf(stderr, "Cannot dlsym dlsym (sic!)\n"); - return 0; - } - - if (!validate_decl_type(V, func, func->type)) { - return 0; - } - - decl->dlptr = dlsym(V->dlopened ?: RTLD_DEFAULT, func->var->name); - if (!decl->dlptr) { - fprintf(stderr, "Failed to located symbol '%s': %s\n", - func->var->name, dlerror()); - } - return 1; -} -static inline int validate_decl_abi(PSI_Validator *V, decl_abi *abi) { - if (strcasecmp(abi->convention, "default")) { - fprintf(stderr, "Invalid calling convention: '%s'\n", abi->convention); - return 0; - } - /* FIXME */ - return 1; -} -static inline int validate_decl_arg(PSI_Validator *V, decl *decl, decl_arg *arg) { - if (!validate_decl_type(V, arg, arg->type)) { - return 0; - } - return 1; -} -static inline int validate_decl_args(PSI_Validator *V, decl *decl, decl_args *args) { - size_t i; - - for (i = 0; i < args->count; ++i) { - if (!validate_decl_arg(V, decl, args->args[i])) { - return 0; - } - } - return 1; -} -static inline int validate_decl(PSI_Validator *V, decl *decl) { - if (!validate_decl_abi(V, decl->abi)) { - return 0; - } - if (!validate_decl_func(V, decl, decl->func)) { - return 0; - } - if (decl->args && !validate_decl_args(V, decl, decl->args)) { - return 0; - } - return 1; -} -static inline int validate_decls(PSI_Validator *V) { - size_t i; - - for (i = 0; i < V->decls->count; ++i) { - if (!validate_decl(V, V->decls->list[i])) { - return 0; - } - } - return 1; -} - -static inline int validate_impl_type(PSI_Validator *V, impl *impl, impl_type *type) { - /* FIXME */ - return 1; -} -static inline int validate_impl_arg(PSI_Validator *V, impl *impl, impl_arg *arg) { - return 1; -} -static inline int validate_impl_args(PSI_Validator *V, impl *impl, impl_args *args) { - size_t i; - - for (i = 0; i < args->count; ++i) { - if (!validate_impl_arg(V, impl, args->args[i])) { - return 0; - } - } - return 1; -} -static inline int validate_impl_func(PSI_Validator *V, impl *impl, impl_func *func) { - /* FIXME: does name need any validation? */ - if (!validate_impl_type(V, impl, func->return_type)) { - return 0; - } - if (func->args && !validate_impl_args(V, impl, func->args)) { - return 0; - } - return 1; -} -static inline int validate_impl_stmts(PSI_Validator *V, impl *impl, impl_stmts *stmts) { - return 1; -} -static inline int validate_impl(PSI_Validator *V, impl *impl) { - if (!validate_impl_func(V, impl, impl->func)) { - return 0; - } - if (!validate_impl_stmts(V, impl, impl->stmts)) { - return 0; - } - return 1; -} -static inline int validate_impls(PSI_Validator *V) { - size_t i; - - for (i = 0; i < V->impls->count; ++i) { - if (!validate_impl(V, V->impls->list[i])) { - return 0; - } - } - return 1; -} - -int PSI_ValidatorValidate(PSI_Validator *V) -{ - if (V->defs && !validate_typedefs(V)) { - return 0; - } - if (V->decls && !validate_decls(V)) { - return 0; - } - if (V->impls && !validate_impls(V)) { - return 0; - } - return 1; -} diff --git a/idl/validator.h b/idl/validator.h deleted file mode 100644 index f96111c..0000000 --- a/idl/validator.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef _PSI_VALIDATOR_H -#define _PSI_VALIDATOR_H - -#include "parser.h" - -typedef struct PSI_Validator { - decl_typedefs *defs; - decls *decls; - impls *impls; - char *lib; - char *fn; - void *dlopened; -} PSI_Validator; - -PSI_Validator *PSI_ValidatorInit(PSI_Validator *V, PSI_Parser *P); -int PSI_ValidatorValidate(PSI_Validator *V); -void PSI_ValidatorFree(PSI_Validator **V); -void PSI_ValidatorDtor(PSI_Validator *V); - -#endif diff --git a/package.xml b/package.xml new file mode 100644 index 0000000..06f2bde --- /dev/null +++ b/package.xml @@ -0,0 +1,3 @@ + +Parse error: parse error in /Users/Mike/Sources/repo-template.git/presets/package.xml on line 2 + diff --git a/php_psi.h b/php_psi.h new file mode 100644 index 0000000..0828ebe --- /dev/null +++ b/php_psi.h @@ -0,0 +1,43 @@ + +#ifndef PHP_PSI_H +#define PHP_PSI_H + +extern zend_module_entry psi_module_entry; +#define phpext_psi_ptr &psi_module_entry + +#define PHP_PSI_VERSION "0.1.0" + +#ifdef PHP_WIN32 +# define PHP_PSI_API __declspec(dllexport) +#elif defined(__GNUC__) && __GNUC__ >= 4 +# define PHP_PSI_API __attribute__ ((visibility("default"))) +#else +# define PHP_PSI_API +#endif + +#ifdef ZTS +#include "TSRM.h" +#endif + +ZEND_BEGIN_MODULE_GLOBALS(psi) + char *directory; + void *context; +ZEND_END_MODULE_GLOBALS(psi); + +#define PSI_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(psi, v) + +#if defined(ZTS) && defined(COMPILE_DL_PSI) +ZEND_TSRMLS_CACHE_EXTERN(); +#endif + +#endif /* PHP_PSI_H */ + + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/src/compiler.c b/src/compiler.c new file mode 100644 index 0000000..e075a39 --- /dev/null +++ b/src/compiler.c @@ -0,0 +1,81 @@ +#include + +#include + +#include +#include + +#include "compiler.h" + +PSI_Compiler *PSI_CompilerInit(PSI_Compiler *C, PSI_Validator *V) +{ + if (!C) { + C = malloc(sizeof(*C)); + } + memset(C, 0, sizeof(*C)); + + PSI_DataExchange((PSI_Data *) C, (PSI_Data *) V); + return C; +} + +typedef struct PSI_ClosureData { + impl *impl; +} PSI_ClosureData; + +static inline size_t impl_num_min_args(impl *impl) { + size_t i, n = impl->func->args->count; + + for (i = 0; i < impl->func->args->count; ++i) { + if (impl->func->args->args[i]->def) { + --n; + } + } + return n; +} +void PSI_Closure(jit_type_t signature, void *result, void **args, void *user_data) +{ + zend_execute_data *execute_data = args[0]; + zval *return_value = args[1]; + PSI_ClosureData *data = user_data; + impl_arg *iarg; + + if (!data->impl->func->args->count) { + if (SUCCESS != zend_parse_parameters_none()) { + return; + } + } else + ZEND_PARSE_PARAMETERS_START(impl_num_min_args(data->impl), data->impl->func->args->count) + nextarg: + iarg = data->impl->func->args->args[_i]; + if (iarg->def) { + Z_PARAM_OPTIONAL; + } + if (PSI_T_BOOL == iarg->type->type) { + if (iarg->def) { + iarg->val.bval = iarg->def->type == PSI_T_TRUE ? 1 : 0; + } + Z_PARAM_BOOL(iarg->val.bval); + } else if (PSI_T_INT == iarg->type->type) { + if (iarg->def) { + iarg->val.lval = atol(iarg->def->text); + } + Z_PARAM_LONG(iarg->val.lval); + } else if (PSI_T_FLOAT == iarg->type->type) { + if (iarg->def) { + iarg->val.dval = strtod(iarg->def->text, NULL); + } + Z_PARAM_DOUBLE(iarg->val.dval); + } else if (PSI_T_STRING == iarg->type->type) { + if (iarg->def) { + /* FIXME */ + iarg->val.str.len = strlen(iarg->def->text) - 2; + iarg->val.str.val = &iarg->def->text[1]; + } + Z_PARAM_STRING(iarg->val.str.val, iarg->val.str.len); + } else { + error_code = ZPP_ERROR_FAILURE; + break; + } + goto nextarg; + ZEND_PARSE_PARAMETERS_END(); +} diff --git a/src/compiler.h b/src/compiler.h new file mode 100644 index 0000000..c5e447f --- /dev/null +++ b/src/compiler.h @@ -0,0 +1,16 @@ +#ifndef _PSI_COMPILER_H +#define _PSI_COMPILER_H + +#include "validator.h" + +typedef struct PSI_Compiler { + decl_typedefs *defs; + decls *decls; + impls *impls; + char *lib; + char *fn; +} PSI_Compiler; + +PSI_Compiler *PSI_CompilerInit(PSI_Compiler *C, PSI_Validator *V); + +#endif diff --git a/src/module.c b/src/module.c new file mode 100644 index 0000000..c45ddb0 --- /dev/null +++ b/src/module.c @@ -0,0 +1,107 @@ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "php.h" +#include "php_ini.h" +#include "ext/standard/info.h" +#include "php_psi.h" + +ZEND_DECLARE_MODULE_GLOBALS(psi); + +PHP_INI_BEGIN() + STD_PHP_INI_ENTRY("psi.directory", "psis", PHP_INI_ALL, OnUpdateString, directory, zend_psi_globals, psi_globals) +PHP_INI_END(); + +PHP_MINIT_FUNCTION(psi) +{ + jit_context_t ctx; + + REGISTER_INI_ENTRIES(); + + jit_init(); + + if (!(ctx = jit_context_create())) { + zend_error(E_WARNING, "Could not initialize libjit!"); + return FAILURE; + } + + PSI_G(context) = ctx; + + return SUCCESS; +} +PHP_MSHUTDOWN_FUNCTION(psi) +{ + jit_context_t *ctx = PSI_G(context); + + jit_context_destroy(ctx); + + UNREGISTER_INI_ENTRIES(); + + return SUCCESS; +} + +/* Remove if there's nothing to do at request start */ +/* {{{ PHP_RINIT_FUNCTION + */ +PHP_RINIT_FUNCTION(psi) +{ +#if defined(COMPILE_DL_PSI) && defined(ZTS) + ZEND_TSRMLS_CACHE_UPDATE(); +#endif + return SUCCESS; +} +/* }}} */ + +/* Remove if there's nothing to do at request end */ +/* {{{ PHP_RSHUTDOWN_FUNCTION + */ +PHP_RSHUTDOWN_FUNCTION(psi) +{ + return SUCCESS; +} +/* }}} */ + +PHP_MINFO_FUNCTION(psi) +{ + php_info_print_table_start(); + php_info_print_table_header(2, "psi support", "enabled"); + php_info_print_table_end(); + + DISPLAY_INI_ENTRIES(); +} +const zend_function_entry psi_functions[] = { + PHP_FE_END +}; + +zend_module_entry psi_module_entry = { + STANDARD_MODULE_HEADER, + "psi", + psi_functions, + PHP_MINIT(psi), + PHP_MSHUTDOWN(psi), + PHP_RINIT(psi), /* Replace with NULL if there's nothing to do at request start */ + PHP_RSHUTDOWN(psi), /* Replace with NULL if there's nothing to do at request end */ + PHP_MINFO(psi), + PHP_PSI_VERSION, + STANDARD_MODULE_PROPERTIES +}; + +#ifdef COMPILE_DL_PSI +#ifdef ZTS +ZEND_TSRMLS_CACHE_DEFINE(); +#endif +ZEND_GET_MODULE(psi) +#endif + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/src/parser.h b/src/parser.h new file mode 100644 index 0000000..d4909dd --- /dev/null +++ b/src/parser.h @@ -0,0 +1,717 @@ +#ifndef _PSI_PARSER_H +#define _PSI_PARSER_H + +#include +#include +#include +#include + +#include + +#include "parser_proc.h" + +#define BSIZE 256 + +typedef int token_t; + +typedef struct PSI_Token { + token_t type; + unsigned line; + size_t size; + char text[1]; +} PSI_Token; + +typedef struct decl_type { + char *name; + token_t type; + struct decl_type *real; +} decl_type; + +static inline decl_type *init_decl_type(token_t type, char *name) { + decl_type *t = malloc(sizeof(*t)); + t->type = type; + t->name = strdup(name); + return t; +} + +static inline void free_decl_type(decl_type *type) { + free(type->name); + free(type); +} + +typedef struct decl_typedef { + char *alias; + decl_type *type; +} decl_typedef; + +static inline decl_typedef *init_decl_typedef(char *name, decl_type *type) { + decl_typedef *t = malloc(sizeof(*t)); + t->alias = strdup(name); + t->type = type; + return t; +} + +static inline void free_decl_typedef(decl_typedef *t) { + free(t->alias); + free_decl_type(t->type); + free(t); +} + +typedef struct decl_typedefs { + size_t count; + decl_typedef **list; +} decl_typedefs; + +static decl_typedefs *add_decl_typedef(decl_typedefs *defs, decl_typedef *def) { + if (!defs) { + defs = calloc(1, sizeof(*defs)); + } + defs->list = realloc(defs->list, ++defs->count * sizeof(*defs->list)); + defs->list[defs->count-1] = def; + return defs; +} + +static void free_decl_typedefs(decl_typedefs *defs) { + size_t i; + + for (i = 0; i < defs->count; ++i) { + free_decl_typedef(defs->list[i]); + } + free(defs->list); + free(defs); +} + +typedef struct decl_var { + char *name; + unsigned pointer_level; +} decl_var; + +static inline decl_var *init_decl_var(char *name, unsigned pl) { + decl_var *v = malloc(sizeof(*v)); + v->name = (char *) strdup((const char *) name); + v->pointer_level = pl; + return v; +} + +static inline void free_decl_var(decl_var *var) { + free(var->name); + free(var); +} + +typedef struct decl_arg { + decl_type *type; + decl_var *var; +} decl_arg; + +static inline decl_arg *init_decl_arg(decl_type *type, decl_var *var) { + decl_arg *arg = malloc(sizeof(*arg)); + arg->type = type; + arg->var = var; + return arg; +} + +static inline void free_decl_arg(decl_arg *arg) { + free_decl_type(arg->type); + free_decl_var(arg->var); + free(arg); +} + +typedef struct decl_vars { + decl_var **vars; + size_t count; +} decl_vars; + +static inline decl_vars *init_decl_vars(decl_var *var) { + decl_vars *vars = malloc(sizeof(*vars)); + vars->count = 1; + vars->vars = malloc(sizeof(*vars->vars)); + vars->vars[0] = var; + return vars; +} + +static inline decl_vars *add_decl_var(decl_vars *vars, decl_var *var) { + vars->vars = realloc(vars->vars, ++vars->count * sizeof(*vars->vars)); + vars->vars[vars->count-1] = var; + return vars; +} + +static inline void free_decl_vars(decl_vars *vars) { + size_t i; + + for (i = 0; i < vars->count; ++i) { + free_decl_var(vars->vars[i]); + } + free(vars->vars); + free(vars); +} + +typedef struct decl_args { + decl_arg **args; + size_t count; +} decl_args; + +static inline decl_args *init_decl_args(decl_arg *arg) { + decl_args *args = malloc(sizeof(*args)); + args->count = 1; + args->args = malloc(sizeof(*args->args)); + args->args[0] = arg; + return args; +} + +static inline decl_args *add_decl_arg(decl_args *args, decl_arg *arg) { + args->args = realloc(args->args, ++args->count * sizeof(*args->args)); + args->args[args->count-1] = arg; + return args; +} + +static inline void free_decl_args(decl_args *args) { + size_t i; + + for (i = 0; i < args->count; ++i) { + free_decl_arg(args->args[i]); + } + free(args->args); + free(args); +} + +typedef struct decl_abi { + char *convention; +} decl_abi; + +static inline decl_abi *init_decl_abi(char *convention) { + decl_abi *abi = malloc(sizeof(*abi)); + abi->convention = strdup(convention); + return abi; +} + +static inline void free_decl_abi(decl_abi *abi) { + free(abi->convention); + free(abi); +} + +typedef struct decl { + decl_abi *abi; + decl_arg *func; + decl_args *args; + void *dlptr; +} decl; + +static inline decl* init_decl(decl_abi *abi, decl_arg *func, decl_args *args) { + decl *d = malloc(sizeof(*d)); + d->abi = abi; + d->func = func; + d->args = args; + return d; +} + +static inline void free_decl(decl *d) { + free_decl_abi(d->abi); + free_decl_arg(d->func); + free_decl_args(d->args); + free(d); +} + +typedef struct decls { + size_t count; + decl **list; +} decls; + +static inline decls *add_decl(decls *decls, decl *decl) { + if (!decls) { + decls = calloc(1, sizeof(*decls)); + } + decls->list = realloc(decls->list, ++decls->count * sizeof(*decls->list)); + decls->list[decls->count-1] = decl; + return decls; +} + +static inline void free_decls(decls *decls) { + size_t i; + + for (i = 0; i < decls->count; ++i) { + free_decl(decls->list[i]); + } + free(decls->list); + free(decls); +} + +typedef struct impl_type { + char *name; + token_t type; +} impl_type; + +static inline impl_type *init_impl_type(token_t type, char *name) { + impl_type *t = malloc(sizeof(*t)); + + t->type = type; + t->name = (char *) strdup((const char *) name); + return t; +} + +static inline void free_impl_type(impl_type *type) { + free(type->name); + free(type); +} + +typedef struct impl_var { + char *name; + unsigned reference:1; +} impl_var; + +static inline impl_var *init_impl_var(char *name, int is_reference) { + impl_var *var = malloc(sizeof(*var)); + var->name = (char *) strdup((const char *) name); + var->reference = is_reference; + return var; +} + +static inline void free_impl_var(impl_var *var) { + free(var->name); + free(var); +} + +typedef struct impl_def_val { + token_t type; + char *text; +} impl_def_val; + +static inline impl_def_val *init_impl_def_val(PSI_Token *T) { + impl_def_val *def = malloc(sizeof(*def)); + def->type = T->type; + def->text = strdup(T->text); + return def; +} + +static inline void free_impl_def_val(impl_def_val *def) { + free(def->text); + free(def); +} + +typedef struct impl_arg { + impl_type *type; + impl_var *var; + impl_def_val *def; + union { + unsigned char bval; + zend_long lval; + double dval; + struct { + char *val; + size_t len; + } str; + } val; +} impl_arg; + +static inline impl_arg *init_impl_arg(impl_type *type, impl_var *var, impl_def_val *def) { + impl_arg *arg = malloc(sizeof(*arg)); + arg->type = type; + arg->var = var; + arg->def = def; + return arg; +} + +static inline void free_impl_arg(impl_arg *arg) { + free_impl_type(arg->type); + free_impl_var(arg->var); + if (arg->def) { + free_impl_def_val(arg->def); + } + free(arg); +} + +typedef struct impl_args { + impl_arg **args; + size_t count; +} impl_args; + +static inline impl_args *init_impl_args(impl_arg *arg) { + impl_args *args = malloc(sizeof(*args)); + args->args = malloc(sizeof(*args->args)); + if (arg) { + args->count = 1; + args->args[0] = arg; + } else { + args->count = 0; + args->args = NULL; + } + return args; +} + +static inline impl_args *add_impl_arg(impl_args *args, impl_arg *arg) { + args->args = realloc(args->args, ++args->count * sizeof(*args->args)); + args->args[args->count-1] = arg; + return args; +} + +static inline void free_impl_args(impl_args *args) { + size_t i; + + for (i = 0; i < args->count; ++i) { + free_impl_arg(args->args[i]); + } + free(args->args); + free(args); +} + +typedef struct impl_func { + char *name; + impl_args *args; + impl_type *return_type; +} impl_func; + +static inline impl_func *init_impl_func(char *name, impl_args *args, impl_type *type) { + impl_func *func = malloc(sizeof(*func)); + func->name = strdup(name); + func->args = args ? args : init_impl_args(NULL); + func->return_type = type; + return func; +} + +static inline void free_impl_func(impl_func *f) { + free_impl_type(f->return_type); + free_impl_args(f->args); + free(f->name); + free(f); +} + +typedef struct let_func { + token_t type; + char *name; +} let_func; + +static inline let_func *init_let_func(token_t type, char *name) { + let_func *func = malloc(sizeof(*func)); + func->type = type; + func->name = (char *) strdup((const char *) name); + return func; +} + +static inline void free_let_func(let_func *func) { + free(func->name); + free(func); +} + +typedef struct let_value { + let_func *func; + impl_var *var; + unsigned null_pointer_ref:1; +} let_value; + +static inline let_value *init_let_value(let_func *func, impl_var *var, int null_pointer_ref) { + let_value *val = malloc(sizeof(*val)); + val->null_pointer_ref = null_pointer_ref; + val->func = func; + val->var = var; + return val; +} + +static inline void free_let_value(let_value *val) { + if (val->func) { + free_let_func(val->func); + } + if (val->var) { + free_impl_var(val->var); + } + free(val); +} + +typedef struct let_stmt { + decl_var *var; + let_value *val; +} let_stmt; + +static inline let_stmt *init_let_stmt(decl_var *var, let_value *val) { + let_stmt *let = malloc(sizeof(*let)); + let->var = var; + let->val = val; + return let; +} + +static inline void free_let_stmt(let_stmt *stmt) { + free_decl_var(stmt->var); + free_let_value(stmt->val); + free(stmt); +} + +typedef struct set_func { + token_t type; + char *name; +} set_func; + +static inline set_func *init_set_func(token_t type, char *name) { + set_func *func = malloc(sizeof(*func)); + func->type = type; + func->name = (char *) strdup((const char *) name); + return func; +} + +static inline void free_set_func(set_func *func) { + free(func->name); + free(func); +} + +typedef struct set_value { + set_func *func; + decl_vars *vars; +} set_value; + +static inline set_value *init_set_value(set_func *func, decl_vars *vars) { + set_value *val = malloc(sizeof(*val)); + val->func = func; + val->vars = vars; + return val; +} + +static inline void free_set_value(set_value *val) { + free_set_func(val->func); + free_decl_vars(val->vars); + free(val); +} + +typedef struct set_stmt { + impl_var *var; + set_value *val; +} set_stmt; + +static inline set_stmt *init_set_stmt(impl_var *var, set_value *val) { + set_stmt *set = malloc(sizeof(*set)); + set->var = var; + set->val = val; + return set; +} + +static inline void free_set_stmt(set_stmt *set) { + free_impl_var(set->var); + free_set_value(set->val); + free(set); +} + +typedef struct ret_stmt { + set_func *func; + decl_var *decl; +} ret_stmt; + +static inline ret_stmt *init_ret_stmt(set_func *func, decl_var *decl) { + ret_stmt *ret = malloc(sizeof(*ret)); + ret->func = func; + ret->decl = decl; + return ret; +} + +static inline void free_ret_stmt(ret_stmt *ret) { + free_set_func(ret->func); + free_decl_var(ret->decl); + free(ret); +} + +typedef struct impl_stmt { + token_t type; + union { + let_stmt *let; + set_stmt *set; + ret_stmt *ret; + void *ptr; + } s; +} impl_stmt; + +static inline impl_stmt *init_impl_stmt(token_t type, void *ptr) { + impl_stmt *stmt = malloc(sizeof(*stmt)); + stmt->type = type; + stmt->s.ptr = ptr; + return stmt; +} + +static inline void free_impl_stmt(impl_stmt *stmt) { + switch (stmt->type) { + case PSI_T_LET: + free_let_stmt(stmt->s.let); + break; + case PSI_T_SET: + free_set_stmt(stmt->s.set); + break; + case PSI_T_RET: + free_ret_stmt(stmt->s.ret); + break; + } + free(stmt); +} + +typedef struct impl_stmts { + struct { + ret_stmt **list; + size_t count; + } ret; + struct { + let_stmt **list; + size_t count; + } let; + struct { + set_stmt **list; + size_t count; + } set; +} impl_stmts; + +static inline void *add_impl_stmt_ex(void *list, size_t count, void *stmt) { + list = realloc(list, count * sizeof(list)); + ((void **)list)[count-1] = stmt; + return list; +} + +static inline impl_stmts *add_impl_stmt(impl_stmts *stmts, impl_stmt *stmt) { + switch (stmt->type) { + case PSI_T_RET: + stmts->ret.list = add_impl_stmt_ex(stmts->ret.list, ++stmts->ret.count, stmt->s.ret); + break; + case PSI_T_LET: + stmts->let.list = add_impl_stmt_ex(stmts->let.list, ++stmts->let.count, stmt->s.let); + break; + case PSI_T_SET: + stmts->set.list = add_impl_stmt_ex(stmts->set.list, ++stmts->set.count, stmt->s.set); + break; + } + return stmts; +} + +static inline impl_stmts *init_impl_stmts(impl_stmt *stmt) { + impl_stmts *stmts = calloc(1, sizeof(*stmts)); + return add_impl_stmt(stmts, stmt); +} + +static inline void free_impl_stmts(impl_stmts *stmts) { + size_t i; + + for (i = 0; i < stmts->let.count; ++i) { + free_let_stmt(stmts->let.list[i]); + } + free(stmts->let.list); + for (i = 0; i < stmts->ret.count; ++i) { + free_ret_stmt(stmts->ret.list[i]); + } + free(stmts->ret.list); + for (i = 0; i < stmts->set.count; ++i) { + free_set_stmt(stmts->set.list[i]); + } + free(stmts->set.list); + free(stmts); +} + +typedef struct impl { + impl_func *func; + impl_stmts *stmts; + decl *decl; +} impl; + +static inline impl *init_impl(impl_func *func, impl_stmts *stmts) { + impl *i = malloc(sizeof(*i)); + i->func = func; + i->stmts = stmts; + return i; +} + +static inline void free_impl(impl *impl) { + free_impl_func(impl->func); + free_impl_stmts(impl->stmts); + free(impl); +} + +typedef struct impls { + size_t count; + impl **list; +} impls; + +static impls *add_impl(impls *impls, impl *impl) { + if (!impls) { + impls = calloc(1, sizeof(*impls)); + } + impls->list = realloc(impls->list, ++impls->count * sizeof(*impls->list)); + impls->list[impls->count-1] = impl; + return impls; +} + +static void free_impls(impls *impls) { + size_t i; + + for (i = 0; i < impls->count; ++i) { + free_impl(impls->list[i]); + } + free(impls->list); + free(impls); +} + +typedef struct PSI_Data { + decl_typedefs *defs; + decls *decls; + impls *impls; + char *lib; + char *fn; +} PSI_Data; + +static inline void PSI_DataExchange(PSI_Data *dest, PSI_Data *src) { + memcpy(dest, src, sizeof(*dest)); + memset(src, 0, sizeof(*src)); +} + +static inline void PSI_DataDtor(PSI_Data *data) { + if (data->defs) { + free_decl_typedefs(data->defs); + } + if (data->decls) { + free_decls(data->decls); + } + if (data->impls) { + free_impls(data->impls); + } + if (data->lib) { + free(data->lib); + } + if (data->fn) { + free(data->fn); + } +} + +typedef struct PSI_Parser { + decl_typedefs *defs; + decls *decls; + impls *impls; + char *lib; + char *fn; + FILE *fp; + unsigned flags; + unsigned errors; + void *proc; + size_t line; + token_t num; + char *cur, *tok, *lim, *eof, *ctx, *mrk, buf[BSIZE]; +} PSI_Parser; + +static inline PSI_Token *PSI_TokenAlloc(PSI_Parser *P) { + PSI_Token *T; + size_t token_len; + + if (P->cur <= P->tok) { + return NULL; + } + + token_len = P->cur - P->tok; + + T = malloc(sizeof(*T) + token_len); + T->type = P->num; + T->line = P->line; + T->size = token_len; + T->text[token_len] = 0; + memcpy(T->text, P->tok, token_len); + + return T; +} + +#define PSI_PARSER_DEBUG 0x1 + +PSI_Parser *PSI_ParserInit(PSI_Parser *P, const char *filename, unsigned flags); +void PSI_ParserSyntaxError(PSI_Parser *P, const char *fn, size_t ln, const char *msg, ...); +size_t PSI_ParserFill(PSI_Parser *P, size_t n); +token_t PSI_ParserScan(PSI_Parser *P); +void PSI_ParserParse(PSI_Parser *P, PSI_Token *T); +void PSI_ParserDtor(PSI_Parser *P); +void PSI_ParserFree(PSI_Parser **P); + +#endif diff --git a/src/parser.re b/src/parser.re new file mode 100644 index 0000000..906e8b9 --- /dev/null +++ b/src/parser.re @@ -0,0 +1,268 @@ +#include +#include + +#include "parser.h" +#include "parser_proc.h" + +void *PSI_ParserProcAlloc(void*(unsigned long)); +void PSI_ParserProcFree(void*, void(*)(void*)); +void PSI_ParserProc(void *, token_t, PSI_Token *, PSI_Parser *); +void PSI_ParserProcTrace(FILE *, const char*); + +PSI_Parser *PSI_ParserInit(PSI_Parser *P, const char *filename, unsigned flags) +{ + FILE *fp; + + if (!P) { + P = malloc(sizeof(*P)); + } + memset(P, 0, sizeof(*P)); + + fp = fopen(filename, "r"); + + if (!fp) { + perror(filename); + return NULL; + } + + if (!P) { + P = malloc(sizeof(*P)); + } + memset(P, 0, sizeof(*P)); + + P->fp = fp; + P->fn = strdup(filename); + P->line = 1; + P->flags = flags; + + P->proc = PSI_ParserProcAlloc(malloc); + if (flags & PSI_PARSER_DEBUG) { + PSI_ParserProcTrace(stderr, "PSI> "); + } + + PSI_ParserFill(P, 0); + + return P; +} + +void PSI_ParserSyntaxError(PSI_Parser *P, const char *fn, size_t ln, const char *msg, ...) { + fprintf(stderr, "WARNING: Syntax error on line %zu in '%s'%s", ln, fn, msg ? ": ": "\n"); + if (msg) { + va_list argv; + + va_start(argv, msg); + vfprintf(stderr, msg, argv); + va_end(argv); + } + ++P->errors; +} + +size_t PSI_ParserFill(PSI_Parser *P, size_t n) +{ + if (P->flags & PSI_PARSER_DEBUG) { + fprintf(stderr, "PSI> Fill: n=%zu\n", n); + } + if (!n) { + P->cur = P->tok = P->lim = P->mrk = P->buf; + P->eof = NULL; + } + + if (!P->eof) { + size_t consumed = P->tok - P->buf; + size_t reserved = P->lim - P->tok; + size_t available = BSIZE - reserved; + size_t didread; + + if (consumed) { + memmove(P->buf, P->tok, reserved); + P->tok -= consumed; + P->cur -= consumed; + P->lim -= consumed; + P->mrk -= consumed; + } + + didread = fread(P->lim, 1, available, P->fp); + P->lim += didread; + if (didread < available) { + P->eof = P->lim; + } + + if (P->flags & PSI_PARSER_DEBUG) { + fprintf(stderr, "PSI> Fill: consumed=%zu reserved=%zu available=%zu didread=%zu\n", + consumed, reserved, available, didread); + } + } + if (P->flags & PSI_PARSER_DEBUG) { + fprintf(stderr, "PSI> Fill: avail=%zu\n", P->lim - P->cur); + } + return P->lim - P->cur; +} + +void PSI_ParserParse(PSI_Parser *P, PSI_Token *T) +{ + if (T) { + PSI_ParserProc(P->proc, T->type, T, P); + } else { + PSI_ParserProc(P->proc, 0, NULL, P); + } +} + +void PSI_ParserDtor(PSI_Parser *P) +{ + PSI_ParserProcFree(P->proc, free); + + if (P->fp) { + fclose(P->fp); + } + + PSI_DataDtor((PSI_Data *) P); + + memset(P, 0, sizeof(*P)); +} + +void PSI_ParserFree(PSI_Parser **P) +{ + if (*P) { + PSI_ParserDtor(*P); + free(*P); + *P = NULL; + } +} + +/*!max:re2c*/ +#define BSIZE 256 + +#if BSIZE < YYMAXFILL +# error BSIZE must be greater than YYMAXFILL +#endif + +#define RETURN(t) do { \ + P->num = t; \ + return t; \ +} while(1) + +/* DIGIT = [0-9] + DIGITS = DIGIT+ + DECIMALS = (+|-)? DIGIT* "." + digits ::= digits DIGIT. + decimals ::= digits DOT digits. + decimals ::= DOT digits. + decimals ::= digits DOT. + number ::= digits. + number ::= PLUS digits. + number ::= MINUS digits. + number ::= decimals. + number ::= MINUS decimals. + number ::= PLUS decimals. + +*/ +token_t PSI_ParserScan(PSI_Parser *P) +{ + for (;;) { + P->tok = P->cur; + /*!re2c + re2c:indent:top = 2; + re2c:define:YYCTYPE = "unsigned char"; + re2c:define:YYCURSOR = P->cur; + re2c:define:YYLIMIT = P->lim; + re2c:define:YYMARKER = P->mrk; + re2c:define:YYFILL = "{ if (!PSI_ParserFill(P,@@)) RETURN(-1); }"; + re2c:yyfill:parameter = 0; + + B = [^a-zA-Z0-9_]; + W = [a-zA-Z0-9_]; + NAME = [a-zA-Z_]W*; + NSNAME = (NAME)? ("\\" NAME)+; + QUOTED_STRING = "\"" ([^\"])+ "\""; + TRUE = 'TRUE'; + FALSE = 'FALSE'; + NULL = 'NULL'; + MIXED = 'mixed'; + VOID = 'void'; + BOOL = 'bool'; + INT = 'int'; + FLOAT = 'float'; + DOUBLE = 'double'; + SINT8 = 'sint8'; + UINT8 = 'uint8'; + SINT16 = 'sint16'; + UINT16 = 'uint16'; + SINT32 = 'sint32'; + UINT32 = 'uint32'; + SINT64 = 'sint64'; + UINT64 = 'uint64'; + STRING = 'string'; + ARRAY = 'array'; + FUNCTION = 'function'; + TYPEDEF = 'typedef'; + LIB = 'lib'; + LET = 'let'; + SET = 'set'; + RET = 'ret'; + STRLEN = 'strlen'; + STRVAL = 'strval'; + INTVAL = 'intval'; + FLOATVAL = 'floatval'; + BOOLVAL = 'boolval'; + TO_STRING = 'to_string'; + TO_INT = 'to_int'; + TO_FLOAT = 'to_float'; + TO_BOOL = 'to_bool'; + NUMBER = [+-]? [0-9]* "."? [0-9]+ ([eE] [+-]? [0-9]+)?; + + "#" .* "\n" { ++P->line; RETURN(PSI_T_COMMENT);} + "(" {RETURN(PSI_T_LPAREN);} + ")" {RETURN(PSI_T_RPAREN);} + ";" {RETURN(PSI_T_EOS);} + "," {RETURN(PSI_T_COMMA);} + ":" {RETURN(PSI_T_COLON);} + "{" {RETURN(PSI_T_LBRACE);} + "}" {RETURN(PSI_T_RBRACE);} + "=" {RETURN(PSI_T_EQUALS);} + "$" {RETURN(PSI_T_DOLLAR);} + "*" {RETURN(PSI_T_POINTER);} + "&" {RETURN(PSI_T_REFERENCE);} + [\r\n] { ++P->line; continue; } + [\t ]+ { continue; } + TRUE {RETURN(PSI_T_TRUE);} + FALSE {RETURN(PSI_T_FALSE);} + NULL {RETURN(PSI_T_NULL);} + MIXED {RETURN(PSI_T_MIXED);} + VOID {RETURN(PSI_T_VOID);} + BOOL {RETURN(PSI_T_BOOL);} + INT {RETURN(PSI_T_INT);} + FLOAT {RETURN(PSI_T_FLOAT);} + DOUBLE {RETURN(PSI_T_DOUBLE);} + SINT8 {RETURN(PSI_T_SINT8);} + UINT8 {RETURN(PSI_T_UINT8);} + SINT16 {RETURN(PSI_T_SINT16);} + UINT16 {RETURN(PSI_T_UINT16);} + SINT32 {RETURN(PSI_T_SINT32);} + UINT32 {RETURN(PSI_T_UINT32);} + SINT64 {RETURN(PSI_T_SINT64);} + UINT64 {RETURN(PSI_T_UINT64);} + STRING {RETURN(PSI_T_STRING);} + ARRAY {RETURN(PSI_T_ARRAY);} + FUNCTION {RETURN(PSI_T_FUNCTION);} + TYPEDEF {RETURN(PSI_T_TYPEDEF);} + LIB {RETURN(PSI_T_LIB);} + LET {RETURN(PSI_T_LET);} + SET {RETURN(PSI_T_SET);} + RET {RETURN(PSI_T_RET);} + STRLEN {RETURN(PSI_T_STRLEN);} + STRVAL {RETURN(PSI_T_STRVAL);} + INTVAL {RETURN(PSI_T_INTVAL);} + FLOATVAL {RETURN(PSI_T_FLOATVAL);} + BOOLVAL {RETURN(PSI_T_BOOLVAL);} + TO_STRING {RETURN(PSI_T_TO_STRING);} + TO_INT {RETURN(PSI_T_TO_INT);} + TO_FLOAT {RETURN(PSI_T_TO_FLOAT);} + TO_BOOL {RETURN(PSI_T_TO_BOOL);} + NUMBER {RETURN(PSI_T_NUMBER);} + NAME {RETURN(PSI_T_NAME);} + NSNAME {RETURN(PSI_T_NSNAME);} + QUOTED_STRING {RETURN(PSI_T_QUOTED_STRING);} + */ + } + return -1; +} diff --git a/src/parser_proc.h b/src/parser_proc.h new file mode 100644 index 0000000..d8466df --- /dev/null +++ b/src/parser_proc.h @@ -0,0 +1,50 @@ +#define PSI_T_COMMENT 1 +#define PSI_T_LIB 2 +#define PSI_T_QUOTED_STRING 3 +#define PSI_T_EOS 4 +#define PSI_T_TYPEDEF 5 +#define PSI_T_NAME 6 +#define PSI_T_LPAREN 7 +#define PSI_T_RPAREN 8 +#define PSI_T_COMMA 9 +#define PSI_T_VOID 10 +#define PSI_T_INT 11 +#define PSI_T_FLOAT 12 +#define PSI_T_DOUBLE 13 +#define PSI_T_SINT8 14 +#define PSI_T_UINT8 15 +#define PSI_T_SINT16 16 +#define PSI_T_UINT16 17 +#define PSI_T_SINT32 18 +#define PSI_T_UINT32 19 +#define PSI_T_SINT64 20 +#define PSI_T_UINT64 21 +#define PSI_T_LBRACE 22 +#define PSI_T_RBRACE 23 +#define PSI_T_FUNCTION 24 +#define PSI_T_NSNAME 25 +#define PSI_T_COLON 26 +#define PSI_T_NULL 27 +#define PSI_T_NUMBER 28 +#define PSI_T_TRUE 29 +#define PSI_T_FALSE 30 +#define PSI_T_DOLLAR 31 +#define PSI_T_REFERENCE 32 +#define PSI_T_EQUALS 33 +#define PSI_T_LET 34 +#define PSI_T_STRLEN 35 +#define PSI_T_STRVAL 36 +#define PSI_T_INTVAL 37 +#define PSI_T_FLOATVAL 38 +#define PSI_T_BOOLVAL 39 +#define PSI_T_SET 40 +#define PSI_T_TO_STRING 41 +#define PSI_T_TO_INT 42 +#define PSI_T_TO_FLOAT 43 +#define PSI_T_TO_BOOL 44 +#define PSI_T_RET 45 +#define PSI_T_MIXED 46 +#define PSI_T_BOOL 47 +#define PSI_T_STRING 48 +#define PSI_T_ARRAY 49 +#define PSI_T_POINTER 50 diff --git a/src/parser_proc.y b/src/parser_proc.y new file mode 100644 index 0000000..66946ca --- /dev/null +++ b/src/parser_proc.y @@ -0,0 +1,327 @@ +%include { +#include +#include +#include + +#include "parser.h" + +} + +%name PSI_ParserProc +%token_prefix PSI_T_ +%token_type {PSI_Token *} +%token_destructor {free($$);} +%extra_argument {PSI_Parser *P} +/* TOKEN is defined inside syntax_error */ +%syntax_error { + PSI_ParserSyntaxError(P, P->fn, P->line, "Unexpected token '%s'.\n", TOKEN->text); +} +file ::= blocks. + +blocks ::= block. +blocks ::= blocks block. + +block ::= COMMENT. + +block ::= LIB(T) QUOTED_STRING(libname) EOS. { + if (P->lib) { + PSI_ParserSyntaxError(P, P->fn, T->line, "Extra 'lib %s' statement has no effect.\n", libname->text); + } else { + P->lib = strndup(libname->text + 1, libname->size - 2); + } + free(libname); + free(T); +} + +block ::= decl(decl). { + P->decls = add_decl(P->decls, decl); +} +block ::= impl(impl). { + P->impls = add_impl(P->impls, impl); +} +block ::= decl_typedef(def). { + P->defs = add_decl_typedef(P->defs, def); +} + +%type decl_typedef {decl_typedef*} +decl_typedef(def) ::= TYPEDEF NAME(ALIAS) decl_type(type) EOS. { + def = init_decl_typedef(ALIAS->text, type); + free(ALIAS); +} + +%type decl {decl*} +decl(decl) ::= decl_abi(abi) decl_arg(func) LPAREN decl_args(args) RPAREN EOS. { + decl = init_decl(abi, func, args); +} + +%type decl_abi {decl_abi*} +decl_abi(abi) ::= NAME(T). { + abi = init_decl_abi(T->text); +} + +%type decl_var {decl_var*} +decl_var(var) ::= NAME(T). { + var = init_decl_var(T->text, 0); + free(T); +} +decl_var(var) ::= pointers(p) NAME(T). { + var = init_decl_var(T->text, p); + free(T); +} + +%type decl_vars {decl_vars*} +decl_vars(vars) ::= decl_var(var). { + vars = init_decl_vars(var); +} +decl_vars(vars) ::= decl_vars(vars_) COMMA decl_var(var). { + vars = add_decl_var(vars_, var); +} + +%type decl_arg {decl_arg*} +decl_arg(arg) ::= decl_type(type) decl_var(var). { + arg = init_decl_arg(type, var); +} + +%type decl_args {decl_args*} +decl_args(args) ::= decl_arg(arg). { + args = init_decl_args(arg); +} +decl_args(args) ::= decl_args(args_) COMMA decl_arg(arg). { + args = add_decl_arg(args_, arg); +} + +%type decl_type {decl_type*} +decl_type(type_) ::= VOID(T). { + type_ = init_decl_type(T->type, T->text); + free(T); +} +decl_type(type_) ::= INT(T). { + type_ = init_decl_type(T->type, T->text); + free(T); +} +decl_type(type_) ::= FLOAT(T). { + type_ = init_decl_type(T->type, T->text); + free(T); +} +decl_type(type_) ::= DOUBLE(T). { + type_ = init_decl_type(T->type, T->text); + free(T); +} +decl_type(type_) ::= SINT8(T). { + type_ = init_decl_type(T->type, T->text); + free(T); +} +decl_type(type_) ::= UINT8(T). { + type_ = init_decl_type(T->type, T->text); + free(T); +} +decl_type(type_) ::= SINT16(T). { + type_ = init_decl_type(T->type, T->text); + free(T); +} +decl_type(type_) ::= UINT16(T). { + type_ = init_decl_type(T->type, T->text); + free(T); +} +decl_type(type_) ::= SINT32(T). { + type_ = init_decl_type(T->type, T->text); + free(T); +} +decl_type(type_) ::= UINT32(T). { + type_ = init_decl_type(T->type, T->text); + free(T); +} +decl_type(type_) ::= SINT64(T). { + type_ = init_decl_type(T->type, T->text); + free(T); +} +decl_type(type_) ::= UINT64(T). { + type_ = init_decl_type(T->type, T->text); + free(T); +} +decl_type(type_) ::= NAME(T). { + type_ = init_decl_type(T->type, T->text); + free(T); +} + +%type impl {impl*} +impl(impl) ::= impl_func(func) LBRACE impl_stmts(stmts) RBRACE. { + impl = init_impl(func, stmts); +} + +%type impl_func {impl_func*} +impl_func(func) ::= FUNCTION NSNAME(NAME) LPAREN impl_args(args) RPAREN COLON impl_type(type). { + func = init_impl_func(NAME->text, args, type); + free(NAME); +} +impl_func(func) ::= FUNCTION NSNAME(NAME) LPAREN RPAREN COLON impl_type(type). { + func = init_impl_func(NAME->text, NULL, type); + free(NAME); +} + +%type impl_def_val {impl_def_val*} +impl_def_val(def) ::= NULL(T). { + def = init_impl_def_val(T); +} +impl_def_val(def) ::= NUMBER(T). { + def = init_impl_def_val(T); +} +impl_def_val(def) ::= TRUE(T). { + def = init_impl_def_val(T); +} +impl_def_val(def) ::= FALSE(T). { + def = init_impl_def_val(T); +} +impl_def_val(def) ::= QUOTED_STRING(T). { + def = init_impl_def_val(T); +} + +%type impl_var {impl_var*} +impl_var(var) ::= DOLLAR NAME(T). { + var = init_impl_var(T->text, 0); + free(T); +} +impl_var(var) ::= REFERENCE DOLLAR NAME(T). { + var = init_impl_var(T->text, 1); + free(T); +} + +%type impl_arg {impl_arg*} +impl_arg(arg) ::= impl_type(type) impl_var(var). { + arg = init_impl_arg(type, var, NULL); +} +impl_arg(arg) ::= impl_type(type) impl_var(var) EQUALS impl_def_val(def). { + arg = init_impl_arg(type, var, def); +} + +%type impl_args {impl_args*} +impl_args(args) ::= impl_arg(arg). { + args = init_impl_args(arg); +} +impl_args(args) ::= impl_args(args_) COMMA impl_arg(arg). { + args = add_impl_arg(args_, arg); +} + +%type impl_stmts {impl_stmts*} +impl_stmts(stmts) ::= impl_stmt(stmt). { + stmts = init_impl_stmts(stmt); +} +impl_stmts(stmts) ::= impl_stmts(stmts_) impl_stmt(stmt). { + stmts = add_impl_stmt(stmts_, stmt); +} + +%type impl_stmt {impl_stmt*} +impl_stmt(stmt) ::= let_stmt(let). { + stmt = init_impl_stmt(PSI_T_LET, let); +} +impl_stmt(stmt) ::= set_stmt(set). { + stmt = init_impl_stmt(PSI_T_SET, set); +} +impl_stmt(stmt) ::= ret_stmt(ret). { + stmt = init_impl_stmt(PSI_T_RET, ret); +} + +%type let_stmt {let_stmt*} +let_stmt(let) ::= LET decl_var(var) EQUALS let_value(val) EOS. { + let = init_let_stmt(var, val); +} + +%type let_value {let_value*} +let_value(val) ::= let_func(func) LPAREN impl_var(var) RPAREN. { + val = init_let_value(func, var, 0); +} +let_value(val) ::= REFERENCE NULL. { + val = init_let_value(NULL, NULL, 1); +} +let_value(val) ::= NULL. { + val = init_let_value(NULL, NULL, 0); +} + +%type let_func {let_func*} +let_func(func) ::= STRLEN(T). { + func = init_let_func(T->type, T->text); + free(T); +} +let_func(func) ::= STRVAL(T). { + func = init_let_func(T->type, T->text); + free(T); +} +let_func(func) ::= INTVAL(T). { + func = init_let_func(T->type, T->text); + free(T); +} +let_func(func) ::= FLOATVAL(T). { + func = init_let_func(T->type, T->text); + free(T); +} +let_func(func) ::= BOOLVAL(T). { + func = init_let_func(T->type, T->text); + free(T); +} + +%type set_stmt {set_stmt*} +set_stmt(set) ::= SET impl_var(var) EQUALS set_value(val) EOS. { + set = init_set_stmt(var, val); +} + +%type set_value {set_value*} +set_value(val) ::= set_func(func) LPAREN decl_vars(vars) RPAREN. { + val = init_set_value(func, vars); +} + +%type set_func {set_func*} +set_func(func) ::= TO_STRING(T). { + func = init_set_func(T->type, T->text); + free(T); +} +set_func(func) ::= TO_INT(T). { + func = init_set_func(T->type, T->text); + free(T); +} +set_func(func) ::= TO_FLOAT(T). { + func = init_set_func(T->type, T->text); + free(T); +} +set_func(func) ::= TO_BOOL(T). { + func = init_set_func(T->type, T->text); + free(T); +} + +%type ret_stmt {ret_stmt*} +ret_stmt(ret) ::= RET set_func(func) LPAREN decl_var(var) RPAREN EOS. { + ret = init_ret_stmt(func, var); +} + +%type impl_type {impl_type*} +impl_type(type_) ::= VOID(T). { + type_ = init_impl_type(T->type, T->text); + free(T); +} +impl_type(type_) ::= MIXED(T). { + type_ = init_impl_type(T->type, T->text); + free(T); +} +impl_type(type_) ::= BOOL(T). { + type_ = init_impl_type(T->type, T->text); + free(T); +} +impl_type(type_) ::= INT(T). { + type_ = init_impl_type(T->type, T->text); + free(T); +} +impl_type(type_) ::= FLOAT(T). { + type_ = init_impl_type(T->type, T->text); + free(T); +} +impl_type(type_) ::= STRING(T). { + type_ = init_impl_type(T->type, T->text); + free(T); +} +impl_type(type_) ::= ARRAY(T). { + type_ = init_impl_type(T->type, T->text); + free(T); +} + +%type pointers {unsigned} +pointers(p) ::= POINTER. {++p;} +pointers(p) ::= pointers(P) POINTER. {p = ++P;} diff --git a/src/validator.c b/src/validator.c new file mode 100644 index 0000000..191124a --- /dev/null +++ b/src/validator.c @@ -0,0 +1,310 @@ +#include +#include +#include +#include +#include + +#include + +#include "validator.h" + +PSI_Validator *PSI_ValidatorInit(PSI_Validator *V, PSI_Parser *P) +{ + if (!V) { + V = malloc(sizeof(*V)); + } + memset(V, 0, sizeof(*V)); + + PSI_DataExchange((PSI_Data *) V, (PSI_Data *) P); + + return V; +} + +void PSI_ValidatorDtor(PSI_Validator *V) +{ + PSI_DataDtor((PSI_Data *) V); + memset(V, 0, sizeof(*V)); +} + +void PSI_ValidatorFree(PSI_Validator **V) +{ + if (*V) { + PSI_ValidatorDtor(*V); + free(*V); + *V = NULL; + } +} + +static int validate_lib(PSI_Validator *V) { + char lib[MAXPATHLEN]; + const char *ptr = V->lib; + size_t len; + + if (!ptr) { + /* FIXME: assume stdlib */ + return 1; + fprintf(stderr, "No import library defined;" + " use 'lib \"\";' statement.\n"); + } else if (!strchr(ptr, '/')) { +#ifdef DARWIN + len = snprintf(lib, MAXPATHLEN, "lib%s.dylib", ptr); +#else + len = snprintf(lib, MAXPATHLEN, "lib%s.so", ptr); +#endif + if (MAXPATHLEN == len) { + fprintf(stderr, "Library name too long: '%s'\n", ptr); + } + lib[len] = 0; + ptr = lib; + } + if (!(V->dlopened = dlopen(ptr, RTLD_LAZY|RTLD_LOCAL))) { + fprintf(stderr, "Could not open library '%s': %s.\n", V->lib, dlerror()); + return 0; + } + return 1; +} +static inline int locate_decl_type_alias(decl_typedefs *defs, decl_type *type) { + size_t i; + + if (type->real) { + return 1; + } + for (i = 0; i < defs->count; ++i) { + if (!strcmp(defs->list[i]->alias, type->name)) { + type->real = defs->list[i]->type; + return 1; + } + } + return 0; +} +static inline int validate_decl_type(PSI_Validator *V, decl_arg *arg, decl_type *type) { + if (type->type == PSI_T_NAME) { + size_t i; + + if (!V->defs || !locate_decl_type_alias(V->defs, type)) { + fprintf(stderr, "Cannot use '%s' as type for '%s';" + " Use 'typedef ;' statement.\n", + type->name, arg->var->name); + } + } + return 1; +} +static inline int validate_typedef(PSI_Validator *V, decl_typedef *def) { + /* FIXME: check def->alias */ + if (def->type->type == PSI_T_NAME) { + fprintf(stderr, "Type '%s' cannot be aliased to '%s'\n", + def->type->name, def->alias); + return 0; + } + return 1; +} +static inline int validate_typedefs(PSI_Validator *V) { + size_t i; + + for (i = 0; i < V->defs->count; ++i) { + if (!validate_typedef(V, V->defs->list[i])) { + return 0; + } + } + + return 1; +} +static inline int validate_decl_func(PSI_Validator *V, decl *decl, decl_arg *func) +{ + void *dlptr; + + if (!strcmp(func->var->name, "dlsym")) { + fprintf(stderr, "Cannot dlsym dlsym (sic!)\n"); + return 0; + } + + if (!validate_decl_type(V, func, func->type)) { + return 0; + } + + decl->dlptr = dlsym(V->dlopened ?: RTLD_DEFAULT, func->var->name); + if (!decl->dlptr) { + fprintf(stderr, "Failed to located symbol '%s': %s\n", + func->var->name, dlerror()); + } + return 1; +} +static inline int validate_decl_abi(PSI_Validator *V, decl_abi *abi) { + if (strcasecmp(abi->convention, "default")) { + fprintf(stderr, "Invalid calling convention: '%s'\n", abi->convention); + return 0; + } + /* FIXME */ + return 1; +} +static inline int validate_decl_arg(PSI_Validator *V, decl *decl, decl_arg *arg) { + if (!validate_decl_type(V, arg, arg->type)) { + return 0; + } + return 1; +} +static inline int validate_decl_args(PSI_Validator *V, decl *decl, decl_args *args) { + size_t i; + + for (i = 0; i < args->count; ++i) { + if (!validate_decl_arg(V, decl, args->args[i])) { + return 0; + } + } + return 1; +} +static inline int validate_decl(PSI_Validator *V, decl *decl) { + if (!validate_decl_abi(V, decl->abi)) { + return 0; + } + if (!validate_decl_func(V, decl, decl->func)) { + return 0; + } + if (decl->args && !validate_decl_args(V, decl, decl->args)) { + return 0; + } + return 1; +} +static inline int validate_decls(PSI_Validator *V) { + size_t i; + + for (i = 0; i < V->decls->count; ++i) { + if (!validate_decl(V, V->decls->list[i])) { + return 0; + } + } + return 1; +} + +static inline int validate_impl_type(PSI_Validator *V, impl *impl, impl_type *type) { + /* FIXME */ + return 1; +} +static inline int validate_impl_arg(PSI_Validator *V, impl *impl, impl_arg *arg) { + return 1; +} +static inline int validate_impl_args(PSI_Validator *V, impl *impl, impl_args *args) { + size_t i; + + for (i = 0; i < args->count; ++i) { + if (!validate_impl_arg(V, impl, args->args[i])) { + return 0; + } + } + return 1; +} +static inline int validate_impl_func(PSI_Validator *V, impl *impl, impl_func *func) { + /* FIXME: does name need any validation? */ + if (!validate_impl_type(V, impl, func->return_type)) { + return 0; + } + if (func->args && !validate_impl_args(V, impl, func->args)) { + return 0; + } + return 1; +} +static inline decl *locate_impl_decl(decls *decls, ret_stmt *ret) { + size_t i; + + for (i = 0; i < decls->count; ++i) { + if (!strcmp(decls->list[i]->func->var->name, ret->decl->name)) { + return decls->list[i]; + } + } + return NULL; +} +static inline int validate_impl_stmts(PSI_Validator *V, impl *impl, impl_stmts *stmts) { + /* okay, + * - we must have exactly one ret stmt delcaring the native func to call and which type cast to apply + * - we can have multiple let stmts; every arg of the ret stmts var (the function to call) must have one + * - we can have any count of set stmts; processing out vars, etc. + */ + size_t i, j; + ret_stmt *ret; + decl *decl; + int *check; + + if (!stmts) { + fprintf(stderr, "Missing body for implementation %s!\n", impl->func->name); + return 0; + } + if (stmts->ret.count != 1) { + if (stmts->ret.count > 1) { + fprintf(stderr, "Too many `ret` statements for implmentation %s; found %zu, exactly one is needed.\n", + impl->func->name, stmts->ret.count); + } else { + fprintf(stderr, "Missing `ret` statement for implementation %s.\n", impl->func->name); + } + return 0; + } + + ret = stmts->ret.list[0]; + decl = locate_impl_decl(V->decls, ret); + if (!decl) { + fprintf(stderr, "Missing declaration for implementation %s.\n", impl->func->name); + return 0; + } + + /* check that we have a let stmt for every decl arg */ + check = calloc(decl->args->count, sizeof(int)); + for (i = 0; i < stmts->let.count; ++i) { + let_stmt *let = stmts->let.list[i]; + + for (j = 0; j < decl->args->count; ++j) { + if (!strcmp(decl->args->args[j]->var->name, let->var->name)) { + check[j] = 1; + break; + } + } + } + for (i = 0; i < decl->args->count; ++i) { + if (!check[i]) { + fprintf(stderr, "Missing `let` statement for arg '%s %.*s%s' of declaration '%s' for implementation '%s'.\n", + decl->args->args[i]->type->name, (int) decl->args->args[i]->var->pointer_level, "*****", decl->args->args[i]->var->name, decl->func->var->name, impl->func->name); + free(check); + return 0; + } + } + free(check); + + impl->decl = decl; + + return 1; +} + +static inline int validate_impl(PSI_Validator *V, impl *impl) { + if (!validate_impl_func(V, impl, impl->func)) { + return 0; + } + if (!validate_impl_stmts(V, impl, impl->stmts)) { + return 0; + } + return 1; +} +static inline int validate_impls(PSI_Validator *V) { + size_t i; + + for (i = 0; i < V->impls->count; ++i) { + if (!validate_impl(V, V->impls->list[i])) { + return 0; + } + } + return 1; +} + +int PSI_ValidatorValidate(PSI_Validator *V) +{ + if (!validate_lib(V)) { + return 0; + } + if (V->defs && !validate_typedefs(V)) { + return 0; + } + if (V->decls && !validate_decls(V)) { + return 0; + } + if (V->impls && !validate_impls(V)) { + return 0; + } + return 1; +} diff --git a/src/validator.h b/src/validator.h new file mode 100644 index 0000000..f96111c --- /dev/null +++ b/src/validator.h @@ -0,0 +1,20 @@ +#ifndef _PSI_VALIDATOR_H +#define _PSI_VALIDATOR_H + +#include "parser.h" + +typedef struct PSI_Validator { + decl_typedefs *defs; + decls *decls; + impls *impls; + char *lib; + char *fn; + void *dlopened; +} PSI_Validator; + +PSI_Validator *PSI_ValidatorInit(PSI_Validator *V, PSI_Parser *P); +int PSI_ValidatorValidate(PSI_Validator *V); +void PSI_ValidatorFree(PSI_Validator **V); +void PSI_ValidatorDtor(PSI_Validator *V); + +#endif