Initial commit
Import existing source tree; original VCS history is no longer available. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
noinst_LIBRARIES = libeel.a
|
||||
|
||||
INCLUDES = @LOCALCFLAGS@
|
||||
|
||||
libeel_a_SOURCES = eel.c e_script.c e_symtab.c e_path.c e_util.c \
|
||||
e_lexer.c e_register.c e_builtin.c e_getargs.c
|
||||
|
||||
EXTRA_DIST = *.h *.txt
|
||||
+434
@@ -0,0 +1,434 @@
|
||||
# Makefile.in generated by automake 1.9.6 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
|
||||
# 2003, 2004, 2005 Free Software Foundation, Inc.
|
||||
# This Makefile.in is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
@SET_MAKE@
|
||||
|
||||
srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
pkgdatadir = $(datadir)/@PACKAGE@
|
||||
pkglibdir = $(libdir)/@PACKAGE@
|
||||
pkgincludedir = $(includedir)/@PACKAGE@
|
||||
top_builddir = ..
|
||||
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
|
||||
INSTALL = @INSTALL@
|
||||
install_sh_DATA = $(install_sh) -c -m 644
|
||||
install_sh_PROGRAM = $(install_sh) -c
|
||||
install_sh_SCRIPT = $(install_sh) -c
|
||||
INSTALL_HEADER = $(INSTALL_DATA)
|
||||
transform = $(program_transform_name)
|
||||
NORMAL_INSTALL = :
|
||||
PRE_INSTALL = :
|
||||
POST_INSTALL = :
|
||||
NORMAL_UNINSTALL = :
|
||||
PRE_UNINSTALL = :
|
||||
POST_UNINSTALL = :
|
||||
build_triplet = @build@
|
||||
host_triplet = @host@
|
||||
target_triplet = @target@
|
||||
subdir = eel
|
||||
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/configure.in
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
|
||||
CONFIG_HEADER = $(top_builddir)/aconfig.h
|
||||
CONFIG_CLEAN_FILES =
|
||||
LIBRARIES = $(noinst_LIBRARIES)
|
||||
AR = ar
|
||||
ARFLAGS = cru
|
||||
libeel_a_AR = $(AR) $(ARFLAGS)
|
||||
libeel_a_LIBADD =
|
||||
am_libeel_a_OBJECTS = eel.$(OBJEXT) e_script.$(OBJEXT) \
|
||||
e_symtab.$(OBJEXT) e_path.$(OBJEXT) e_util.$(OBJEXT) \
|
||||
e_lexer.$(OBJEXT) e_register.$(OBJEXT) e_builtin.$(OBJEXT) \
|
||||
e_getargs.$(OBJEXT)
|
||||
libeel_a_OBJECTS = $(am_libeel_a_OBJECTS)
|
||||
DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
|
||||
depcomp = $(SHELL) $(top_srcdir)/depcomp
|
||||
am__depfiles_maybe = depfiles
|
||||
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
|
||||
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
|
||||
CCLD = $(CC)
|
||||
LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
|
||||
SOURCES = $(libeel_a_SOURCES)
|
||||
DIST_SOURCES = $(libeel_a_SOURCES)
|
||||
ETAGS = etags
|
||||
CTAGS = ctags
|
||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||
ACLOCAL = @ACLOCAL@
|
||||
AMDEP_FALSE = @AMDEP_FALSE@
|
||||
AMDEP_TRUE = @AMDEP_TRUE@
|
||||
AMTAR = @AMTAR@
|
||||
AUDIO_LIBS = @AUDIO_LIBS@
|
||||
AUTOCONF = @AUTOCONF@
|
||||
AUTOHEADER = @AUTOHEADER@
|
||||
AUTOMAKE = @AUTOMAKE@
|
||||
AWK = @AWK@
|
||||
BUILD_MACOSX_BUNDLE_FALSE = @BUILD_MACOSX_BUNDLE_FALSE@
|
||||
BUILD_MACOSX_BUNDLE_TRUE = @BUILD_MACOSX_BUNDLE_TRUE@
|
||||
BUILD_SIMPLE_BUNDLE_FALSE = @BUILD_SIMPLE_BUNDLE_FALSE@
|
||||
BUILD_SIMPLE_BUNDLE_TRUE = @BUILD_SIMPLE_BUNDLE_TRUE@
|
||||
CC = @CC@
|
||||
CCDEPMODE = @CCDEPMODE@
|
||||
CFLAGS = @CFLAGS@
|
||||
CONFIGDIR = @CONFIGDIR@
|
||||
CONFIGFILE = @CONFIGFILE@
|
||||
CPP = @CPP@
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
CXX = @CXX@
|
||||
CXXDEPMODE = @CXXDEPMODE@
|
||||
CXXFLAGS = @CXXFLAGS@
|
||||
CYGPATH_W = @CYGPATH_W@
|
||||
DATADIR = @DATADIR@
|
||||
DEFS = @DEFS@
|
||||
DEPDIR = @DEPDIR@
|
||||
ECHO_C = @ECHO_C@
|
||||
ECHO_N = @ECHO_N@
|
||||
ECHO_T = @ECHO_T@
|
||||
EGREP = @EGREP@
|
||||
EXEEXT = @EXEEXT@
|
||||
EXEFILE = @EXEFILE@
|
||||
GREP = @GREP@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBOBJS = @LIBOBJS@
|
||||
LIBS = @LIBS@
|
||||
LOCALCFLAGS = @LOCALCFLAGS@
|
||||
LTLIBOBJS = @LTLIBOBJS@
|
||||
MAKEINFO = @MAKEINFO@
|
||||
MATHLIB = @MATHLIB@
|
||||
OBJEXT = @OBJEXT@
|
||||
PACKAGE = @PACKAGE@
|
||||
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
|
||||
PACKAGE_NAME = @PACKAGE_NAME@
|
||||
PACKAGE_STRING = @PACKAGE_STRING@
|
||||
PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||
POW_LIB = @POW_LIB@
|
||||
RANLIB = @RANLIB@
|
||||
SCOREDIR = @SCOREDIR@
|
||||
SDL_CFLAGS = @SDL_CFLAGS@
|
||||
SDL_CONFIG = @SDL_CONFIG@
|
||||
SDL_LIBS = @SDL_LIBS@
|
||||
SET_MAKE = @SET_MAKE@
|
||||
SHELL = @SHELL@
|
||||
STRIP = @STRIP@
|
||||
UNIX_SCOREDIR_FALSE = @UNIX_SCOREDIR_FALSE@
|
||||
UNIX_SCOREDIR_TRUE = @UNIX_SCOREDIR_TRUE@
|
||||
VERSION = @VERSION@
|
||||
XMKMF = @XMKMF@
|
||||
X_CFLAGS = @X_CFLAGS@
|
||||
X_EXTRA_LIBS = @X_EXTRA_LIBS@
|
||||
X_LIBS = @X_LIBS@
|
||||
X_PRE_LIBS = @X_PRE_LIBS@
|
||||
ac_ct_CC = @ac_ct_CC@
|
||||
ac_ct_CXX = @ac_ct_CXX@
|
||||
am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
|
||||
am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
|
||||
am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
|
||||
am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
|
||||
am__include = @am__include@
|
||||
am__leading_dot = @am__leading_dot@
|
||||
am__quote = @am__quote@
|
||||
am__tar = @am__tar@
|
||||
am__untar = @am__untar@
|
||||
bindir = @bindir@
|
||||
build = @build@
|
||||
build_alias = @build_alias@
|
||||
build_cpu = @build_cpu@
|
||||
build_os = @build_os@
|
||||
build_vendor = @build_vendor@
|
||||
datadir = @datadir@
|
||||
datarootdir = @datarootdir@
|
||||
docdir = @docdir@
|
||||
dvidir = @dvidir@
|
||||
exec_prefix = @exec_prefix@
|
||||
host = @host@
|
||||
host_alias = @host_alias@
|
||||
host_cpu = @host_cpu@
|
||||
host_os = @host_os@
|
||||
host_vendor = @host_vendor@
|
||||
htmldir = @htmldir@
|
||||
includedir = @includedir@
|
||||
infodir = @infodir@
|
||||
install_sh = @install_sh@
|
||||
libdir = @libdir@
|
||||
libexecdir = @libexecdir@
|
||||
localedir = @localedir@
|
||||
localstatedir = @localstatedir@
|
||||
mandir = @mandir@
|
||||
mkdir_p = @mkdir_p@
|
||||
oldincludedir = @oldincludedir@
|
||||
pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
sysconfdir = @sysconfdir@
|
||||
target = @target@
|
||||
target_alias = @target_alias@
|
||||
target_cpu = @target_cpu@
|
||||
target_os = @target_os@
|
||||
target_vendor = @target_vendor@
|
||||
noinst_LIBRARIES = libeel.a
|
||||
INCLUDES = @LOCALCFLAGS@
|
||||
libeel_a_SOURCES = eel.c e_script.c e_symtab.c e_path.c e_util.c \
|
||||
e_lexer.c e_register.c e_builtin.c e_getargs.c
|
||||
|
||||
EXTRA_DIST = *.h *.txt
|
||||
all: all-am
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .c .o .obj
|
||||
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
|
||||
@for dep in $?; do \
|
||||
case '$(am__configure_deps)' in \
|
||||
*$$dep*) \
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
|
||||
&& exit 0; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
done; \
|
||||
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign eel/Makefile'; \
|
||||
cd $(top_srcdir) && \
|
||||
$(AUTOMAKE) --foreign eel/Makefile
|
||||
.PRECIOUS: Makefile
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
@case '$?' in \
|
||||
*config.status*) \
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
|
||||
*) \
|
||||
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
|
||||
esac;
|
||||
|
||||
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
|
||||
$(top_srcdir)/configure: $(am__configure_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
|
||||
clean-noinstLIBRARIES:
|
||||
-test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
|
||||
libeel.a: $(libeel_a_OBJECTS) $(libeel_a_DEPENDENCIES)
|
||||
-rm -f libeel.a
|
||||
$(libeel_a_AR) libeel.a $(libeel_a_OBJECTS) $(libeel_a_LIBADD)
|
||||
$(RANLIB) libeel.a
|
||||
|
||||
mostlyclean-compile:
|
||||
-rm -f *.$(OBJEXT)
|
||||
|
||||
distclean-compile:
|
||||
-rm -f *.tab.c
|
||||
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/e_builtin.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/e_getargs.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/e_lexer.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/e_path.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/e_register.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/e_script.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/e_symtab.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/e_util.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eel.Po@am__quote@
|
||||
|
||||
.c.o:
|
||||
@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
|
||||
@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(COMPILE) -c $<
|
||||
|
||||
.c.obj:
|
||||
@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
|
||||
@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
|
||||
uninstall-info-am:
|
||||
|
||||
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) ' { files[$$0] = 1; } \
|
||||
END { for (i in files) print i; }'`; \
|
||||
mkid -fID $$unique
|
||||
tags: TAGS
|
||||
|
||||
TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
|
||||
$(TAGS_FILES) $(LISP)
|
||||
tags=; \
|
||||
here=`pwd`; \
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) ' { files[$$0] = 1; } \
|
||||
END { for (i in files) print i; }'`; \
|
||||
if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
|
||||
test -n "$$unique" || unique=$$empty_fix; \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
$$tags $$unique; \
|
||||
fi
|
||||
ctags: CTAGS
|
||||
CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
|
||||
$(TAGS_FILES) $(LISP)
|
||||
tags=; \
|
||||
here=`pwd`; \
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) ' { files[$$0] = 1; } \
|
||||
END { for (i in files) print i; }'`; \
|
||||
test -z "$(CTAGS_ARGS)$$tags$$unique" \
|
||||
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
|
||||
$$tags $$unique
|
||||
|
||||
GTAGS:
|
||||
here=`$(am__cd) $(top_builddir) && pwd` \
|
||||
&& cd $(top_srcdir) \
|
||||
&& gtags -i $(GTAGS_ARGS) $$here
|
||||
|
||||
distclean-tags:
|
||||
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
|
||||
|
||||
distdir: $(DISTFILES)
|
||||
@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
|
||||
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
|
||||
list='$(DISTFILES)'; for file in $$list; do \
|
||||
case $$file in \
|
||||
$(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
|
||||
$(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
|
||||
esac; \
|
||||
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
|
||||
dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
|
||||
if test "$$dir" != "$$file" && test "$$dir" != "."; then \
|
||||
dir="/$$dir"; \
|
||||
$(mkdir_p) "$(distdir)$$dir"; \
|
||||
else \
|
||||
dir=''; \
|
||||
fi; \
|
||||
if test -d $$d/$$file; then \
|
||||
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
|
||||
cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
|
||||
fi; \
|
||||
cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
|
||||
else \
|
||||
test -f $(distdir)/$$file \
|
||||
|| cp -p $$d/$$file $(distdir)/$$file \
|
||||
|| exit 1; \
|
||||
fi; \
|
||||
done
|
||||
check-am: all-am
|
||||
check: check-am
|
||||
all-am: Makefile $(LIBRARIES)
|
||||
installdirs:
|
||||
install: install-am
|
||||
install-exec: install-exec-am
|
||||
install-data: install-data-am
|
||||
uninstall: uninstall-am
|
||||
|
||||
install-am: all-am
|
||||
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
|
||||
|
||||
installcheck: installcheck-am
|
||||
install-strip:
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
`test -z '$(STRIP)' || \
|
||||
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
|
||||
mostlyclean-generic:
|
||||
|
||||
clean-generic:
|
||||
|
||||
distclean-generic:
|
||||
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
|
||||
|
||||
maintainer-clean-generic:
|
||||
@echo "This command is intended for maintainers to use"
|
||||
@echo "it deletes files that may require special tools to rebuild."
|
||||
clean: clean-am
|
||||
|
||||
clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am
|
||||
|
||||
distclean: distclean-am
|
||||
-rm -rf ./$(DEPDIR)
|
||||
-rm -f Makefile
|
||||
distclean-am: clean-am distclean-compile distclean-generic \
|
||||
distclean-tags
|
||||
|
||||
dvi: dvi-am
|
||||
|
||||
dvi-am:
|
||||
|
||||
html: html-am
|
||||
|
||||
info: info-am
|
||||
|
||||
info-am:
|
||||
|
||||
install-data-am:
|
||||
|
||||
install-exec-am:
|
||||
|
||||
install-info: install-info-am
|
||||
|
||||
install-man:
|
||||
|
||||
installcheck-am:
|
||||
|
||||
maintainer-clean: maintainer-clean-am
|
||||
-rm -rf ./$(DEPDIR)
|
||||
-rm -f Makefile
|
||||
maintainer-clean-am: distclean-am maintainer-clean-generic
|
||||
|
||||
mostlyclean: mostlyclean-am
|
||||
|
||||
mostlyclean-am: mostlyclean-compile mostlyclean-generic
|
||||
|
||||
pdf: pdf-am
|
||||
|
||||
pdf-am:
|
||||
|
||||
ps: ps-am
|
||||
|
||||
ps-am:
|
||||
|
||||
uninstall-am: uninstall-info-am
|
||||
|
||||
.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
|
||||
clean-noinstLIBRARIES ctags distclean distclean-compile \
|
||||
distclean-generic distclean-tags distdir dvi dvi-am html \
|
||||
html-am info info-am install install-am install-data \
|
||||
install-data-am install-exec install-exec-am install-info \
|
||||
install-info-am install-man install-strip installcheck \
|
||||
installcheck-am installdirs maintainer-clean \
|
||||
maintainer-clean-generic mostlyclean mostlyclean-compile \
|
||||
mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \
|
||||
uninstall-am uninstall-info-am
|
||||
|
||||
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||
.NOEXPORT:
|
||||
@@ -0,0 +1,40 @@
|
||||
/*(LGPL)
|
||||
---------------------------------------------------------------------------
|
||||
_e_script.h - EEL source code management (Private)
|
||||
---------------------------------------------------------------------------
|
||||
* Copyright (C) 2002, David Olofson
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef _EEL__SCRIPT_H_
|
||||
#define _EEL__SCRIPT_H_
|
||||
|
||||
#include "eel.h"
|
||||
#include "e_script.h"
|
||||
|
||||
#define MAX_SCRIPTS 256
|
||||
|
||||
typedef struct script_t
|
||||
{
|
||||
char *name;
|
||||
unsigned char *data;
|
||||
unsigned len;
|
||||
} script_t;
|
||||
|
||||
extern script_t eel_scripttab[MAX_SCRIPTS];
|
||||
|
||||
|
||||
#endif /*_EEL__SCRIPT_H_*/
|
||||
+462
@@ -0,0 +1,462 @@
|
||||
/*(LGPL)
|
||||
---------------------------------------------------------------------------
|
||||
e_builtin.c - EEL built-in commands and directives
|
||||
---------------------------------------------------------------------------
|
||||
* Copyright (C) 2002, 2003, David Olofson
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#define DBG(x)
|
||||
|
||||
#include "kobolog.h"
|
||||
#include "math.h"
|
||||
#include "e_builtin.h"
|
||||
#include "e_util.h"
|
||||
#include "e_lexer.h"
|
||||
|
||||
|
||||
/*----------------------------------------------------------
|
||||
Command Callbacks
|
||||
----------------------------------------------------------*/
|
||||
|
||||
int eel_cmd_end(int argc, struct eel_data_t *argv)
|
||||
{
|
||||
DBG(log_printf(DLOG, "end;\n");)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int eel_cmd_set(int argc, struct eel_data_t *argv)
|
||||
{
|
||||
eel_symbol_t *to;
|
||||
eel_data_t *val;
|
||||
|
||||
if(eel_get_args("nV(irsce)", &to, &val) != 2)
|
||||
return -1;
|
||||
|
||||
DBG(log_printf(DLOG, "set %s, ", eel_s_stringrep(to));)
|
||||
DBG(log_printf(DLOG, "%s;\n", eel_d_stringrep(val));)
|
||||
|
||||
eel_s_set(to, val);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int eel_cmd_print(int argc, struct eel_data_t *argv)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < argc; ++i)
|
||||
{
|
||||
if(EDT_SYMREF == argv[i].type)
|
||||
switch(argv[i].value.sym->type)
|
||||
{
|
||||
case EST_CONSTANT:
|
||||
case EST_VARIABLE:
|
||||
/* Print the *value* of these... */
|
||||
log_printf(ULOG, "%s", eel_d_stringrep(
|
||||
&argv[i].value.sym->data));
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
log_printf(ULOG, "%s", eel_d_stringrep(argv + i));
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*----------------------------------------------------------
|
||||
Operator Callbacks
|
||||
----------------------------------------------------------*/
|
||||
|
||||
static inline eel_datatypes_t promote(struct eel_data_t *left,
|
||||
struct eel_data_t *right)
|
||||
{
|
||||
if(left->type == right->type)
|
||||
{
|
||||
if(left->type == EDT_INTEGER || left->type == EDT_REAL)
|
||||
return left->type;
|
||||
else
|
||||
{
|
||||
eel_error("Operands of unsupported type!");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if(left->type == EDT_INTEGER)
|
||||
{
|
||||
left->value.r = (double)left->value.i;
|
||||
left->type = EDT_REAL;
|
||||
}
|
||||
else if(left->type != EDT_REAL)
|
||||
{
|
||||
eel_error("Left hand operand of unsupported type!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(right->type == EDT_INTEGER)
|
||||
{
|
||||
right->value.r = (double)right->value.i;
|
||||
right->type = EDT_REAL;
|
||||
}
|
||||
else if(right->type != EDT_REAL)
|
||||
{
|
||||
eel_error("Right hand operand of unsupported type!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return EDT_REAL;
|
||||
}
|
||||
|
||||
|
||||
int eel_op_add(int argc, struct eel_data_t *argv)
|
||||
{
|
||||
eel_data_t *left = argv, *right = argv + 1;
|
||||
DBG(log_printf(DLOG, "add ");)
|
||||
if(argc != 2)
|
||||
{
|
||||
eel_error("Operator needs exactly two arguments!");
|
||||
return -1;
|
||||
}
|
||||
switch(promote(left, right))
|
||||
{
|
||||
case EDT_REAL:
|
||||
DBG(log_printf(DLOG, "%f, %f\n", left->value.r, right->value.r);)
|
||||
left->value.r += right->value.r;
|
||||
break;
|
||||
case EDT_INTEGER:
|
||||
DBG(log_printf(DLOG, "%d, %d\n", left->value.i, right->value.i);)
|
||||
left->value.i += right->value.i;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int eel_op_sub(int argc, struct eel_data_t *argv)
|
||||
{
|
||||
eel_data_t *left = argv, *right = argv + 1;
|
||||
DBG(log_printf(DLOG, "sub ");)
|
||||
if(argc != 2)
|
||||
{
|
||||
eel_error("Operator needs exactly two arguments!");
|
||||
return -1;
|
||||
}
|
||||
switch(promote(left, right))
|
||||
{
|
||||
case EDT_REAL:
|
||||
DBG(log_printf(DLOG, "%f, %f\n", left->value.r, right->value.r);)
|
||||
left->value.r -= right->value.r;
|
||||
break;
|
||||
case EDT_INTEGER:
|
||||
DBG(log_printf(DLOG, "%d, %d\n", left->value.i, right->value.i);)
|
||||
left->value.i -= right->value.i;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int eel_op_mul(int argc, struct eel_data_t *argv)
|
||||
{
|
||||
eel_data_t *left = argv, *right = argv + 1;
|
||||
DBG(log_printf(DLOG, "mul ");)
|
||||
if(argc != 2)
|
||||
{
|
||||
eel_error("Operator needs exactly two arguments!");
|
||||
return -1;
|
||||
}
|
||||
switch(promote(left, right))
|
||||
{
|
||||
case EDT_REAL:
|
||||
DBG(log_printf(DLOG, "%f, %f\n", left->value.r, right->value.r);)
|
||||
left->value.r *= right->value.r;
|
||||
break;
|
||||
case EDT_INTEGER:
|
||||
DBG(log_printf(DLOG, "%d, %d\n", left->value.i, right->value.i);)
|
||||
left->value.i *= right->value.i;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int eel_op_div(int argc, struct eel_data_t *argv)
|
||||
{
|
||||
eel_data_t *left = argv, *right = argv + 1;
|
||||
DBG(log_printf(DLOG, "div ");)
|
||||
if(argc != 2)
|
||||
{
|
||||
eel_error("Operator needs exactly two arguments!");
|
||||
return -1;
|
||||
}
|
||||
switch(promote(left, right))
|
||||
{
|
||||
case EDT_REAL:
|
||||
if(!right->value.r)
|
||||
{
|
||||
eel_error("Division by zero!");
|
||||
return -1;
|
||||
}
|
||||
DBG(log_printf(DLOG, "%f, %f\n", left->value.r, right->value.r);)
|
||||
left->value.r /= right->value.r;
|
||||
break;
|
||||
case EDT_INTEGER:
|
||||
if(!right->value.i)
|
||||
{
|
||||
eel_error("Division by zero!");
|
||||
return -1;
|
||||
}
|
||||
DBG(log_printf(DLOG, "%d, %d\n", left->value.i, right->value.i);)
|
||||
left->value.i /= right->value.i;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int eel_op_mod(int argc, struct eel_data_t *argv)
|
||||
{
|
||||
eel_data_t *left = argv, *right = argv + 1;
|
||||
DBG(log_printf(DLOG, "mod ");)
|
||||
if(argc != 2)
|
||||
{
|
||||
eel_error("Operator needs exactly two arguments!");
|
||||
return -1;
|
||||
}
|
||||
switch(promote(left, right))
|
||||
{
|
||||
case EDT_REAL:
|
||||
if(!right->value.r)
|
||||
{
|
||||
eel_error("Zero modulus!");
|
||||
return -1;
|
||||
}
|
||||
DBG(log_printf(DLOG, "%f, %f\n", left->value.r, right->value.r);)
|
||||
left->value.r -= right->value.r *
|
||||
floor(left->value.r / right->value.r);
|
||||
break;
|
||||
case EDT_INTEGER:
|
||||
if(!right->value.i)
|
||||
{
|
||||
eel_error("Zero modulus!");
|
||||
return -1;
|
||||
}
|
||||
DBG(log_printf(DLOG, "%d, %d\n", left->value.i, right->value.i);)
|
||||
left->value.i %= right->value.i;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int eel_op_pow(int argc, struct eel_data_t *argv)
|
||||
{
|
||||
eel_data_t *left = argv, *right = argv + 1;
|
||||
DBG(log_printf(DLOG, "pow ");)
|
||||
if(argc != 2)
|
||||
{
|
||||
eel_error("Operator needs exactly two arguments!");
|
||||
return -1;
|
||||
}
|
||||
switch(promote(left, right))
|
||||
{
|
||||
case EDT_REAL:
|
||||
DBG(log_printf(DLOG, "%f, %f\n", left->value.r, right->value.r);)
|
||||
left->value.r = pow(left->value.r, right->value.r);
|
||||
break;
|
||||
case EDT_INTEGER:
|
||||
DBG(log_printf(DLOG, "%d, %d\n", left->value.i, right->value.i);)
|
||||
left->value.i = pow(left->value.i, right->value.i);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*----------------------------------------------------------
|
||||
Directive Callbacks
|
||||
----------------------------------------------------------*/
|
||||
|
||||
int eel_dir_include(void)
|
||||
{
|
||||
int h, res;
|
||||
const char *fn;
|
||||
|
||||
if(eel_parse_args(" ", '\n') < 0)
|
||||
return -1;
|
||||
|
||||
if(eel_get_args("s", &fn) < 0)
|
||||
return -1;
|
||||
|
||||
h = eel_load(fn);
|
||||
if(h < 0)
|
||||
{
|
||||
eel_error("Couldn't include file \"%s\"!", fn);
|
||||
return -1;
|
||||
}
|
||||
res = eel_run(h);
|
||||
eel_free(h);
|
||||
|
||||
if(res < 0)
|
||||
return res;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int eel_dir_define(void)
|
||||
{
|
||||
eel_symbol_t *to;
|
||||
eel_data_t *val;
|
||||
int res;
|
||||
|
||||
if(eel_parse_args(" ", '\n') < 0)
|
||||
return -1;
|
||||
|
||||
res = eel_get_args("n[V(irsce)]", &to, &val);
|
||||
|
||||
if(res < 0)
|
||||
return -1;
|
||||
|
||||
switch(res)
|
||||
{
|
||||
case 1:
|
||||
DBG(log_printf(DLOG, "#define\t%s\n", eel_s_stringrep(to));)
|
||||
to->data.type = EDT_ILLEGAL;
|
||||
to->data.value.i = 0;
|
||||
to->type = EST_CONSTANT;
|
||||
break;
|
||||
case 2:
|
||||
DBG(log_printf(DLOG, "#define\t%s\t%s\n",
|
||||
eel_s_stringrep(to), eel_d_stringrep(val));)
|
||||
eel_s_set(to, val);
|
||||
to->type = EST_CONSTANT;
|
||||
break;
|
||||
default:
|
||||
eel_error("Expected either one or two arguments!");
|
||||
return -1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/*----------------------------------------------------------
|
||||
Special Callbacks
|
||||
----------------------------------------------------------*/
|
||||
|
||||
static int _proc_func(void)
|
||||
{
|
||||
const char *funcname;
|
||||
eel_symbol_t *s;
|
||||
int tk, res;
|
||||
|
||||
/* Get function name */
|
||||
tk = eel_lex(0);
|
||||
if(tk != TK_NEWSYM)
|
||||
{
|
||||
eel_error("Function/procedure name must be unique!");
|
||||
return -1;
|
||||
}
|
||||
funcname = eel_current.lval->value.s;
|
||||
|
||||
/* Create function symbol */
|
||||
s = eel_s_new(funcname, EST_FUNCTION);
|
||||
if(!s)
|
||||
{
|
||||
eel_error("INTERNAL ERROR: Failed to create "
|
||||
"function/procedure symbol!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check argument list */
|
||||
if(eel_lex(0) != '(')
|
||||
{
|
||||
eel_error("Expected '('!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Store the start of the *argument list*... :-) */
|
||||
s->data.value.a = bio_tell(eel_current.bio);
|
||||
s->token = eel_current.script;
|
||||
eel_push_scope();
|
||||
res = eel_parse_args(",", ')');
|
||||
eel_pop_scope();
|
||||
if(res < 0)
|
||||
return -1;
|
||||
|
||||
DBG(log_printf(DLOG, "Function/procedure '%s' defined; starting at %d.\n",
|
||||
s->name, s->data.value.a);)
|
||||
|
||||
/* Find start of body ("the code") */
|
||||
if(eel_lex(0) != '{')
|
||||
{
|
||||
eel_error("Expected '{'!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int eel_spec_function(void)
|
||||
{
|
||||
int c;
|
||||
|
||||
if(_proc_func() < 0)
|
||||
return -1;
|
||||
|
||||
/* QUICK HACK: Skip function body */
|
||||
while((c = bio_getchar(eel_current.bio)) != '}')
|
||||
if(EOF == c)
|
||||
{
|
||||
eel_error("EOF inside function body!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int eel_spec_procedure(void)
|
||||
{
|
||||
int c;
|
||||
|
||||
if(_proc_func() < 0)
|
||||
return -1;
|
||||
|
||||
/* QUICK HACK: Skip procedure body */
|
||||
while((c = bio_getchar(eel_current.bio)) != '}')
|
||||
if(EOF == c)
|
||||
{
|
||||
eel_error("EOF inside procedure body!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*(LGPL)
|
||||
---------------------------------------------------------------------------
|
||||
e_builtin.c - EEL built-in commands and directives
|
||||
---------------------------------------------------------------------------
|
||||
* Copyright (C) 2002, David Olofson
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef _EEL_BUILTIN_H_
|
||||
#define _EEL_BUILTIN_H_
|
||||
|
||||
#include "eel.h"
|
||||
|
||||
/*----------------------------------------------------------
|
||||
Command Callbacks
|
||||
----------------------------------------------------------*/
|
||||
int eel_cmd_end(int argc, struct eel_data_t *argv);
|
||||
int eel_cmd_set(int argc, struct eel_data_t *argv);
|
||||
int eel_cmd_print(int argc, struct eel_data_t *argv);
|
||||
|
||||
|
||||
/*----------------------------------------------------------
|
||||
Operator Callbacks
|
||||
----------------------------------------------------------*/
|
||||
int eel_op_add(int argc, struct eel_data_t *argv);
|
||||
int eel_op_sub(int argc, struct eel_data_t *argv);
|
||||
int eel_op_mul(int argc, struct eel_data_t *argv);
|
||||
int eel_op_div(int argc, struct eel_data_t *argv);
|
||||
int eel_op_mod(int argc, struct eel_data_t *argv);
|
||||
int eel_op_pow(int argc, struct eel_data_t *argv);
|
||||
|
||||
|
||||
/*----------------------------------------------------------
|
||||
Directive Callbacks
|
||||
----------------------------------------------------------*/
|
||||
int eel_dir_include(void);
|
||||
int eel_dir_define(void);
|
||||
|
||||
|
||||
/*----------------------------------------------------------
|
||||
Special Callbacks
|
||||
----------------------------------------------------------*/
|
||||
int eel_spec_function(void);
|
||||
int eel_spec_procedure(void);
|
||||
|
||||
#endif /*_EEL_BUILTIN_H_*/
|
||||
+1023
File diff suppressed because it is too large
Load Diff
+419
@@ -0,0 +1,419 @@
|
||||
/*(LGPL)
|
||||
---------------------------------------------------------------------------
|
||||
e_lexer.c - EEL engine lexer
|
||||
---------------------------------------------------------------------------
|
||||
* Copyright (C) 2002, David Olofson
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "e_lexer.h"
|
||||
#include "e_util.h"
|
||||
|
||||
|
||||
int eel_get_unique_token()
|
||||
{
|
||||
static int last = TK_USER;
|
||||
return last++;
|
||||
}
|
||||
|
||||
|
||||
static char *lexbuf = NULL;
|
||||
static int lexbuf_length = 0;
|
||||
|
||||
|
||||
static int lexbuf_realloc(int len)
|
||||
{
|
||||
char *nsb;
|
||||
lexbuf_length = len * 5 / 4;
|
||||
nsb = (char *)realloc(lexbuf, lexbuf_length + 1);
|
||||
if(!nsb)
|
||||
{
|
||||
eel_error("EEL lexer out of memory!");
|
||||
return -1;
|
||||
}
|
||||
lexbuf = nsb;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static inline int lexbuf_bump(int len)
|
||||
{
|
||||
if(len >= lexbuf_length)
|
||||
return lexbuf_realloc(len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void eel_lexer_cleanup(void)
|
||||
{
|
||||
if(eel_current.lval)
|
||||
{
|
||||
eel_d_freestring(eel_current.lval);
|
||||
free(eel_current.lval);
|
||||
eel_current.lval = NULL;
|
||||
}
|
||||
free(lexbuf);
|
||||
lexbuf = NULL;
|
||||
lexbuf_length = 0;
|
||||
}
|
||||
|
||||
|
||||
static int skipwhite(int report_eoln)
|
||||
{
|
||||
int c;
|
||||
/* Ignore whitespace and get first nonwhite character. */
|
||||
while((c = bio_getchar(eel_current.bio)) == ' ' || c == '\t' ||
|
||||
c == '\r' || c == '\n')
|
||||
if((c == '\n') && report_eoln)
|
||||
return c;
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
static eel_data_t *newdata(eel_datatypes_t type)
|
||||
{
|
||||
eel_data_t *d = (eel_data_t *)calloc(1, sizeof(eel_data_t));
|
||||
if(!d)
|
||||
return NULL;
|
||||
d->type = type;
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
static int get_figure(bio_file_t *h, int base)
|
||||
{
|
||||
int n = bio_getchar(h);
|
||||
if(n >= '0' && n <= '9')
|
||||
n -= '0';
|
||||
else if(n >= 'a' && n <= 'z')
|
||||
n -= 'a';
|
||||
else if(n >= 'A' && n <= 'Z')
|
||||
n -= 'A';
|
||||
else
|
||||
return -1;
|
||||
if(n >= base)
|
||||
return -1;
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
static int get_num(bio_file_t *h, int base, int figures)
|
||||
{
|
||||
int value = 0;
|
||||
while(figures--)
|
||||
{
|
||||
int n = get_figure(h, base);
|
||||
if(n < 0)
|
||||
return n;
|
||||
value *= base;
|
||||
value += n;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Parse quoted string.
|
||||
* C printf "backslash codes" are supported,
|
||||
* as well as "\dXXX", for decimal codes.
|
||||
*/
|
||||
static int parse_string(bio_file_t *h)
|
||||
{
|
||||
int c, len = 0;
|
||||
while((c = bio_getchar(h)) != '"')
|
||||
{
|
||||
switch(c)
|
||||
{
|
||||
case EOF:
|
||||
eel_error("EOF inside string literal!");
|
||||
return TK_ERROR;
|
||||
case '\\':
|
||||
c = bio_getchar(h);
|
||||
switch(c)
|
||||
{
|
||||
case EOF:
|
||||
eel_error("EOF inside string escape sequence!");
|
||||
return -1;
|
||||
case '0':
|
||||
c = get_num(h, 8, 3);
|
||||
if(c < 0)
|
||||
{
|
||||
eel_error("Illegal octal figure!");
|
||||
return TK_ERROR;
|
||||
}
|
||||
break;
|
||||
case 'a':
|
||||
c = '\a';
|
||||
break;
|
||||
case 'b':
|
||||
c = '\b';
|
||||
break;
|
||||
case 'c':
|
||||
c = '\0';
|
||||
break;
|
||||
case 'd':
|
||||
c = get_num(h, 10, 2);
|
||||
if(c < 0)
|
||||
{
|
||||
eel_error("Illegal decimal figure!");
|
||||
return TK_ERROR;
|
||||
}
|
||||
break;
|
||||
case 'f':
|
||||
c = '\f';
|
||||
break;
|
||||
case 'n':
|
||||
c = '\n';
|
||||
break;
|
||||
case 'r':
|
||||
c = '\r';
|
||||
break;
|
||||
case 't':
|
||||
c = '\t';
|
||||
break;
|
||||
case 'v':
|
||||
c = '\v';
|
||||
break;
|
||||
case 'x':
|
||||
c = get_num(h, 16, 2);
|
||||
if(c < 0)
|
||||
{
|
||||
eel_error("Illegal hex figure!");
|
||||
return TK_ERROR;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
lexbuf_bump(len + 1);
|
||||
lexbuf[len++] = c;
|
||||
}
|
||||
lexbuf[len] = 0;
|
||||
eel_current.lval = newdata(EDT_STRING);
|
||||
if(!eel_current.lval)
|
||||
return TK_ERROR;
|
||||
eel_d_setstring(eel_current.lval, lexbuf);
|
||||
return TK_STRN;
|
||||
}
|
||||
|
||||
|
||||
static inline int token(int tk)
|
||||
{
|
||||
eel_current.token = tk;
|
||||
return tk;
|
||||
}
|
||||
|
||||
/*
|
||||
* Pass 1 for 'report_eoln' to get '\n' back whenever a
|
||||
* newline occurs in the source.
|
||||
*
|
||||
* Note that newlines inside comments are *always* treated
|
||||
* as white space!
|
||||
*/
|
||||
int eel_lex(int report_eoln)
|
||||
{
|
||||
int c, prevc;
|
||||
int negative = 0, directive = 0;
|
||||
bio_file_t *h = eel_current.bio;
|
||||
eel_symbol_t *s;
|
||||
|
||||
/* Handle eel_unlex() pushbacks */
|
||||
if(eel_current.unlexed)
|
||||
{
|
||||
eel_current.unlexed = 0;
|
||||
return eel_current.token;
|
||||
}
|
||||
|
||||
/* In case someone should ignore an lval... */
|
||||
if(eel_current.lval)
|
||||
{
|
||||
eel_d_freestring(eel_current.lval);
|
||||
free(eel_current.lval);
|
||||
eel_current.lval = NULL;
|
||||
}
|
||||
|
||||
while(1)
|
||||
{
|
||||
c = skipwhite(report_eoln);
|
||||
if(c == EOF)
|
||||
return token(0);
|
||||
|
||||
/* /X comment tokens */
|
||||
if(c == '/')
|
||||
{
|
||||
switch ((c = bio_getchar(h)))
|
||||
{
|
||||
case '/': /* C++ style single line comment */
|
||||
while(EOF != (c = bio_getchar(h)))
|
||||
if('\n' == c)
|
||||
break;
|
||||
continue;
|
||||
case '*': /* C style comment */
|
||||
prevc = 0;
|
||||
while(EOF != (c = bio_getchar(h)))
|
||||
{
|
||||
if(('/' == c) && ('*' == prevc))
|
||||
break;
|
||||
else
|
||||
prevc = c;
|
||||
}
|
||||
continue;
|
||||
default:
|
||||
bio_ungetc(h);
|
||||
c = '/';
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Char starts a number => parse the number.
|
||||
* Note: This never returns an EDT_INTEGER!
|
||||
*/
|
||||
if(c == '.' || isdigit(c))
|
||||
{
|
||||
bio_ungetc(h);
|
||||
eel_current.lval = newdata(EDT_REAL);
|
||||
if(!eel_current.lval)
|
||||
return token(TK_ERROR);
|
||||
eel_current.lval->value.r = bio_strtod(h);
|
||||
if(negative)
|
||||
eel_current.lval->value.r = -eel_current.lval->value.r;
|
||||
return token(TK_RNUM);
|
||||
}
|
||||
|
||||
negative = 0;
|
||||
|
||||
/*
|
||||
* (Multi)character literal (cast to integer)
|
||||
* Note that this is always little endian, so
|
||||
* it's safe to use for "FourCC" identifiers
|
||||
* and the like.
|
||||
*/
|
||||
if('\'' == c)
|
||||
{
|
||||
eel_current.lval = newdata(EDT_INTEGER);
|
||||
if(!eel_current.lval)
|
||||
return token(TK_ERROR);
|
||||
eel_current.lval->value.i = 0;
|
||||
while((c = bio_getchar(h)) != '\'')
|
||||
{
|
||||
if(EOF == c)
|
||||
{
|
||||
eel_error("EOF inside character literal!");
|
||||
return token(TK_ERROR);
|
||||
}
|
||||
eel_current.lval->value.i <<= 8;
|
||||
eel_current.lval->value.i |= c;
|
||||
}
|
||||
return token(TK_INUM);
|
||||
}
|
||||
|
||||
/* String literal */
|
||||
if('"' == c)
|
||||
return token(parse_string(h));
|
||||
|
||||
/* Check for "preprocessor" directives */
|
||||
if('#' == c)
|
||||
{
|
||||
directive = 1;
|
||||
c = bio_getchar(h);
|
||||
}
|
||||
|
||||
/* Char starts an identifier => read the name. */
|
||||
if(isalpha(c) || ('_' == c))
|
||||
{
|
||||
int len = 1;
|
||||
int start = bio_tell(h) - 1;
|
||||
while((isalnum(c = bio_getchar(h)) || ('_' == c)) && (EOF != c))
|
||||
++len;
|
||||
|
||||
if(lexbuf_bump(len) < 0)
|
||||
return token(TK_ERROR);
|
||||
bio_seek(h, start, SEEK_SET);
|
||||
bio_read(h, lexbuf, len);
|
||||
lexbuf[len] = '\0';
|
||||
|
||||
if(directive)
|
||||
{
|
||||
directive = 0;
|
||||
s = eel_s_find_n_t(NULL, lexbuf, EST_DIRECTIVE);
|
||||
if(!s)
|
||||
{
|
||||
eel_error("Unknown directive '%s'!",
|
||||
lexbuf);
|
||||
return token(TK_ERROR);
|
||||
}
|
||||
if(s->type != EST_DIRECTIVE)
|
||||
{
|
||||
eel_error("Preprocessor directive expected!");
|
||||
return token(TK_ERROR);
|
||||
}
|
||||
eel_current.lval = newdata(EDT_SYMREF);
|
||||
eel_current.lval->value.sym = s;
|
||||
return token(TK_SYMREF);
|
||||
}
|
||||
else
|
||||
{
|
||||
s = eel_s_find(NULL, lexbuf);
|
||||
if(s)
|
||||
{
|
||||
eel_current.lval = newdata(EDT_SYMREF);
|
||||
eel_current.lval->value.sym = s;
|
||||
return token(TK_SYMREF);
|
||||
}
|
||||
else
|
||||
{
|
||||
eel_current.lval = newdata(EDT_SYMNAME);
|
||||
eel_d_setstring(eel_current.lval, lexbuf);
|
||||
return token(TK_NEWSYM);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Look for valid operator characters */
|
||||
if(strchr("+-*/^<>~&%@!|$", (char)c))
|
||||
{
|
||||
lexbuf[0] = c;
|
||||
lexbuf[1] = 0;
|
||||
s = eel_s_find_n_t(NULL, lexbuf, EST_OPERATOR);
|
||||
if(!s)
|
||||
{
|
||||
eel_error("Unknown operator '%s'!", lexbuf);
|
||||
return token(TK_ERROR);
|
||||
}
|
||||
eel_current.lval = newdata(EDT_SYMREF);
|
||||
eel_current.lval->value.sym = s;
|
||||
return token(TK_SYMREF);
|
||||
}
|
||||
|
||||
return token(c);
|
||||
}
|
||||
|
||||
|
||||
void eel_unlex(void)
|
||||
{
|
||||
eel_current.unlexed = 1;
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*(LGPL)
|
||||
---------------------------------------------------------------------------
|
||||
e_lexer.h - EEL engine lexer
|
||||
---------------------------------------------------------------------------
|
||||
* Copyright (C) 2002, David Olofson
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef _EEL_LEXER_H_
|
||||
#define _EEL_LEXER_H_
|
||||
|
||||
#include "eel.h"
|
||||
|
||||
|
||||
/*----------------------------------------------------------
|
||||
Tokens and Unique User Token management
|
||||
----------------------------------------------------------*/
|
||||
|
||||
/* Errors... */
|
||||
#define TK_ERROR -1 /* Lexer complains about something */
|
||||
|
||||
/* Immediate arguments */
|
||||
#define TK_RNUM 300 /* Real number */
|
||||
#define TK_INUM 301 /* Integer number */
|
||||
#define TK_STRN 302 /* String literal */
|
||||
|
||||
/* Symbol reference */
|
||||
#define TK_SYMREF 303
|
||||
|
||||
/* New symbol */
|
||||
#define TK_NEWSYM 304
|
||||
|
||||
#define TK_USER 1024
|
||||
|
||||
int eel_get_unique_token();
|
||||
|
||||
|
||||
/*----------------------------------------------------------
|
||||
The Lexer
|
||||
----------------------------------------------------------*/
|
||||
/* Get next "token" */
|
||||
int eel_lex(int report_eoln);
|
||||
|
||||
/*
|
||||
* Push back last token + lval.
|
||||
* Works only for *one* token per context!
|
||||
*/
|
||||
void eel_unlex(void);
|
||||
|
||||
void eel_lexer_cleanup(void);
|
||||
|
||||
#endif /*_EEL_LEXER_H_*/
|
||||
@@ -0,0 +1,60 @@
|
||||
/*(LGPL)
|
||||
---------------------------------------------------------------------------
|
||||
e_path.c - EEL file
|
||||
---------------------------------------------------------------------------
|
||||
* Copyright (C) 2002, David Olofson
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "eel.h"
|
||||
|
||||
|
||||
/*----------------------------------------------------------
|
||||
File System Interface (Hah! :-)
|
||||
----------------------------------------------------------*/
|
||||
|
||||
static char *_eel_path = NULL;
|
||||
|
||||
|
||||
void eel_set_path(const char *path)
|
||||
{
|
||||
if(_eel_path)
|
||||
free(_eel_path);
|
||||
if(path)
|
||||
_eel_path = strdup(path);
|
||||
else
|
||||
_eel_path = NULL;
|
||||
}
|
||||
|
||||
|
||||
const char *eel_path(void)
|
||||
{
|
||||
if(!_eel_path)
|
||||
{
|
||||
#if defined(WIN32)
|
||||
eel_set_path("");
|
||||
#elif defined(MACOS)
|
||||
eel_set_path("");
|
||||
#else
|
||||
eel_set_path("./");
|
||||
#endif
|
||||
}
|
||||
return _eel_path;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
/*(LGPL)
|
||||
---------------------------------------------------------------------------
|
||||
e_register.c - EEL extension registry
|
||||
---------------------------------------------------------------------------
|
||||
* Copyright (C) 2002, David Olofson
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "e_register.h"
|
||||
#include "e_symtab.h"
|
||||
#include "e_lexer.h"
|
||||
|
||||
eel_symbol_t *_register(const char *name, eel_symtypes_t stype,
|
||||
eel_datatypes_t type)
|
||||
{
|
||||
eel_symbol_t *s = eel_s_new(name, stype);
|
||||
if(!s)
|
||||
return (eel_symbol_t *)0;
|
||||
s->data.type = type;
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
int eel_register_operator(const char *name, eel_operator_cb_t handler,
|
||||
int priority, int retargs, int preargs)
|
||||
{
|
||||
eel_symbol_t *s = _register(name, EST_OPERATOR, EDT_OPERATOR);
|
||||
if(!s)
|
||||
return -1;
|
||||
|
||||
s->token = eel_get_unique_token();
|
||||
s->data.value.op.priority = priority;
|
||||
s->data.value.op.retargs = retargs;
|
||||
s->data.value.op.preargs = preargs;
|
||||
s->data.value.op.cb = handler;
|
||||
return s->token;
|
||||
}
|
||||
|
||||
|
||||
int eel_register_enum_class(void)
|
||||
{
|
||||
return eel_get_unique_token();
|
||||
}
|
||||
|
||||
|
||||
int eel_register_enum(int eclass, const char *name, int value)
|
||||
{
|
||||
eel_symbol_t *s = _register(name, EST_ENUM, EDT_INTEGER);
|
||||
if(!s)
|
||||
return -1;
|
||||
s->token = eclass;
|
||||
s->data.value.i = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int eel_register_directive(const char *name, eel_parser_cb_t parser)
|
||||
{
|
||||
eel_symbol_t *s = _register(name, EST_DIRECTIVE, EDT_DIRECTIVE);
|
||||
if(!s)
|
||||
return -1;
|
||||
s->token = eel_get_unique_token();
|
||||
s->data.value.parse = parser;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int eel_register_special(const char *name, eel_parser_cb_t parser)
|
||||
{
|
||||
eel_symbol_t *s = _register(name, EST_SPECIAL, EDT_SPECIAL);
|
||||
if(!s)
|
||||
return -1;
|
||||
s->token = eel_get_unique_token();
|
||||
s->data.value.parse = parser;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*(LGPL)
|
||||
---------------------------------------------------------------------------
|
||||
e_register.h - EEL extension registry
|
||||
---------------------------------------------------------------------------
|
||||
* Copyright (C) 2002, David Olofson
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef _EEL_REGISTER_H_
|
||||
#define _EEL_REGISTER_H_
|
||||
|
||||
#include "eel.h"
|
||||
|
||||
/*----------------------------------------------------------
|
||||
Language Extension API
|
||||
----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Register an EEL operator. ("The real thing")
|
||||
*
|
||||
* (This is the "direct to the metal" interface; you may want
|
||||
* to use eel_register_cmd_operator(), eel_register_func_operator()
|
||||
* or eel_register_math_operator() instead most of the time.)
|
||||
*
|
||||
* The callback should check the types and number of
|
||||
* arguments (easily done with eel_get_args()), and return
|
||||
* 1 upon success, -1 in case of an error, or 0 if the script
|
||||
* should be terminated.
|
||||
*
|
||||
* Operator precendence in expressions is controlled by means
|
||||
* of operator priorities specified when operators are
|
||||
* registered. EEL built-in operators also have priorities,
|
||||
* and these are of course put in relation to the ones
|
||||
* specified for extension operators;
|
||||
* '=' (assignment) 0 (always lowest)
|
||||
* '+' '-' (add, sub) 10
|
||||
* '*' '/' '%' (mul, div, mod) 20
|
||||
* '^' (power) 30
|
||||
* (command and function operators) 100
|
||||
*
|
||||
* 'retargs' is the number of return arguments, and 'preargs'
|
||||
* is the number of arguments that must be placed *before* the
|
||||
* operator token. (Only normal, "post operator token" argument
|
||||
* lists can be variable length!)
|
||||
*
|
||||
* The return value is the command's unique token, or a
|
||||
* negative value upon failure.
|
||||
*/
|
||||
int eel_register_operator(const char *name, eel_operator_cb_t handler,
|
||||
int priority, int retargs, int preargs);
|
||||
|
||||
/* Register a new enum class. The unique token is returned. */
|
||||
int eel_register_enum_class(void);
|
||||
|
||||
/*
|
||||
* Add enum constant to specified enum class.
|
||||
*
|
||||
* A negative value is returned if the operation fails.
|
||||
*/
|
||||
int eel_register_enum(int eclass, const char *name, int value);
|
||||
|
||||
/*
|
||||
* Register a directive.
|
||||
*
|
||||
* A directive is similar to a command, but can optionally be
|
||||
* invoked with a '#' before it's name. It does argument
|
||||
* parsing itself, which provides more detailed control.
|
||||
*
|
||||
* A negative value is returned if the operation fails.
|
||||
*/
|
||||
int eel_register_directive(const char *name, int (*parser)(void));
|
||||
|
||||
/*
|
||||
* Register a special.
|
||||
*
|
||||
* A special does argument parsing itself, like a directive,
|
||||
* but the #<name> syntax is not valid.
|
||||
*
|
||||
* A negative value is returned if the operation fails.
|
||||
*/
|
||||
int eel_register_special(const char *name, int (*parser)(void));
|
||||
|
||||
#endif /*_EEL_REGISTER_H_*/
|
||||
+159
@@ -0,0 +1,159 @@
|
||||
/*(LGPL)
|
||||
---------------------------------------------------------------------------
|
||||
e_script.c - EEL source code management
|
||||
---------------------------------------------------------------------------
|
||||
* Copyright (C) 2002, David Olofson
|
||||
* Copyright (C) 2002, Florian Schulze <fs@crowproductions.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "_e_script.h"
|
||||
#include "e_util.h"
|
||||
|
||||
#define DBG(x)
|
||||
|
||||
|
||||
/*----------------------------------------------------------
|
||||
Script source management
|
||||
----------------------------------------------------------*/
|
||||
|
||||
script_t eel_scripttab[MAX_SCRIPTS];
|
||||
|
||||
int eel_script_alloc()
|
||||
{
|
||||
int h = 0;
|
||||
while(h < MAX_SCRIPTS)
|
||||
{
|
||||
if(!eel_scripttab[h].data)
|
||||
return h;
|
||||
++h;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int eel_load(const char *filename)
|
||||
{
|
||||
FILE *f;
|
||||
int h = eel_script_alloc();
|
||||
if(h < 0)
|
||||
return h;
|
||||
|
||||
/* Construct full name with path */
|
||||
eel_scripttab[h].name = malloc(strlen(filename) +
|
||||
strlen(eel_path()) + 2);
|
||||
if(!eel_scripttab[h].name)
|
||||
return -1;
|
||||
strcpy(eel_scripttab[h].name, eel_path());
|
||||
#ifdef WIN32
|
||||
strcat(eel_scripttab[h].name, "\\");
|
||||
#elif defined MACOS
|
||||
strcat(eel_scripttab[h].name, ":");
|
||||
#else
|
||||
strcat(eel_scripttab[h].name, "/");
|
||||
#endif
|
||||
strcat(eel_scripttab[h].name, filename);
|
||||
|
||||
f = fopen(eel_scripttab[h].name, "rb");
|
||||
if(!f)
|
||||
return -1;
|
||||
|
||||
if(fseek(f, 0, SEEK_END) == 0)
|
||||
{
|
||||
eel_scripttab[h].len = ftell(f);
|
||||
if(fseek(f, 0, SEEK_SET) == 0)
|
||||
{
|
||||
eel_scripttab[h].data = (unsigned char *)malloc(
|
||||
eel_scripttab[h].len + 1);
|
||||
if(eel_scripttab[h].data)
|
||||
{
|
||||
if(fread(eel_scripttab[h].data,
|
||||
eel_scripttab[h].len,
|
||||
1, f) == 1)
|
||||
{
|
||||
fclose(f);
|
||||
DBG(log_printf(DLOG, "Loaded script \"%s\"."
|
||||
" (Handle %d)\n",
|
||||
eel_scripttab[h].name,
|
||||
h);)
|
||||
return h;
|
||||
}
|
||||
DBG(printf("eel_load(): Read error!\n");)
|
||||
eel_free(h);
|
||||
}
|
||||
DBG(printf("eel_load(): Memory allocation error!\n");)
|
||||
}
|
||||
DBG(printf("eel_load(): Rewind error!\n");)
|
||||
}
|
||||
DBG(printf("eel_load(): Seek-to-end error!\n");)
|
||||
fclose(f);
|
||||
return -2;
|
||||
}
|
||||
|
||||
|
||||
int eel_load_from_mem(const char *script, unsigned len)
|
||||
{
|
||||
char name_buffer[128];
|
||||
int h = eel_script_alloc();
|
||||
if(h < 0)
|
||||
return h;
|
||||
|
||||
/* Construct name */
|
||||
snprintf(name_buffer, 127, "mem_script (%p, %u)", script, len);
|
||||
name_buffer[127] = '\0';
|
||||
eel_scripttab[h].name = (char *)malloc(strlen(name_buffer) + 1);
|
||||
if(!eel_scripttab[h].name)
|
||||
return -1;
|
||||
|
||||
strcpy(eel_scripttab[h].name, name_buffer);
|
||||
|
||||
eel_scripttab[h].len = len;
|
||||
eel_scripttab[h].data =
|
||||
(unsigned char *)malloc(eel_scripttab[h].len + 1);
|
||||
if(!eel_scripttab[h].data)
|
||||
{
|
||||
DBG(printf("eel_load_from_mem(): Memory allocation error!\n");)
|
||||
return -2;
|
||||
}
|
||||
memcpy(eel_scripttab[h].data, script, len);
|
||||
DBG(printf("Loaded script \"%s\" (Handle %d)\n",
|
||||
eel_scripttab[h].name, h);)
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
void eel_free(int handle)
|
||||
{
|
||||
if(handle < 0)
|
||||
return;
|
||||
if(handle > MAX_SCRIPTS)
|
||||
return;
|
||||
if(!eel_scripttab[handle].data)
|
||||
return;
|
||||
|
||||
DBG(printf("Freeing script \"%s\". (Handle %d)\n",
|
||||
eel_scripttab[handle].name, handle);)
|
||||
free(eel_scripttab[handle].data);
|
||||
eel_scripttab[handle].data = NULL;
|
||||
free(eel_scripttab[handle].name);
|
||||
eel_scripttab[handle].name = NULL;
|
||||
eel_scripttab[handle].len = 0;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*(LGPL)
|
||||
---------------------------------------------------------------------------
|
||||
e_script.h - EEL source code management (API)
|
||||
---------------------------------------------------------------------------
|
||||
* Copyright (C) 2002, David Olofson
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef _EEL_SCRIPT_H_
|
||||
#define _EEL_SCRIPT_H_
|
||||
|
||||
int eel_load(const char *filename);
|
||||
int eel_load_from_mem(const char *script, unsigned len);
|
||||
void eel_free(int handle);
|
||||
|
||||
#endif /*_EEL_SCRIPT_H_*/
|
||||
+444
@@ -0,0 +1,444 @@
|
||||
/*(LGPL)
|
||||
---------------------------------------------------------------------------
|
||||
symtab.c - Simple symbol table for EEL
|
||||
---------------------------------------------------------------------------
|
||||
* Copyright (C) 2000-2003, 2007 David Olofson
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "kobolog.h"
|
||||
#include "e_symtab.h"
|
||||
|
||||
#define DBG(x)
|
||||
|
||||
#define STRINGREP_SIZE 128
|
||||
|
||||
#define MAX_SCOPES 32
|
||||
|
||||
|
||||
/*------------------------------------------------
|
||||
Data container
|
||||
------------------------------------------------*/
|
||||
|
||||
int eel_d_copy(eel_data_t *data, const eel_data_t *from)
|
||||
{
|
||||
eel_d_freestring(data);
|
||||
switch (from->type)
|
||||
{
|
||||
case EDT_ILLEGAL:
|
||||
case EDT_REAL:
|
||||
case EDT_INTEGER:
|
||||
case EDT_CADDR:
|
||||
case EDT_SYMREF:
|
||||
case EDT_SYMTAB:
|
||||
case EDT_OPERATOR:
|
||||
case EDT_DIRECTIVE:
|
||||
case EDT_SPECIAL:
|
||||
*data = *from;
|
||||
return 1;
|
||||
case EDT_STRING:
|
||||
case EDT_SYMNAME:
|
||||
data->type = from->type;
|
||||
return eel_d_setstring(data, from->value.s);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int eel_d_setstring(eel_data_t *data, const char *s)
|
||||
{
|
||||
if((EDT_STRING == data->type) || (EDT_SYMNAME == data->type))
|
||||
free(data->value.s);
|
||||
else
|
||||
data->type = EDT_STRING;
|
||||
data->value.s = (char *)malloc(strlen(s) + 1);
|
||||
if(data->value.s < 0)
|
||||
return -1;
|
||||
strcpy(data->value.s, s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void eel_d_grabstring(eel_data_t *data, char *s)
|
||||
{
|
||||
if((EDT_STRING == data->type) || (EDT_SYMNAME == data->type))
|
||||
free(data->value.s);
|
||||
else
|
||||
data->type = EDT_STRING;
|
||||
data->value.s = s;
|
||||
}
|
||||
|
||||
void eel_d_freestring(eel_data_t *data)
|
||||
{
|
||||
if((data->type != EDT_STRING) && (data->type != EDT_SYMNAME))
|
||||
return;
|
||||
free(data->value.s);
|
||||
data->value.s = 0;
|
||||
}
|
||||
|
||||
/* NOTE: Output string only valid until next call. */
|
||||
const char *eel_d_stringrep(eel_data_t * data)
|
||||
{
|
||||
static char buf[STRINGREP_SIZE];
|
||||
switch (data->type)
|
||||
{
|
||||
case EDT_ILLEGAL:
|
||||
return "<illegal data>";
|
||||
case EDT_REAL:
|
||||
snprintf(buf, STRINGREP_SIZE, "%.10g", data->value.r);
|
||||
return buf;
|
||||
case EDT_INTEGER:
|
||||
snprintf(buf, STRINGREP_SIZE, "%d", data->value.i);
|
||||
return buf;
|
||||
case EDT_STRING:
|
||||
case EDT_SYMNAME:
|
||||
if(data->value.s)
|
||||
{
|
||||
strncpy(buf, data->value.s, STRINGREP_SIZE);
|
||||
return buf;
|
||||
}
|
||||
else
|
||||
return "<undef string>";
|
||||
case EDT_SYMTAB:
|
||||
return "<symbol table reference>";
|
||||
case EDT_CADDR:
|
||||
snprintf(buf, STRINGREP_SIZE, "%x", data->value.a);
|
||||
return buf;
|
||||
case EDT_SYMREF:
|
||||
return eel_s_stringrep(data->value.sym);
|
||||
case EDT_OPERATOR:
|
||||
if(data->value.s)
|
||||
{
|
||||
snprintf(buf, STRINGREP_SIZE, "(%s)",
|
||||
data->value.s);
|
||||
return buf;
|
||||
}
|
||||
else
|
||||
return "<unnamed operator>";
|
||||
case EDT_DIRECTIVE:
|
||||
if(data->value.s)
|
||||
{
|
||||
snprintf(buf, STRINGREP_SIZE, "(#%s)",
|
||||
data->value.s);
|
||||
return buf;
|
||||
}
|
||||
else
|
||||
return "<unnamed directive>";
|
||||
case EDT_SPECIAL:
|
||||
if(data->value.s)
|
||||
{
|
||||
snprintf(buf, STRINGREP_SIZE, "(%s)",
|
||||
data->value.s);
|
||||
return buf;
|
||||
}
|
||||
else
|
||||
return "<unnamed special>";
|
||||
default:
|
||||
return "<internal error: undef data type>";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------
|
||||
Symbol table
|
||||
------------------------------------------------*/
|
||||
|
||||
/* The symbol table: a chain of `struct symrec'. */
|
||||
static eel_symbol_t *eel_s_table[MAX_SCOPES];
|
||||
|
||||
static int _current_scope = 0;
|
||||
static int _deepest_scope = 0;
|
||||
|
||||
|
||||
int eel_s_open(void)
|
||||
{
|
||||
memset(eel_s_table, 0, sizeof(eel_s_table));
|
||||
_current_scope = 0;
|
||||
_deepest_scope = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void eel_s_close(void)
|
||||
{
|
||||
eel_s_freeall();
|
||||
}
|
||||
|
||||
|
||||
eel_symbol_t *eel_s_new(const char *name, eel_symtypes_t type)
|
||||
{
|
||||
eel_symbol_t *sym;
|
||||
sym = (eel_symbol_t *) calloc(1, sizeof(eel_symbol_t));
|
||||
if(!sym)
|
||||
{
|
||||
log_printf(ELOG, "eel_s_new: Out of memory!\n");
|
||||
return 0;
|
||||
}
|
||||
sym->name = strdup(name);
|
||||
sym->type = type;
|
||||
switch (type)
|
||||
{
|
||||
case EST_UNDEFINED:
|
||||
break;
|
||||
case EST_CONSTANT:
|
||||
case EST_VARIABLE:
|
||||
sym->data.type = EDT_REAL; /* Default type */
|
||||
break;
|
||||
case EST_LABEL:
|
||||
case EST_FUNCTION:
|
||||
sym->data.type = EDT_CADDR;
|
||||
break;
|
||||
case EST_OPERATOR:
|
||||
sym->data.type = EDT_OPERATOR;
|
||||
break;
|
||||
case EST_DIRECTIVE:
|
||||
sym->data.type = EDT_DIRECTIVE;
|
||||
break;
|
||||
case EST_SPECIAL:
|
||||
sym->data.type = EDT_SPECIAL;
|
||||
break;
|
||||
case EST_ENUM:
|
||||
sym->data.type = EDT_INTEGER; /* For the value */
|
||||
break;
|
||||
case EST_NAMESPACE:
|
||||
sym->data.type = EDT_SYMTAB;
|
||||
default:
|
||||
log_printf(ELOG, "internal error: created"
|
||||
" symbol of undef type\n");
|
||||
}
|
||||
sym->next = (struct eel_symbol_t *)eel_s_table[_current_scope];
|
||||
eel_s_table[_current_scope] = sym;
|
||||
return sym;
|
||||
}
|
||||
|
||||
static void _free_scope(int scope)
|
||||
{
|
||||
eel_symbol_t *sym, *nextptr;
|
||||
for(sym = eel_s_table[scope]; sym; sym = nextptr)
|
||||
{
|
||||
nextptr = (eel_symbol_t *) sym->next;
|
||||
eel_d_freestring(&sym->data);
|
||||
free(sym->name);
|
||||
free(sym);
|
||||
}
|
||||
eel_s_table[scope] = (eel_symbol_t *)0;
|
||||
}
|
||||
|
||||
void eel_s_freeall(void)
|
||||
{
|
||||
int scope;
|
||||
for(scope = 0; scope < MAX_SCOPES; ++scope)
|
||||
_free_scope(scope);
|
||||
}
|
||||
|
||||
eel_symbol_t *eel_s_find(eel_symbol_t * sym, const char *eel_s_name)
|
||||
{
|
||||
int scope = _current_scope;
|
||||
while(scope >= 0)
|
||||
{
|
||||
if(!sym)
|
||||
sym = eel_s_table[scope];
|
||||
for(; sym; sym = (eel_symbol_t *) sym->next)
|
||||
if(strcmp(sym->name, eel_s_name) == 0)
|
||||
return sym;
|
||||
sym = NULL;
|
||||
--scope;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
eel_symbol_t *eel_s_find_n_tk(eel_symbol_t * sym, const char *eel_s_name, int token)
|
||||
{
|
||||
int scope = _current_scope;
|
||||
while(scope >= 0)
|
||||
{
|
||||
if(!sym)
|
||||
sym = eel_s_table[scope];
|
||||
for(; sym; sym = (eel_symbol_t *) sym->next)
|
||||
if((sym->token == token) &&
|
||||
(strcmp(sym->name, eel_s_name) == 0))
|
||||
return sym;
|
||||
sym = NULL;
|
||||
--scope;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
eel_symbol_t *eel_s_find_tk(eel_symbol_t * sym, int token)
|
||||
{
|
||||
int scope = _current_scope;
|
||||
while(scope >= 0)
|
||||
{
|
||||
if(!sym)
|
||||
sym = eel_s_table[scope];
|
||||
for(; sym; sym = (eel_symbol_t *) sym->next)
|
||||
if(sym->token == token)
|
||||
return sym;
|
||||
sym = NULL;
|
||||
--scope;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
eel_symbol_t *eel_s_find_n_t(eel_symbol_t * sym, const char *eel_s_name,
|
||||
eel_symtypes_t type)
|
||||
{
|
||||
int scope = _current_scope;
|
||||
while(scope >= 0)
|
||||
{
|
||||
if(!sym)
|
||||
sym = eel_s_table[scope];
|
||||
for(; sym; sym = (eel_symbol_t *) sym->next)
|
||||
if((sym->type == type) &&
|
||||
(strcmp(sym->name, eel_s_name) == 0))
|
||||
return sym;
|
||||
--scope;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
eel_symbol_t *eel_s_find_t(eel_symbol_t * sym, eel_symtypes_t type)
|
||||
{
|
||||
int scope = _current_scope;
|
||||
while(scope >= 0)
|
||||
{
|
||||
if(!sym)
|
||||
sym = eel_s_table[scope];
|
||||
for(; sym; sym = (eel_symbol_t *) sym->next)
|
||||
if(sym->type == type)
|
||||
return sym;
|
||||
--scope;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* NOTE: Output string only valid until next call. */
|
||||
const char *eel_s_stringrep(eel_symbol_t * sym)
|
||||
{
|
||||
static char buf[STRINGREP_SIZE];
|
||||
switch (sym->type)
|
||||
{
|
||||
case EST_UNDEFINED:
|
||||
snprintf(buf, STRINGREP_SIZE, "<undef symbol '%s'>",
|
||||
sym->name);
|
||||
return buf;
|
||||
case EST_CONSTANT:
|
||||
strncpy(buf, eel_d_stringrep(&sym->data), STRINGREP_SIZE);
|
||||
return buf;
|
||||
case EST_VARIABLE:
|
||||
case EST_LABEL:
|
||||
case EST_FUNCTION:
|
||||
case EST_OPERATOR:
|
||||
case EST_DIRECTIVE:
|
||||
case EST_SPECIAL:
|
||||
case EST_ENUM:
|
||||
case EST_NAMESPACE:
|
||||
strncpy(buf, sym->name, STRINGREP_SIZE);
|
||||
return buf;
|
||||
default:
|
||||
return "<internal error: undef symbol type>";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------
|
||||
Scope/Namespace Management
|
||||
------------------------------------------------*/
|
||||
|
||||
int eel_push_scope(void)
|
||||
{
|
||||
if(_deepest_scope >= MAX_SCOPES-1)
|
||||
{
|
||||
log_printf(ELOG, "EEL ERROR: Too deep scope nesting!\n");
|
||||
return -1;
|
||||
}
|
||||
++_deepest_scope;
|
||||
_current_scope = _deepest_scope;
|
||||
DBG(log_printf(DLOG, "eel_push_scope(): current scope = %d\n", _current_scope);)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int eel_pop_scope(void)
|
||||
{
|
||||
if(!_deepest_scope)
|
||||
{
|
||||
log_printf(ELOG, "EEL ERROR: Tried to pop root scope!\n");
|
||||
return -1;
|
||||
}
|
||||
_free_scope(_deepest_scope);
|
||||
--_deepest_scope;
|
||||
_current_scope = _deepest_scope;
|
||||
DBG(log_printf(DLOG, "eel_pop_scope(): current scope = %d\n", _current_scope);)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int eel_scope(void)
|
||||
{
|
||||
return _current_scope;
|
||||
}
|
||||
|
||||
|
||||
int eel_set_scope(int ns)
|
||||
{
|
||||
if(ns < 0 || ns > _deepest_scope)
|
||||
{
|
||||
log_printf(ELOG, "EEL ERROR: Tried to select illegal scope!\n");
|
||||
return -1;
|
||||
}
|
||||
_current_scope = ns;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void eel_restore_scope(void)
|
||||
{
|
||||
_current_scope = _deepest_scope;
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------
|
||||
Symbol table tools
|
||||
------------------------------------------------*/
|
||||
|
||||
eel_symbol_t *eel_s_get(const char *name, eel_symtypes_t type)
|
||||
{
|
||||
eel_symbol_t *sym = eel_s_find(NULL, name);
|
||||
if(sym)
|
||||
{
|
||||
if(sym->type == type)
|
||||
return sym;
|
||||
else
|
||||
{
|
||||
log_printf(ELOG, "eel_s_integer: '%s' is of"
|
||||
" the wrong type!\n", name);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
return eel_s_new(name, type);
|
||||
}
|
||||
|
||||
|
||||
int eel_s_set(eel_symbol_t *sym, const eel_data_t *dat)
|
||||
{
|
||||
return eel_d_copy(&sym->data, dat);
|
||||
}
|
||||
+239
@@ -0,0 +1,239 @@
|
||||
/*(LGPL)
|
||||
---------------------------------------------------------------------------
|
||||
symtab.h - Simple symbol table for EEL
|
||||
---------------------------------------------------------------------------
|
||||
* Copyright (C) 2000, 2002, David Olofson
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef _EEL_SYMTAB_H_
|
||||
#define _EEL_SYMTAB_H_
|
||||
|
||||
|
||||
/*------------------------------------------------
|
||||
Data container
|
||||
------------------------------------------------*/
|
||||
|
||||
struct eel_symbol_table_t;
|
||||
struct eel_symbol_t;
|
||||
struct eel_data_t;
|
||||
|
||||
typedef int (*eel_operator_cb_t)(int argc, struct eel_data_t *argv);
|
||||
typedef int (*eel_parser_cb_t)(void);
|
||||
|
||||
/* Native datatypes */
|
||||
typedef enum
|
||||
{
|
||||
EDT_ILLEGAL = 0,
|
||||
EDT_REAL, /* Real */
|
||||
EDT_INTEGER, /* Integer */
|
||||
EDT_STRING, /* String */
|
||||
EDT_CADDR, /* Code address */
|
||||
EDT_SYMREF, /* Symbol reference */
|
||||
EDT_SYMTAB, /* Symbol Table Reference (for namespaces) */
|
||||
EDT_SYMNAME, /* Name of a new symbol (String) */
|
||||
EDT_OPERATOR, /* Operator callback */
|
||||
EDT_DIRECTIVE, /* Directive parser callback */
|
||||
EDT_SPECIAL /* Special parser callback */
|
||||
} eel_datatypes_t;
|
||||
|
||||
#define EDTM_ILLEGAL (1<<EDT_ILLEGAL)
|
||||
#define EDTM_REAL (1<<EDT_REAL)
|
||||
#define EDTM_INTEGER (1<<EDT_INTEGER)
|
||||
#define EDTM_STRING (1<<EDT_STRING)
|
||||
#define EDTM_CADDR (1<<EDT_CADDR)
|
||||
#define EDTM_SYMREF (1<<EDT_SYMREF)
|
||||
#define EDTM_SYMNAME (1<<EDT_SYMNAME)
|
||||
#define EDTM_OPERATOR (1<<EDT_OPERATOR)
|
||||
#define EDTM_DIRECTIVE (1<<EDT_DIRECTIVE)
|
||||
#define EDTM_SPECIAL (1<<EDT_SPECIAL)
|
||||
|
||||
/* Data container */
|
||||
typedef struct eel_data_t
|
||||
{
|
||||
eel_datatypes_t type;
|
||||
union {
|
||||
double r; /* real constant */
|
||||
int i; /* integer constant; token */
|
||||
int a; /* code address */
|
||||
char *s; /* string constant; symbol name */
|
||||
struct eel_symbol_t *sym; /* Symbol ref */
|
||||
struct eel_symbol_table_t *st; /* Symbol table */
|
||||
struct
|
||||
{
|
||||
eel_operator_cb_t cb;
|
||||
char priority;
|
||||
char retargs;
|
||||
char preargs;
|
||||
} op;
|
||||
eel_parser_cb_t parse;
|
||||
} value;
|
||||
} eel_data_t;
|
||||
|
||||
int eel_d_copy(eel_data_t *data, const eel_data_t *from);
|
||||
|
||||
/* Copy string */
|
||||
int eel_d_setstring(eel_data_t *data, const char *s);
|
||||
|
||||
/*
|
||||
* Take over string. (No copying)
|
||||
*
|
||||
* The source string pointer *must* have been returned
|
||||
* by malloc(), calloc() or realloc(), and the string
|
||||
* MUST NOT be freed after this call. (The string will
|
||||
* be owned by the data_t.)
|
||||
*/
|
||||
void eel_d_grabstring(eel_data_t *data, char *s);
|
||||
|
||||
void eel_d_freestring(eel_data_t *data);
|
||||
|
||||
/* NOTE: Output string only valid until next call. */
|
||||
const char *eel_d_stringrep(eel_data_t *data);
|
||||
|
||||
|
||||
/*------------------------------------------------
|
||||
Symbol table
|
||||
------------------------------------------------*/
|
||||
|
||||
typedef enum eel_symtypes_t
|
||||
{
|
||||
EST_UNDEFINED,
|
||||
EST_CONSTANT,
|
||||
EST_VARIABLE,
|
||||
EST_LABEL,
|
||||
EST_FUNCTION, /* token = function index; data.a = start "address" */
|
||||
EST_OPERATOR, /* data -> callback; token = priority */
|
||||
EST_DIRECTIVE, /* data -> callback */
|
||||
EST_SPECIAL, /* data -> callback */
|
||||
EST_ENUM, /* token = enum type; data.i = enum value */
|
||||
EST_NAMESPACE /* data -> namespace symbol table */
|
||||
} eel_symtypes_t;
|
||||
|
||||
#define ESTM_UNDEFINED (1<<EST_UNDEFINED)
|
||||
#define ESTM_CONSTANT (1<<EST_CONSTANT)
|
||||
#define ESTM_VARIABLE (1<<EST_VARIABLE)
|
||||
#define ESTM_LABEL (1<<EST_LABEL)
|
||||
#define ESTM_FUNCTION (1<<EST_FUNCTION)
|
||||
#define ESTM_OPERATOR (1<<EST_OPERATOR)
|
||||
#define ESTM_DIRECTIVE (1<<EST_DIRECTIVE)
|
||||
#define ESTM_SPECIAL (1<<EST_SPECIAL)
|
||||
#define ESTM_ENUM (1<<EST_ENUM)
|
||||
#define ESTM_NAMESPACE (1<<EST_NAMESPACE)
|
||||
|
||||
/* symbol list node */
|
||||
typedef struct eel_symbol_t
|
||||
{
|
||||
struct eel_symbol_t *next;
|
||||
char *name;
|
||||
eel_symtypes_t type;
|
||||
eel_data_t data;
|
||||
int token;
|
||||
} eel_symbol_t;
|
||||
|
||||
/* Open/close symbol table */
|
||||
int eel_s_open(void);
|
||||
void eel_s_close(void);
|
||||
|
||||
eel_symbol_t *eel_s_new(const char *name, eel_symtypes_t type);
|
||||
|
||||
void eel_s_freeall(void);
|
||||
|
||||
eel_symbol_t *eel_s_find(eel_symbol_t *sym, const char *sym_name);
|
||||
eel_symbol_t *eel_s_find_n_tk(eel_symbol_t *sym, const char *sym_name,
|
||||
int token);
|
||||
eel_symbol_t *eel_s_find_tk(eel_symbol_t *sym, int token);
|
||||
eel_symbol_t *eel_s_find_n_t(eel_symbol_t *sym, const char *sym_name,
|
||||
eel_symtypes_t type);
|
||||
eel_symbol_t *eel_s_find_t(eel_symbol_t *sym, eel_symtypes_t type);
|
||||
|
||||
/* NOTE: Output string only valid until next call. */
|
||||
const char *eel_s_stringrep(eel_symbol_t *sym);
|
||||
|
||||
|
||||
/*------------------------------------------------
|
||||
Scope Management
|
||||
--------------------------------------------------
|
||||
* The EEL symbol table manages namespace
|
||||
* separation using a stack of separate symbol
|
||||
* tables. A "scope" consists of a namespace and
|
||||
* all namespaces above it.
|
||||
*
|
||||
* In the normal case, the "current scope" includes
|
||||
* all namespaces currently defined, but it's
|
||||
* possible to temporarily move the scope up to an
|
||||
* arbitrary namespace level.
|
||||
*
|
||||
* Symbol lookups start at the namespace level set
|
||||
* by the "current scope", and moves up from there
|
||||
* until the symbol is found, or it is concluded
|
||||
* that the symbol does not exist.
|
||||
*
|
||||
* New symbols are added to the namespace set by
|
||||
* the "current scope". Higher level namespaces are
|
||||
* never considered.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Create a new, local scope inside the deepest
|
||||
* level of the current scope, and make it current.
|
||||
*/
|
||||
int eel_push_scope(void);
|
||||
|
||||
/*
|
||||
* Destroy the deepest level of the scope, and move
|
||||
* up to the next higher level.
|
||||
*/
|
||||
int eel_pop_scope(void);
|
||||
|
||||
/*
|
||||
* Returns the current scope level.
|
||||
*/
|
||||
int eel_scope(void);
|
||||
|
||||
/*
|
||||
* Directly set scope level for subsequent eel_s_*()
|
||||
* operations.
|
||||
*/
|
||||
int eel_set_scope(int ns);
|
||||
|
||||
/*
|
||||
* Return to the current deepest level scope.
|
||||
*/
|
||||
void eel_restore_scope(void);
|
||||
|
||||
|
||||
/*------------------------------------------------
|
||||
Symbol table tools
|
||||
------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Find symbol 'name' and verify that it is of of type 'type',
|
||||
* or if it doesn't exist, create new symbol 'name' of type
|
||||
* 'type'.
|
||||
*
|
||||
* Returns the found/new symbol, or NULL in the case of
|
||||
* failure.
|
||||
*/
|
||||
eel_symbol_t *eel_s_get(const char *name, eel_symtypes_t type);
|
||||
|
||||
/*
|
||||
* Load 'dat' into symbol 'sym'.
|
||||
* Returns 0 upon success, or a negative value if the operation
|
||||
* fails.
|
||||
*/
|
||||
int eel_s_set(eel_symbol_t *sym, const eel_data_t *dat);
|
||||
|
||||
#endif /* _EEL_SYMTAB_H_ */
|
||||
+236
@@ -0,0 +1,236 @@
|
||||
/*(LGPL)
|
||||
---------------------------------------------------------------------------
|
||||
e_util.c - EEL engine utilities
|
||||
---------------------------------------------------------------------------
|
||||
* Copyright (C) 2002, 2003, David Olofson
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "kobolog.h"
|
||||
#include "e_util.h"
|
||||
#include "eel.h"
|
||||
|
||||
#include "_e_script.h"
|
||||
|
||||
|
||||
/*----------------------------------------------------------
|
||||
"stdio" style API for raw memory buffers
|
||||
----------------------------------------------------------*/
|
||||
|
||||
bio_file_t *bio_open(void *data, int len)
|
||||
{
|
||||
bio_file_t *bio = malloc(sizeof(bio_file_t));
|
||||
if(!bio)
|
||||
return NULL;
|
||||
bio->data = (unsigned char *)data;
|
||||
bio->len = len;
|
||||
bio->pos = 0;
|
||||
return bio;
|
||||
}
|
||||
|
||||
|
||||
bio_file_t *bio_clone(bio_file_t *bio)
|
||||
{
|
||||
bio_file_t *c = malloc(sizeof(bio_file_t));
|
||||
if(!c)
|
||||
return NULL;
|
||||
*c = *bio;
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
void bio_close(bio_file_t *bio)
|
||||
{
|
||||
free(bio);
|
||||
}
|
||||
|
||||
|
||||
int bio_seek(bio_file_t *bio, int offset, int whence)
|
||||
{
|
||||
switch(whence)
|
||||
{
|
||||
case SEEK_SET:
|
||||
bio->pos = offset;
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
bio->pos += offset;
|
||||
break;
|
||||
case SEEK_END:
|
||||
bio->pos = bio->len - offset;
|
||||
break;
|
||||
}
|
||||
if(bio->pos < 0)
|
||||
bio->pos = 0;
|
||||
else if(bio->pos > bio->len)
|
||||
bio->pos = bio->len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int bio_read(bio_file_t *bio, char *buf, int count)
|
||||
{
|
||||
if(bio->pos + count > bio->len)
|
||||
count = bio->len - bio->pos;
|
||||
memcpy(buf, bio->data + bio->pos, count);
|
||||
bio->pos += count;
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
double bio_strtod(bio_file_t *bio)
|
||||
{
|
||||
char *p = (char *)bio->data + bio->pos;
|
||||
double val;
|
||||
val = strtod(p, &p);
|
||||
bio->pos = p - (char *)bio->data;
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
/*----------------------------------------------------------
|
||||
Context management ("VM stack")
|
||||
----------------------------------------------------------*/
|
||||
|
||||
eel_context_t eel_current = {
|
||||
NULL,
|
||||
NULL,
|
||||
-1,
|
||||
0,
|
||||
0,
|
||||
EOF,
|
||||
NULL
|
||||
};
|
||||
|
||||
static eel_context_t *context_stack = NULL;
|
||||
|
||||
|
||||
void eel_push_context(void)
|
||||
{
|
||||
eel_context_t *c = malloc(sizeof(eel_context_t));
|
||||
if(!c)
|
||||
{
|
||||
eel_error("INTERNAL ERROR: Failed to push context!");
|
||||
return;
|
||||
}
|
||||
memcpy(c, &eel_current, sizeof(eel_context_t));
|
||||
c->previous = context_stack;
|
||||
context_stack = c;
|
||||
}
|
||||
|
||||
|
||||
void eel_pop_context(void)
|
||||
{
|
||||
eel_context_t *c = context_stack;
|
||||
if(!c)
|
||||
{
|
||||
eel_error("INTERNAL ERROR: No context to pop!");
|
||||
return;
|
||||
}
|
||||
memcpy(&eel_current, c, sizeof(eel_context_t));
|
||||
context_stack = c->previous;
|
||||
if(c->lval)
|
||||
{
|
||||
eel_d_freestring(c->lval);
|
||||
free(c->lval);
|
||||
}
|
||||
free(c);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*----------------------------------------------------------
|
||||
Error handling tools
|
||||
----------------------------------------------------------*/
|
||||
|
||||
static int last_script = -1;
|
||||
|
||||
int eel_error(const char *format, ...)
|
||||
{
|
||||
int count = 0;
|
||||
va_list args;
|
||||
int i, pos, line = 1;
|
||||
|
||||
/* Figure out which line we're at... */
|
||||
pos = bio_tell(eel_current.bio);
|
||||
bio_seek(eel_current.bio, 0, SEEK_SET);
|
||||
for(i = 0; i < pos; ++i)
|
||||
if('\n' == bio_getchar(eel_current.bio))
|
||||
++line;
|
||||
|
||||
if((eel_current.script >= 0) && (eel_current.script != last_script))
|
||||
{
|
||||
count = log_printf(ELOG, "(EEL) in file \"%s\":\n",
|
||||
eel_scripttab[eel_current.script].name);
|
||||
last_script = eel_current.script;
|
||||
}
|
||||
if(eel_current.arg)
|
||||
count += log_printf(ELOG, "(EEL) line %d, arg %d: ",
|
||||
line, eel_current.arg);
|
||||
else
|
||||
count += log_printf(ELOG, "(EEL) line %d: ", line);
|
||||
va_start(args, format);
|
||||
count += vfprintf(stderr, format, args);
|
||||
va_end(args);
|
||||
count += log_printf(ELOG, "\n");
|
||||
return count;
|
||||
}
|
||||
|
||||
const char *eel_symbol_is(eel_symbol_t *s)
|
||||
{
|
||||
switch(s->type)
|
||||
{
|
||||
case EST_UNDEFINED: return "an undedined symbol";
|
||||
case EST_CONSTANT: return "a constant";
|
||||
case EST_VARIABLE: return "a variable";
|
||||
case EST_LABEL: return "a label";
|
||||
case EST_FUNCTION: return "a function";
|
||||
case EST_OPERATOR: return "an operator";
|
||||
case EST_DIRECTIVE: return "a directive";
|
||||
case EST_SPECIAL: return "a special";
|
||||
case EST_ENUM: return "an enum constant";
|
||||
case EST_NAMESPACE: return "a namespace";
|
||||
}
|
||||
/*
|
||||
* Should be here, and not under default:, to get
|
||||
* a warning if we forget to add new types. :-)
|
||||
*/
|
||||
return "a broken symbol! (illegal type)";
|
||||
}
|
||||
|
||||
const char *eel_data_is(eel_data_t *d)
|
||||
{
|
||||
switch(d->type)
|
||||
{
|
||||
case EDT_ILLEGAL: return "an illegal value";
|
||||
case EDT_REAL: return "a real value";
|
||||
case EDT_INTEGER: return "an integer value";
|
||||
case EDT_STRING: return "a string";
|
||||
case EDT_CADDR: return "a code address";
|
||||
case EDT_SYMREF: return "a symbol reference";
|
||||
case EDT_SYMTAB: return "a symbol table pointer";
|
||||
case EDT_SYMNAME: return "a (new) symbol name";
|
||||
case EDT_OPERATOR: return "an operator callback pointer";
|
||||
case EDT_DIRECTIVE: return "a directive callback pointer";
|
||||
case EDT_SPECIAL: return "a special callback pointer";
|
||||
}
|
||||
return "a broken value! (illegal type)";
|
||||
}
|
||||
|
||||
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
/*(LGPL)
|
||||
---------------------------------------------------------------------------
|
||||
e_util.h - EEL engine utilities
|
||||
---------------------------------------------------------------------------
|
||||
* Copyright (C) 2002, David Olofson
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef _EEL_UTIL_H_
|
||||
#define _EEL_UTIL_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include "eel.h"
|
||||
|
||||
|
||||
/*----------------------------------------------------------
|
||||
"stdio" style API for raw memory buffers
|
||||
----------------------------------------------------------*/
|
||||
|
||||
typedef struct bio_file_t
|
||||
{
|
||||
unsigned char *data;
|
||||
int len;
|
||||
int pos;
|
||||
} bio_file_t;
|
||||
|
||||
bio_file_t *bio_open(void *data, int len);
|
||||
bio_file_t *bio_clone(bio_file_t *bio);
|
||||
void bio_close(bio_file_t *bio);
|
||||
|
||||
/* Get the next character from the buffer */
|
||||
static inline int bio_getchar(bio_file_t *bio)
|
||||
{
|
||||
if(bio->pos < bio->len)
|
||||
return bio->data[bio->pos++];
|
||||
else
|
||||
return EOF;
|
||||
}
|
||||
|
||||
/* Push last character back */
|
||||
static inline void bio_ungetc(bio_file_t *bio)
|
||||
{
|
||||
if(bio->pos > 0)
|
||||
--bio->pos;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the current source buffer position
|
||||
*/
|
||||
static inline int bio_tell(bio_file_t *bio)
|
||||
{
|
||||
return bio->pos;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the current source buffer position
|
||||
*/
|
||||
int bio_seek(bio_file_t *bio, int offset, int whence);
|
||||
|
||||
/*
|
||||
* Read 'count' bytes from the source code,
|
||||
* starting at the current position, into
|
||||
* 'buf'. Returns the number of bytes
|
||||
* actually read.
|
||||
*/
|
||||
int bio_read(bio_file_t *bio, char *buf, int count);
|
||||
|
||||
double bio_strtod(bio_file_t *bio);
|
||||
|
||||
|
||||
/*----------------------------------------------------------
|
||||
Context management ("VM stack")
|
||||
------------------------------------------------------------
|
||||
* This supports skipping between scripts, and also keeps
|
||||
* track of the arg count for error messages.
|
||||
*/
|
||||
|
||||
typedef struct eel_context_t
|
||||
{
|
||||
struct eel_context_t *previous;
|
||||
bio_file_t *bio;
|
||||
int script;
|
||||
int arg;
|
||||
int unlexed;
|
||||
int token;
|
||||
eel_data_t *lval;
|
||||
} eel_context_t;
|
||||
|
||||
extern eel_context_t eel_current;
|
||||
|
||||
void eel_push_context(void);
|
||||
void eel_pop_context(void);
|
||||
|
||||
#endif /*_EEL_UTIL_H_*/
|
||||
@@ -0,0 +1,89 @@
|
||||
|
||||
The "EEL Compressed Source" file format
|
||||
---------------------------------------
|
||||
|
||||
EEL Compressed Source files are EEL source files stripped of
|
||||
all comments and formatting information. They are tokenized
|
||||
using an external dictionary, which contains all keywords of
|
||||
EEL and extensions, and any project names. Immediate values
|
||||
are encoded using an extended "variable length number" BCD
|
||||
format.
|
||||
|
||||
* EEL Compressed Source files should have the extension
|
||||
".eec" instead of the normal ".eel", for reliable
|
||||
identification, and to avoid accidentally overwriting
|
||||
source files with compressed source files. (That would
|
||||
be nasty, as the compression is destructive WRT comments,
|
||||
symbol names and code formatting...)
|
||||
|
||||
* The files are based on 4 bit words. Wider words (8 or 16
|
||||
bits) are *not* aligned to 8 or 16 bits, but start
|
||||
directly at the current 4 bit word position.
|
||||
|
||||
* There are two modes: XASCII and XBCD. Decoding of a file
|
||||
starts in the XASCII mode. XASCII codes are 8 bits, and
|
||||
XBCD codes are 4 bits.
|
||||
|
||||
* The file starts with an 8 bit version code for the EEL
|
||||
dictionary to use. Then follows a list of 4 byte EEL
|
||||
extension IDs, terminated by a 0 byte. The EEL extension
|
||||
IDs are of the form "XXXv", where "XXX" is an acronym
|
||||
identifying the extension, and "v" is the version of the
|
||||
extension dictionary to use.
|
||||
|
||||
Any extension ID that doesn't math any known EEL
|
||||
extension is assumed to be a Local Dictionary name.
|
||||
".eed" will be appended to the full 4 byte string (no
|
||||
version code), and then EEL will try to find a file by
|
||||
that name and load it as a Local Dictionary.
|
||||
|
||||
* A Local Dictionary file consists of a 32 bit little
|
||||
endian integer that holds the number of tokens needed
|
||||
by the dictionary, *optionally* followed by a list of
|
||||
null terminated ASCII strings, holding the human
|
||||
readable names of all tokens. (The token name list is
|
||||
useful when mixing compressed source with ASCII source
|
||||
during development.)
|
||||
|
||||
* Token values are allocated from 0 and up as
|
||||
dictionaries are loaded. This is why there are
|
||||
extension version numbers in the dictionary lists -
|
||||
and it should also make it obvious that EEL extensions
|
||||
must only *add* to their dictionaries if compatibility
|
||||
with old compressed sources is to be maintained.
|
||||
|
||||
* XASCII code:
|
||||
0-14 XBCD code + enter XBCD mode
|
||||
|
||||
15 Local token dictionary follows
|
||||
16 8 bit character follows
|
||||
17 Null terminated 8 bit quoted string
|
||||
18 Quoted 8 bit Pascal string follows
|
||||
19 Quoted 8 bit Pascal string continued
|
||||
20 <unused>
|
||||
21 <unused>
|
||||
22 <unused>
|
||||
23 <unused>
|
||||
24 <unused>
|
||||
25 <unused>
|
||||
26 <unused>
|
||||
27 <unused>
|
||||
28 <unused>
|
||||
29 <unused>
|
||||
30 <unused>
|
||||
31 <unused>
|
||||
|
||||
32-127 Standard 7 bit ASCII (copied as is)
|
||||
|
||||
128-191 Short Tokens
|
||||
192-254 Extended Tokens (8 extra bits follow)
|
||||
255 Wide Tokens (16 extra bits follow)
|
||||
|
||||
* XBCD code:
|
||||
0-9 Decimal numbers 0-9
|
||||
10 Decimal point (.)
|
||||
11 Unary minus (-)
|
||||
12 Argument separator/white space
|
||||
13 Statement terminator (;)
|
||||
14 Single XASCII character follows
|
||||
15 Switch to XASCII mode
|
||||
@@ -0,0 +1,161 @@
|
||||
|
||||
The Extensible Embeddable Language
|
||||
----------------------------------
|
||||
|
||||
Well, here's a simple extensible scripting language
|
||||
for ya' - all in a few thousand lines of (hopefully)
|
||||
portable C code! No external tools needed to build
|
||||
this version, although future versions might have the
|
||||
parsing functions replaced with a Bison parser. (You
|
||||
still won't really need Bison, unless you want to
|
||||
change the language syntax.)
|
||||
|
||||
Extending the language is done by adding commands,
|
||||
directives, operators, enums and "specials". It's pretty
|
||||
much as simple as it gets, without using a custom source
|
||||
preprocessor. A single scanf() style function call does
|
||||
argument checking and casting for commands, so you
|
||||
usually get away with a single call to get all your
|
||||
arguments.
|
||||
|
||||
The Language:
|
||||
EEL is CaSe SEnSitIve!
|
||||
|
||||
An EEL file consists of zero or more statements.
|
||||
|
||||
There are (so far) two kinds of statements: Command
|
||||
Statements and Assignments.
|
||||
|
||||
A Command Statement starts with a command name,
|
||||
followed by zero or more coma (,) separated arguments,
|
||||
and is terminated with a semicolon (;). Some commands
|
||||
accept variable numbers of arguments.
|
||||
|
||||
A command argument may be of any type, which means
|
||||
that symbol references, command references and other
|
||||
weird stuff can be passed.
|
||||
|
||||
"Functions" can be implemented as commands that
|
||||
require one or more arguments to be passed by
|
||||
reference. (See "set" / '=' command, which is an
|
||||
example of this.)
|
||||
|
||||
Assignments can be written in two forms; either using
|
||||
the 'set' command, which takes two arguments; the
|
||||
target and the source - or the more compact '='
|
||||
operator method, is which the target is on the left
|
||||
side of the '=' operator, and the source is on the
|
||||
right.
|
||||
TODO:
|
||||
"Function commands" can alternatively be called using
|
||||
the traditional "a = function ...;" style. The
|
||||
command's first argument should be an output argument,
|
||||
and preferably the only output argument. (Note that
|
||||
the *real* set command/'=' operator is not involved!)
|
||||
/TODO
|
||||
|
||||
Variables are created implicitly as a result of the
|
||||
first Assignment. (This will probably change...)
|
||||
|
||||
Variables are dynamically typed. Both value and type
|
||||
may be changed after a variable has been declared.
|
||||
|
||||
EEL strives to use "late casting", which means that
|
||||
in the normal case, assignments change type as well
|
||||
as value.
|
||||
TODO:
|
||||
The above is somewhat confusing, and will most probably
|
||||
change. We need a clear distinction between "passing
|
||||
by value" and "passing by reference", as this becomes
|
||||
very important in algorithmic code.)
|
||||
/TODO
|
||||
|
||||
Data types that can be stored in a variable:
|
||||
Real (64 bit float)
|
||||
Integer (32 bit signed)
|
||||
String (Null terminated)
|
||||
Code Address (Source or bytecode position)
|
||||
Symbol Reference (Can refer to any symbol)
|
||||
|
||||
Symbol reference variables are quite interesting, as
|
||||
they can theoretically reference *anything*, including
|
||||
commands - and all type info is available as an extra
|
||||
bonus. (Note that most of this is rather useless right
|
||||
now, as the language doesn't have constructs that can
|
||||
make use of it!)
|
||||
|
||||
Built-in EEL commands, functions and directives:
|
||||
end;
|
||||
End of script. (Same effect as EOF.)
|
||||
|
||||
set <name>, <value>;
|
||||
<name> = <value>;
|
||||
Set variable <name> to <value>. If <name>
|
||||
is not yet defined, it will be created
|
||||
automatically. (This is likely to change.)
|
||||
|
||||
print arg[, arg[,...]];
|
||||
Print the arguments in the "standard console".
|
||||
|
||||
procedure <procname>([arg[, arg[,...]]]) { <body> }
|
||||
function <funcname>([arg[, arg[,...]]]) { <body> }
|
||||
Define procedure 'procname' or function
|
||||
'funcname', respectively. The function will
|
||||
take (as in "require") the specified
|
||||
(dynamically typed) arguments, and when it's
|
||||
invoked, the code in between the curly
|
||||
brackets ('{' and '}') will be executed.
|
||||
The function *must* return a value, while
|
||||
the procedure must *not* - that's the only
|
||||
difference between them.
|
||||
|
||||
When a function or procedure is running, a
|
||||
local "partition" of the symbol table is used.
|
||||
Initially, this table contains only the
|
||||
arguments, but any new variables declared as
|
||||
the body code executes are added to *this*
|
||||
table, instead of the global table, as in the
|
||||
normal case. The "partition" (actually just a
|
||||
local namespace) is removed as the function
|
||||
or procedure returns, which obviously means
|
||||
that the argument variables, as well as any
|
||||
local variables, are deleted.
|
||||
|
||||
<funcname> [arg[, arg[,...]]];
|
||||
Function invocation. Works just like a
|
||||
command invocation, although EEL will just
|
||||
add the arguments to the Local Symbol Table -
|
||||
it will not perform any type checking, as
|
||||
argument types aren't supported as of now.
|
||||
|
||||
#include <filename>
|
||||
Run the file 'filename' in the current scope,
|
||||
and then continue executing the current
|
||||
script.
|
||||
|
||||
Note that as of now, this is not 100%
|
||||
compatible with the way a C/C++ preprocessor
|
||||
works! It's more like loading and executing
|
||||
a "subroutine script".
|
||||
|
||||
#define <identifier> <value>
|
||||
C header compatibility hack for defining
|
||||
constants. It's mostly there to allow EEL
|
||||
scripts to share headers with other languages
|
||||
using C preprocessors, like C or C++. We want
|
||||
to do that *without* actually using cpp, as
|
||||
EEL scripts are supposed to load and run from
|
||||
source without "special tools".
|
||||
|
||||
TODO:
|
||||
<name>:
|
||||
Label declaration. Creates a symbol <name>
|
||||
that contains the Code Address of the
|
||||
statement following the colon.
|
||||
|
||||
TODO:
|
||||
i = 0;
|
||||
for i < 10
|
||||
{
|
||||
...
|
||||
} i = i + 1;
|
||||
@@ -0,0 +1,573 @@
|
||||
/*(LGPL)
|
||||
---------------------------------------------------------------------------
|
||||
eel.c - The "Extensible Embeddable Language"
|
||||
---------------------------------------------------------------------------
|
||||
* Copyright (C) 2002, 2007 David Olofson
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
TODO:
|
||||
* Eliminate the parser and use the expression
|
||||
evaluator instead. "Everything is an expression."
|
||||
The evaluator will need a few extra features, but
|
||||
lots of messy code will be eliminated, and the
|
||||
design will be much cleaner and more flexible.
|
||||
|
||||
* Make all commands, functions and stuff operators.
|
||||
Binary commands and operators should use the same
|
||||
callback prototype. A way of describing return,
|
||||
reference and input arguments will be needed. (Not
|
||||
sure about multiple return arguments...)
|
||||
|
||||
* Split the command and operator callbacks up
|
||||
into one "parser" callback, and one or more
|
||||
run-time callbacks. Leave argument grabbing/casting
|
||||
and callback selection to the parser callbacks, for
|
||||
simplicity and flexibility. (They can still use
|
||||
tools like the EEL argument grabber.) Let them
|
||||
generate byte code or similar (using some EEL API
|
||||
calls) for one or more "operations", as required to
|
||||
perform the desired actions.
|
||||
|
||||
Interpreting mode could still be implemented,
|
||||
with some overhead, by compiling and executing one
|
||||
statement at a time - although IMHO, one might as
|
||||
well make a complete switch to compiling + VM.
|
||||
That would eliminate issues with distinguishing
|
||||
between compiled and interpreted functions and the
|
||||
like.
|
||||
|
||||
* To make the above work, we'll need a distinction
|
||||
between compile time and run-time symbols. (In
|
||||
fact, we don't really need actual symbols at run
|
||||
time, other than for globals. Local variables
|
||||
should be allocated from some VM stack.) For
|
||||
example, some features of the current argument
|
||||
grabber won't work for compiling, as they rely on
|
||||
the actual contents of a symbol, to extract data.
|
||||
Such features will have to be implemented though
|
||||
run-time callbacks that execute the corresponding
|
||||
operations.
|
||||
|
||||
* Remove EDT_INTEGER? The lexer currently never
|
||||
returns TK_INUM except for character literals,
|
||||
and I'm starting to think it's a good idea to
|
||||
keep it that way, for various reasons...
|
||||
|
||||
* Functions should return values! Make sure
|
||||
that errors are issued if a function returns
|
||||
without an explicit return statement.
|
||||
|
||||
* Add "procedure" keyword for "functions"
|
||||
without return values. Issue an error if a
|
||||
"return with value" statement is executed
|
||||
within a procedure.
|
||||
|
||||
* Implement conditional constructs.
|
||||
|
||||
* Implement '&' ("address" of function) operator.
|
||||
|
||||
* Add a procedure extension(name) to EEL, to allow
|
||||
scripts to check for extension availability and
|
||||
version. Should return version #, or 0 if the
|
||||
extension is not available. There should probably
|
||||
also be a uses(name), to avoid implicitly stuffing
|
||||
all available extensions into the name space of
|
||||
every script.
|
||||
|
||||
* Eliminate all fixed size arrays and limits...
|
||||
|
||||
* Implement the Compressed Source file format.
|
||||
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "eel.h"
|
||||
#include "e_lexer.h"
|
||||
#include "e_util.h"
|
||||
#include "e_builtin.h"
|
||||
|
||||
#include "_e_script.h"
|
||||
|
||||
|
||||
/*----------------------------------------------------------
|
||||
Parser/Interpreter
|
||||
----------------------------------------------------------*/
|
||||
|
||||
static int command(void)
|
||||
{
|
||||
eel_symbol_t *sym = eel_current.lval->value.sym;
|
||||
|
||||
if(!sym->data.value.op.cb)
|
||||
{
|
||||
eel_error("INTERNAL ERROR: Command callback missing!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(sym->data.value.op.retargs)
|
||||
{
|
||||
eel_error("INTERNAL ERROR: Return value ignored!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(eel_parse_args(",", ';') < 0)
|
||||
return -1;
|
||||
|
||||
return sym->data.value.op.cb(eel_arg_count, eel_args);
|
||||
}
|
||||
|
||||
|
||||
static int assignment(int token)
|
||||
{
|
||||
int res;
|
||||
|
||||
/* Get target */
|
||||
switch(token)
|
||||
{
|
||||
case TK_SYMREF:
|
||||
switch (eel_current.lval->value.sym->type)
|
||||
{
|
||||
case EST_UNDEFINED:
|
||||
case EST_VARIABLE:
|
||||
break;
|
||||
default:
|
||||
eel_error("Cannot change the value of %s!",
|
||||
eel_symbol_is(eel_current.lval->value.sym));
|
||||
return -1;
|
||||
}
|
||||
case TK_NEWSYM:
|
||||
if(eel_grab_arg() < 0)
|
||||
{
|
||||
eel_error("Argument overflow!");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
#if 0
|
||||
case 0:
|
||||
eel_error("Unexpected end of file!");
|
||||
return -1;
|
||||
default:
|
||||
eel_error("Unexpected token!");
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Get operator */
|
||||
if(eel_lex(0) != '=')
|
||||
{
|
||||
eel_error("Expected '='!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get source */
|
||||
if(eel_parse_args(",", ';') < 0)
|
||||
return -1;
|
||||
|
||||
/* End of declaration; execute! */
|
||||
res = eel_cmd_set(eel_arg_count, eel_args);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static int directive(void)
|
||||
{
|
||||
int res;
|
||||
eel_symbol_t *sym = eel_current.lval->value.sym;
|
||||
|
||||
if(!sym->data.value.parse)
|
||||
{
|
||||
eel_error("INTERNAL ERROR: Directive callback missing!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = sym->data.value.parse();
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static int function(void)
|
||||
{
|
||||
int arg, res;
|
||||
eel_symbol_t *func = eel_current.lval->value.sym;
|
||||
|
||||
eel_push_scope();
|
||||
|
||||
/* Grab arguments */
|
||||
res = eel_parse_args(",", ';');
|
||||
|
||||
/* Enter function */
|
||||
eel_push_context();
|
||||
if(eel_current.script == func->token)
|
||||
eel_current.bio = bio_clone(eel_current.bio);
|
||||
else
|
||||
eel_current.bio = bio_open(eel_scripttab[func->token].data,
|
||||
eel_scripttab[func->token].len);
|
||||
if(!eel_current.bio)
|
||||
{
|
||||
eel_error("INTERNAL ERROR: Failed to set up script"
|
||||
" reading at start of function!");
|
||||
eel_pop_context();
|
||||
eel_pop_scope();
|
||||
return -1;
|
||||
}
|
||||
res = bio_seek(eel_current.bio, func->data.value.a, SEEK_SET);
|
||||
|
||||
/*
|
||||
* Find out where to stuff the arguments.
|
||||
*/
|
||||
for(arg = 0; (arg < eel_arg_count) && (res >= 0); )
|
||||
switch(eel_lex(0))
|
||||
{
|
||||
case ',':
|
||||
/* Already verified, so we just skip them. */
|
||||
break;
|
||||
case TK_NEWSYM:
|
||||
{
|
||||
eel_symbol_t *sym;
|
||||
sym = eel_set_data(eel_current.lval->value.s,
|
||||
eel_args + arg);
|
||||
if(sym)
|
||||
{
|
||||
sym->type = EST_VARIABLE;
|
||||
++arg;
|
||||
}
|
||||
else
|
||||
{
|
||||
eel_error("INTERNAL ERROR: Failed to "
|
||||
"create argument variable!");
|
||||
res = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TK_SYMREF:
|
||||
eel_error("Function argument clashes with "
|
||||
"previously defined symbol!");
|
||||
res = -1;
|
||||
break;
|
||||
default:
|
||||
eel_error("Syntax error in argument list!");
|
||||
res = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Find start of body ("the code") */
|
||||
if(res >= 0)
|
||||
{
|
||||
if(eel_lex(0) != ')')
|
||||
{
|
||||
eel_error("Expected ')'!");
|
||||
res = -1;
|
||||
}
|
||||
else if(eel_lex(0) != '{')
|
||||
{
|
||||
eel_error("Expected '{'!");
|
||||
res = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if(res >= 0)
|
||||
{
|
||||
/*
|
||||
* Execute function
|
||||
*
|
||||
* Note that this is a simple, inefficient
|
||||
* RECURSIVE implementation!
|
||||
*
|
||||
* Alternatively, we could set up a "trigger"
|
||||
* to run "the rest of this function" when
|
||||
* the function ends - and then just return.
|
||||
*/
|
||||
res = eel_call(eel_current.script, bio_tell(eel_current.bio));
|
||||
}
|
||||
|
||||
/* Leave function */
|
||||
bio_close(eel_current.bio);
|
||||
eel_pop_context();
|
||||
eel_pop_scope();
|
||||
|
||||
if(res >= 0)
|
||||
return 1;
|
||||
else
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
int eel_call(int handle, int pos)
|
||||
{
|
||||
int res = 1;
|
||||
int depth = 0;
|
||||
eel_push_context();
|
||||
eel_current.script = handle;
|
||||
eel_current.bio = bio_open(eel_scripttab[handle].data,
|
||||
eel_scripttab[handle].len);
|
||||
if(!eel_current.bio)
|
||||
{
|
||||
eel_error("INTERNAL ERROR: Couldn't read script!");
|
||||
eel_pop_context();
|
||||
return -1;
|
||||
}
|
||||
bio_seek(eel_current.bio, pos, SEEK_SET);
|
||||
|
||||
eel_current.lval = NULL;
|
||||
while(res > 0)
|
||||
{
|
||||
/* Start of statement */
|
||||
eel_clear_args(0);
|
||||
eel_current.arg = 0;
|
||||
switch(eel_lex(0))
|
||||
{
|
||||
case 0:
|
||||
/* End of script */
|
||||
res = 0;
|
||||
break;
|
||||
case ';':
|
||||
/* Empty statement */
|
||||
res = 1;
|
||||
break;
|
||||
case '{':
|
||||
/* Begin scope */
|
||||
eel_push_scope();
|
||||
++depth;
|
||||
res = 1;
|
||||
break;
|
||||
case '}':
|
||||
/* End scope */
|
||||
if(depth)
|
||||
{
|
||||
eel_pop_scope();
|
||||
--depth;
|
||||
}
|
||||
else
|
||||
res = 0;
|
||||
break;
|
||||
case TK_NEWSYM:
|
||||
res = assignment(TK_NEWSYM);
|
||||
break;
|
||||
case TK_SYMREF:
|
||||
switch(eel_current.lval->value.sym->type)
|
||||
{
|
||||
case EST_CONSTANT: /* Just to get a more
|
||||
* sensible error message...
|
||||
*/
|
||||
case EST_UNDEFINED:
|
||||
case EST_VARIABLE:
|
||||
res = assignment(TK_SYMREF);
|
||||
break;
|
||||
/* case EST_COMMAND:
|
||||
res = command();
|
||||
break;*/
|
||||
case EST_FUNCTION:
|
||||
res = function();
|
||||
break;
|
||||
case EST_DIRECTIVE:
|
||||
case EST_SPECIAL:
|
||||
res = directive();
|
||||
break;
|
||||
case EST_ENUM:
|
||||
case EST_LABEL:
|
||||
eel_error("Syntax error!");
|
||||
res = -1;
|
||||
break;
|
||||
case EST_OPERATOR:
|
||||
res = command();
|
||||
break;
|
||||
default:
|
||||
eel_error("INTERNAL ERROR: Lexer returned"
|
||||
" symbol of illegal type!");
|
||||
res = -1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
eel_error("Unexpected character!");
|
||||
res = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
eel_current.arg = 0;
|
||||
bio_close(eel_current.bio);
|
||||
eel_pop_context();
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
int eel_run(int handle)
|
||||
{
|
||||
return eel_call(handle, 0);
|
||||
}
|
||||
|
||||
|
||||
static int _eel_users = 0;
|
||||
|
||||
int eel_open(void)
|
||||
{
|
||||
if(_eel_users++)
|
||||
return 0;
|
||||
|
||||
memset(eel_scripttab, 0, sizeof(eel_scripttab));
|
||||
|
||||
if(eel_s_open() < 0)
|
||||
{
|
||||
_eel_users = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
eel_register_operator("end", eel_cmd_end, 100, 0, 0);
|
||||
eel_register_operator("set", eel_cmd_set, 100, 0, 0);
|
||||
eel_register_operator("print", eel_cmd_print, 100, 0, 0);
|
||||
|
||||
eel_register_operator("+", eel_op_add, 10, 0, 1);
|
||||
eel_register_operator("-", eel_op_sub, 10, 0, 1);
|
||||
|
||||
eel_register_operator("*", eel_op_mul, 20, 0, 1);
|
||||
eel_register_operator("/", eel_op_div, 20, 0, 1);
|
||||
eel_register_operator("%", eel_op_mod, 20, 0, 1);
|
||||
|
||||
eel_register_operator("^", eel_op_pow, 30, 0, 1);
|
||||
|
||||
eel_register_directive("include", eel_dir_include);
|
||||
eel_register_directive("define", eel_dir_define);
|
||||
|
||||
eel_register_special("function", eel_spec_function);
|
||||
eel_register_special("procedure", eel_spec_procedure);
|
||||
/* eel_register_special("global", eel_spec_global);*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void eel_close()
|
||||
{
|
||||
int h;
|
||||
if(!_eel_users)
|
||||
return;
|
||||
|
||||
for(h = 0; h < MAX_SCRIPTS; ++h)
|
||||
eel_free(h);
|
||||
|
||||
eel_s_freeall();
|
||||
eel_set_path(NULL);
|
||||
eel_s_close();
|
||||
eel_lexer_cleanup();
|
||||
|
||||
--_eel_users;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*----------------------------------------------------------
|
||||
EEL variable access
|
||||
----------------------------------------------------------*/
|
||||
|
||||
eel_symbol_t *eel_set_integer(const char *name, int value)
|
||||
{
|
||||
eel_symbol_t *sym = eel_s_get(name, EST_VARIABLE);
|
||||
if(!sym)
|
||||
return NULL;
|
||||
eel_d_freestring(&sym->data);
|
||||
sym->data.type = EDT_INTEGER;
|
||||
sym->data.value.i = value;
|
||||
return sym;
|
||||
}
|
||||
|
||||
|
||||
eel_symbol_t *eel_set_real(const char *name, double value)
|
||||
{
|
||||
eel_symbol_t *sym = eel_s_get(name, EST_VARIABLE);
|
||||
if(!sym)
|
||||
return NULL;
|
||||
eel_d_freestring(&sym->data);
|
||||
sym->data.type = EDT_REAL;
|
||||
sym->data.value.r = value;
|
||||
return sym;
|
||||
}
|
||||
|
||||
|
||||
eel_symbol_t *eel_set_string(const char *name, const char *s)
|
||||
{
|
||||
eel_symbol_t *sym = eel_s_get(name, EST_VARIABLE);
|
||||
if(!sym)
|
||||
return NULL;
|
||||
eel_d_setstring(&sym->data, s);
|
||||
return sym;
|
||||
}
|
||||
|
||||
|
||||
eel_symbol_t *eel_set_data(const char *name, const eel_data_t *dat)
|
||||
{
|
||||
eel_symbol_t *sym = eel_s_get(name, EST_VARIABLE);
|
||||
if(!sym)
|
||||
return NULL;
|
||||
|
||||
eel_d_freestring(&sym->data);
|
||||
switch (dat->type)
|
||||
{
|
||||
case EDT_ILLEGAL:
|
||||
case EDT_REAL:
|
||||
case EDT_INTEGER:
|
||||
case EDT_CADDR:
|
||||
case EDT_SYMREF:
|
||||
case EDT_SYMTAB:
|
||||
case EDT_OPERATOR:
|
||||
case EDT_DIRECTIVE:
|
||||
case EDT_SPECIAL:
|
||||
sym->data = *dat;
|
||||
break;
|
||||
case EDT_STRING:
|
||||
case EDT_SYMNAME:
|
||||
sym->data.type = dat->type;
|
||||
if(eel_d_setstring(&sym->data, dat->value.s) < 0)
|
||||
return NULL;
|
||||
break;
|
||||
}
|
||||
return sym;
|
||||
}
|
||||
|
||||
|
||||
eel_symbol_t *eel_clone_symbol(const char *name, const eel_symbol_t *orig)
|
||||
{
|
||||
eel_symbol_t *sym = eel_s_new(name, orig->type);
|
||||
if(!sym)
|
||||
return NULL;
|
||||
|
||||
eel_d_freestring(&sym->data);
|
||||
switch (orig->data.type)
|
||||
{
|
||||
case EDT_ILLEGAL:
|
||||
case EDT_REAL:
|
||||
case EDT_INTEGER:
|
||||
case EDT_CADDR:
|
||||
case EDT_SYMREF:
|
||||
case EDT_SYMTAB:
|
||||
case EDT_OPERATOR:
|
||||
case EDT_DIRECTIVE:
|
||||
case EDT_SPECIAL:
|
||||
sym->data = orig->data;
|
||||
break;
|
||||
case EDT_STRING:
|
||||
case EDT_SYMNAME:
|
||||
sym->data.type = orig->data.type;
|
||||
if(eel_d_setstring(&sym->data, orig->data.value.s) < 0)
|
||||
return NULL;
|
||||
break;
|
||||
}
|
||||
return sym;
|
||||
}
|
||||
@@ -0,0 +1,376 @@
|
||||
/*(LGPL)
|
||||
---------------------------------------------------------------------------
|
||||
eel.c - The "Extensible Embeddable Language"
|
||||
---------------------------------------------------------------------------
|
||||
* Copyright (C) 2002, David Olofson
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
TODO:
|
||||
...or at least think about: Extend the dynamic typing to
|
||||
include functions. Ex:
|
||||
|
||||
set some_var, some_function;
|
||||
|
||||
will connect 'some_function' to 'some_var', so that the
|
||||
function is called to calculate the value whenever the
|
||||
variable is read. Obviously, such a variable becomes
|
||||
read-only! This could be worked around with the following
|
||||
syntax:
|
||||
|
||||
set some_var, read_function, write_function;
|
||||
|
||||
A handy syntax extension:
|
||||
|
||||
set some_var, some_function(...);
|
||||
|
||||
or
|
||||
|
||||
set some_other_var,
|
||||
{
|
||||
...
|
||||
some code
|
||||
...
|
||||
};
|
||||
|
||||
which would be interpreted as a nameless, single statement
|
||||
function being connected to 'some_var', and a nameless
|
||||
function with a normal body being connected to
|
||||
'some_other_var'.
|
||||
|
||||
The whole point with this is that it allows the way a
|
||||
variable gets written to change at run time, and that it's
|
||||
even applicable to code that isn't aware of this feature.
|
||||
|
||||
BTW, this is pretty similar to Delphi 'properties' -
|
||||
although you cannot turn variables into properties or vice
|
||||
versa, at run time, as you could do with this feature.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Scope/Namespace management sucks. Namespaces probably need
|
||||
to be arranged in a tree rather than a stack.
|
||||
|
||||
This becomes obvious when considering what happens when you
|
||||
call a function... The function executes in a scope that's
|
||||
the calling scope + a local namespace!
|
||||
|
||||
Indeed, this could be considered an interesting "feature",
|
||||
but I'm not sure it's as useful as it is confusing...
|
||||
|
||||
As a quick hack solution, one could reserve the first few
|
||||
namespaces (ie highest levels) for language extensions, to
|
||||
make it easy to install and remove extensions without them
|
||||
interfering with each other.
|
||||
|
||||
One could possible change the "scope level" into a "scope
|
||||
handle", and make a scope a "list of namespaces" rather
|
||||
than the current "lowest namespace index". That would allow
|
||||
multiple totally independent scopes under the same scripting
|
||||
engine.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _EEL_H_
|
||||
#define _EEL_H_
|
||||
|
||||
#include "e_script.h"
|
||||
#include "e_symtab.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define EEL_MAX_ARGS 128
|
||||
|
||||
#define _EEL_API_
|
||||
|
||||
#include "e_register.h"
|
||||
|
||||
|
||||
/*----------------------------------------------------------
|
||||
Toolkit for directive callbacks
|
||||
----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* The internal argument list. Avoid using this directly!
|
||||
*/
|
||||
extern int eel_arg_count;
|
||||
extern eel_data_t *eel_args;
|
||||
|
||||
/*
|
||||
* Add the last lval returned from the lexer to the internal
|
||||
* argument list.
|
||||
*/
|
||||
int eel_grab_arg(void);
|
||||
|
||||
/*
|
||||
* Clear the internal argument list starting at argument
|
||||
* 'first'.
|
||||
*/
|
||||
void eel_clear_args(int first);
|
||||
|
||||
/*
|
||||
* Parse arguments separated by one of the characters in
|
||||
* 'separators', until the character 'terminator' is
|
||||
* matched, or an error occurs.
|
||||
*
|
||||
* The arguments that are "grabbed" are added to the
|
||||
* internal argument list using eel_grab_arg(), and can
|
||||
* be retrieved, decoded and typechecked with eel_get_args()
|
||||
* if desired.
|
||||
*
|
||||
* Returns a negative value in case of an error.
|
||||
*/
|
||||
int eel_parse_args(const char *separators, char terminator);
|
||||
|
||||
|
||||
/*----------------------------------------------------------
|
||||
Toolkit for command callbacks
|
||||
----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Grab arguments from the internal argument list, verifying
|
||||
* that their types and count are in accordance with 'fmt'.
|
||||
* Results will be stored in the variables passed by
|
||||
* reference after the 'fmt' argument.
|
||||
*
|
||||
* Normally, the argument count not matching the number of
|
||||
* arguments specified in the format string will be reported
|
||||
* as an error. However, this can be changed by means of
|
||||
* argument tipples and optional arguments, denoted by the
|
||||
* '<', '>' and '[', ']' characters respectively.
|
||||
*
|
||||
* The return value is the number of arguments correctly
|
||||
* retrieved, or a negative value if something goes wrong.
|
||||
*
|
||||
* Format string syntax:
|
||||
*
|
||||
* Char Meaning Type
|
||||
*--------------------------------------------------------------------
|
||||
* * Skip argument N/A
|
||||
*
|
||||
* , Next argument (optional) N/A
|
||||
*
|
||||
* ? Grab any argument as is eel_data_t *
|
||||
*
|
||||
* < > Argument tipple. The argument spec in N/A
|
||||
* between the < and > will be repeated
|
||||
* until all arguments have been grabbed,
|
||||
* or an error occurs. The target args
|
||||
* should be ARRAYS and *must* be large
|
||||
* enough to fit all arguments retrieved,
|
||||
* or bad things will happen. Argument
|
||||
* tipples cannot be nested. There must
|
||||
* be no argument specifiers after the
|
||||
* '>', as an argument tipple repeats
|
||||
* "forever". Normally, the arguments
|
||||
* must match an *integer* number of
|
||||
* tipple repetitions - but this can be
|
||||
* changed using the Optional Argument
|
||||
* format codes.
|
||||
*
|
||||
* [ ] Optional arguments. Arguments beyond N/A
|
||||
* the '[' character after the 'argv'
|
||||
* array has been exhausted will not
|
||||
* generate an error, as this situation
|
||||
* normally would.
|
||||
*
|
||||
* Optional arguments inside argument
|
||||
* tipples apply only to the *last*
|
||||
* tipple repetition.
|
||||
*
|
||||
* Note that no argument specifiers must
|
||||
* follow the ']' character - or; optional
|
||||
* arguments must be the last ones in the
|
||||
* list.
|
||||
*
|
||||
* E Get any enum symbol. Any enum class eel_symbol_t *
|
||||
* is accepted. (Do check, if you care!)
|
||||
*
|
||||
* V Get value of any allowed type. This eel_data_t *
|
||||
* code can optionally be followed by a
|
||||
* list of allowed types, enclosed within
|
||||
* parentheses. If no list is specified,
|
||||
* all *value* data types are accepted,
|
||||
* including EDT_CADDR. Available types:
|
||||
* i integer (EDT_INTEGER)
|
||||
* r real (EDT_REAL)
|
||||
* s string (EDT_STRING)
|
||||
* c code address (EDT_CADDR)
|
||||
* e enum constant (EDT_SYMREF)
|
||||
* All but 'e' are set by default, if no
|
||||
* explicit list is provided.
|
||||
*
|
||||
* Note that symrefs are followed, to get
|
||||
* the values of the symbols they refer to,
|
||||
* except that when 'e' (enum constant) is
|
||||
* listed, symrefs to enum constants will
|
||||
* stay symrefs.
|
||||
*
|
||||
* e Get enum value. The argument should be int
|
||||
* INITIALIZED with the enum class. Only
|
||||
* enum constants from the right class
|
||||
* are accepted.
|
||||
*
|
||||
* i Get integer value int
|
||||
*
|
||||
* n Get or create variable. In the case of eel_symbol_t *
|
||||
* a new variable being created, the
|
||||
* argument has to be a string holding the
|
||||
* name of the new variable. The type of
|
||||
* a new variable is undefined.
|
||||
*
|
||||
* r Get real value double
|
||||
*
|
||||
* s Get string value char *
|
||||
* NOTE: Currently it's NOT possible to
|
||||
* get non-string values casted to strings.
|
||||
* (We need a fast, reference counting
|
||||
* string package...)
|
||||
*
|
||||
* v Get variable (must be defined) eel_symbol_t *
|
||||
*
|
||||
* f Get function "address". The returned eel_symbol_t *
|
||||
* symbol will be of type EST_FUNCTION.
|
||||
*
|
||||
* Any other character in the format string in matched with that
|
||||
* respective character in the input.
|
||||
*/
|
||||
int eel_get_args(const char *fmt, ...);
|
||||
|
||||
|
||||
/*
|
||||
* Like eel_get_args(), but reads from the specified eel_data_t
|
||||
* array instead of the internal argument list.
|
||||
*/
|
||||
int eel_get_args_from(int argc, struct eel_data_t *argv, const char *fmt, ...);
|
||||
|
||||
/*
|
||||
* Print a nice error "prompt" with file name, line #
|
||||
* and arg #, followed by your formatted error message,
|
||||
* followed by a newline ('\n') where appropriate. (Don't
|
||||
* add this yourself, unless you need multiple lines.)
|
||||
*
|
||||
* Note that syntax checking and most type
|
||||
* and error checking is done automatically
|
||||
* by EEL (mostly in eel_get_args()). This
|
||||
* function is only for errors that EEL
|
||||
* can't detect.
|
||||
*
|
||||
* Returns total number of characters printed.
|
||||
*/
|
||||
int eel_error(const char *format, ...);
|
||||
|
||||
/*
|
||||
* Returns a string describing the specified symbol
|
||||
* in a way that would complete the sentences:
|
||||
* "This is ..."
|
||||
* "Expected ..."
|
||||
*/
|
||||
const char *eel_symbol_is(eel_symbol_t *s);
|
||||
|
||||
/*
|
||||
* As eel_symbol_is(), but for data containers.
|
||||
*/
|
||||
const char *eel_data_is(eel_data_t *d);
|
||||
|
||||
|
||||
|
||||
/*----------------------------------------------------------
|
||||
Runtime API
|
||||
----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Set the EEL path for scripts and includes.
|
||||
*
|
||||
* This must be a valid path, terminated by a
|
||||
* '/', '\', ':' or whatever "directory separator"
|
||||
* the current platform is using, and will be
|
||||
* prepended to file names passed to the #include
|
||||
* directive.
|
||||
*/
|
||||
void eel_set_path(const char *path);
|
||||
|
||||
/* Returns the current EEL path. */
|
||||
const char *eel_path(void);
|
||||
|
||||
/* Open/Close EEL. (Keep track of nested calls!) */
|
||||
int eel_open(void);
|
||||
void eel_close();
|
||||
|
||||
/*
|
||||
* Execute code inside script 'handle', starting at 'pos'.
|
||||
*
|
||||
* Execution will take place as a "sub procedure", with it's
|
||||
* own context¨, but *not* automatically it's own *scope*.
|
||||
* This is because most real applications will require
|
||||
* scripts to be passed some "arguments", which is actually
|
||||
* done by creating a few variables before the script is
|
||||
* called. Obviously, the code that sets up the "argument
|
||||
* variables" and calls eel_run() will also have to do any
|
||||
* scope pushing and popping *around* these calls - which is
|
||||
* why it can't be done inside eel_run().
|
||||
*
|
||||
* The following events will end execution:
|
||||
* - A statement gives a "stop execution" return code.
|
||||
* - The top level scope is terminated; ie an unmatched
|
||||
* curly brace ('}') is found.
|
||||
* - EOF is reached.
|
||||
* - An error occurs.
|
||||
*
|
||||
* Returns the result, which will be negative in the case
|
||||
* of an error.
|
||||
*/
|
||||
int eel_call(int handle, int pos);
|
||||
|
||||
/*
|
||||
* Run a script from the start.
|
||||
*
|
||||
* Currently 100% equivalent to eel_call('handle', 0);
|
||||
*/
|
||||
int eel_run(int handle);
|
||||
|
||||
/*
|
||||
* Create or set variable 'name' to the specified value.
|
||||
* Existing symbols *must* be of type ST_VARIABLE, or
|
||||
* these calls will fail.
|
||||
*
|
||||
* Returns the changed/created symbol, or NULL if the
|
||||
* operation failed.
|
||||
*/
|
||||
eel_symbol_t *eel_set_integer(const char *name, int value);
|
||||
eel_symbol_t *eel_set_real(const char *name, double value);
|
||||
eel_symbol_t *eel_set_string(const char *name, const char *s);
|
||||
eel_symbol_t *eel_set_data(const char *name, const eel_data_t *dat);
|
||||
|
||||
/*
|
||||
* Make an exact copy of symbol 'orig', except for the name,
|
||||
* which will be 'name'. Symbol 'name' must not exist before
|
||||
* this call.
|
||||
*
|
||||
* Returns the created symbol, or NULL if the operation failed.
|
||||
*/
|
||||
eel_symbol_t *eel_clone_symbol(const char *name, const eel_symbol_t *orig);
|
||||
|
||||
#undef _EEL_API_
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* _EEL_H_ */
|
||||
Reference in New Issue
Block a user