From f1a387482a9270a34ae684109ad8be7c104148d6 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Wed, 14 Oct 2015 20:47:17 +0200 Subject: [PATCH 1/1] flush --- .gitignore | 47 +++++++++++++--- AUTHORS | 1 + BUGS | 1 + CONTRIBUTING.md | 39 ++++++++++++++ CREDITS | 2 + EXPERIMENTAL | 0 LICENSE | 22 ++++++++ Makefile.frag | 30 +++++++++++ README.md | 48 +++++++++++++++++ THANKS | 1 + TODO | 1 + config.m4 | 43 +++++++++++++++ idl/compiler.c | 14 ----- package.xml | 3 ++ php_psi.h | 43 +++++++++++++++ src/compiler.c | 81 ++++++++++++++++++++++++++++ {idl => src}/compiler.h | 0 src/module.c | 107 +++++++++++++++++++++++++++++++++++++ {idl => src}/parser.h | 89 ++++++++++++++++++++++-------- {idl => src}/parser.re | 60 ++++++++++++++++++--- {idl => src}/parser_proc.h | 44 +++++++-------- {idl => src}/parser_proc.y | 50 +++++++---------- {idl => src}/validator.c | 77 ++++++++++++++++++++++++-- {idl => src}/validator.h | 0 24 files changed, 697 insertions(+), 106 deletions(-) create mode 100644 AUTHORS create mode 100644 BUGS create mode 100644 CONTRIBUTING.md create mode 100644 CREDITS create mode 100644 EXPERIMENTAL create mode 100644 LICENSE create mode 100644 Makefile.frag create mode 100644 README.md create mode 100644 THANKS create mode 100644 config.m4 delete mode 100644 idl/compiler.c create mode 100644 package.xml create mode 100644 php_psi.h create mode 100644 src/compiler.c rename {idl => src}/compiler.h (100%) create mode 100644 src/module.c rename {idl => src}/parser.h (88%) rename {idl => src}/parser.re (74%) rename {idl => src}/parser_proc.h (56%) rename {idl => src}/parser_proc.y (88%) rename {idl => src}/validator.c (70%) rename {idl => src}/validator.h (100%) 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/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/idl/compiler.h b/src/compiler.h similarity index 100% rename from idl/compiler.h rename to src/compiler.h 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/idl/parser.h b/src/parser.h similarity index 88% rename from idl/parser.h rename to src/parser.h index dcb464b..d4909dd 100644 --- a/idl/parser.h +++ b/src/parser.h @@ -3,8 +3,11 @@ #include #include +#include #include +#include + #include "parser_proc.h" #define BSIZE 256 @@ -269,21 +272,18 @@ static inline void free_impl_var(impl_var *var) { typedef struct impl_def_val { token_t type; - union { - int64_t digits; - double decimals; - } v; - unsigned is_null:1; + char *text; } impl_def_val; -static inline impl_def_val *init_impl_def_val() { +static inline impl_def_val *init_impl_def_val(PSI_Token *T) { impl_def_val *def = malloc(sizeof(*def)); - def->type = 0; - def->is_null = 1; + 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); } @@ -291,6 +291,15 @@ 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) { @@ -528,37 +537,68 @@ static inline void free_impl_stmt(impl_stmt *stmt) { } typedef struct impl_stmts { - impl_stmt **stmts; - size_t count; + 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 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 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) { - stmts->stmts = realloc(stmts->stmts, ++stmts->count * sizeof(*stmts->stmts)); - stmts->stmts[stmts->count-1] = 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->count; ++i) { - free_impl_stmt(stmts->stmts[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->stmts); + 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) { @@ -636,6 +676,8 @@ typedef struct PSI_Parser { char *lib; char *fn; FILE *fp; + unsigned flags; + unsigned errors; void *proc; size_t line; token_t num; @@ -662,7 +704,10 @@ static inline PSI_Token *PSI_TokenAlloc(PSI_Parser *P) { return T; } -PSI_Parser *PSI_ParserInit(PSI_Parser *P, const char *filename); +#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); diff --git a/idl/parser.re b/src/parser.re similarity index 74% rename from idl/parser.re rename to src/parser.re index 5a06023..906e8b9 100644 --- a/idl/parser.re +++ b/src/parser.re @@ -7,8 +7,9 @@ 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) +PSI_Parser *PSI_ParserInit(PSI_Parser *P, const char *filename, unsigned flags) { FILE *fp; @@ -32,17 +33,35 @@ PSI_Parser *PSI_ParserInit(PSI_Parser *P, const char *filename) 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) { - // printf("+ Fill: n=%zu\n", 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; @@ -68,10 +87,14 @@ size_t PSI_ParserFill(PSI_Parser *P, size_t n) P->eof = P->lim; } - // printf("+ Fill: consumed=%zu reserved=%zu available=%zu didread=%zu\n", - // consumed, reserved, available, didread); + 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); } - // printf("+ Fill: avail=%zu\n", P->lim - P->cur); return P->lim - P->cur; } @@ -118,6 +141,21 @@ void PSI_ParserFree(PSI_Parser **P) 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 (;;) { @@ -133,9 +171,11 @@ token_t PSI_ParserScan(PSI_Parser *P) B = [^a-zA-Z0-9_]; W = [a-zA-Z0-9_]; - NAME = W+; + NAME = [a-zA-Z_]W*; NSNAME = (NAME)? ("\\" NAME)+; QUOTED_STRING = "\"" ([^\"])+ "\""; + TRUE = 'TRUE'; + FALSE = 'FALSE'; NULL = 'NULL'; MIXED = 'mixed'; VOID = 'void'; @@ -159,6 +199,7 @@ token_t PSI_ParserScan(PSI_Parser *P) LET = 'let'; SET = 'set'; RET = 'ret'; + STRLEN = 'strlen'; STRVAL = 'strval'; INTVAL = 'intval'; FLOATVAL = 'floatval'; @@ -167,6 +208,7 @@ token_t PSI_ParserScan(PSI_Parser *P) 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);} @@ -176,13 +218,14 @@ token_t PSI_ParserScan(PSI_Parser *P) ":" {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; } + 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);} @@ -206,6 +249,7 @@ token_t PSI_ParserScan(PSI_Parser *P) 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);} @@ -214,7 +258,7 @@ token_t PSI_ParserScan(PSI_Parser *P) 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);} + NUMBER {RETURN(PSI_T_NUMBER);} NAME {RETURN(PSI_T_NAME);} NSNAME {RETURN(PSI_T_NSNAME);} QUOTED_STRING {RETURN(PSI_T_QUOTED_STRING);} diff --git a/idl/parser_proc.h b/src/parser_proc.h similarity index 56% rename from idl/parser_proc.h rename to src/parser_proc.h index 3be3c66..d8466df 100644 --- a/idl/parser_proc.h +++ b/src/parser_proc.h @@ -25,26 +25,26 @@ #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_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/idl/parser_proc.y b/src/parser_proc.y similarity index 88% rename from idl/parser_proc.y rename to src/parser_proc.y index 47de153..66946ca 100644 --- a/idl/parser_proc.y +++ b/src/parser_proc.y @@ -2,20 +2,9 @@ #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 @@ -25,7 +14,7 @@ %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); + PSI_ParserSyntaxError(P, P->fn, P->line, "Unexpected token '%s'.\n", TOKEN->text); } file ::= blocks. @@ -36,7 +25,7 @@ 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); + 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); } @@ -171,13 +160,20 @@ impl_func(func) ::= FUNCTION NSNAME(NAME) LPAREN RPAREN COLON impl_type(type). { } %type impl_def_val {impl_def_val*} -impl_def_val(def) ::= NULL. { - /* FIXME */ - def = init_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) ::= number. { - /* FIXME */ - def = init_impl_def_val(); +impl_def_val(def) ::= QUOTED_STRING(T). { + def = init_impl_def_val(T); } %type impl_var {impl_var*} @@ -242,6 +238,10 @@ let_value(val) ::= NULL. { } %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); @@ -322,18 +322,6 @@ impl_type(type_) ::= ARRAY(T). { 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/src/validator.c similarity index 70% rename from idl/validator.c rename to src/validator.c index 87951eb..191124a 100644 --- a/idl/validator.c +++ b/src/validator.c @@ -1,8 +1,10 @@ #include #include #include -#include #include +#include + +#include #include "validator.h" @@ -33,7 +35,7 @@ void PSI_ValidatorFree(PSI_Validator **V) } } -static inline int validate_lib(PSI_Validator *V) { +static int validate_lib(PSI_Validator *V) { char lib[MAXPATHLEN]; const char *ptr = V->lib; size_t len; @@ -56,7 +58,7 @@ static inline int validate_lib(PSI_Validator *V) { ptr = lib; } if (!(V->dlopened = dlopen(ptr, RTLD_LAZY|RTLD_LOCAL))) { - perror(ptr); + fprintf(stderr, "Could not open library '%s': %s.\n", V->lib, dlerror()); return 0; } return 1; @@ -201,9 +203,75 @@ static inline int validate_impl_func(PSI_Validator *V, impl *impl, impl_func *fu } 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; @@ -226,6 +294,9 @@ static inline int validate_impls(PSI_Validator *V) { int PSI_ValidatorValidate(PSI_Validator *V) { + if (!validate_lib(V)) { + return 0; + } if (V->defs && !validate_typedefs(V)) { return 0; } diff --git a/idl/validator.h b/src/validator.h similarity index 100% rename from idl/validator.h rename to src/validator.h -- 2.30.2