From a19a216bc60160c162e616145ef091dd18ce4e61 Mon Sep 17 00:00:00 2001 From: Skip Montanaro Date: Tue, 16 Feb 2021 14:40:46 -0600 Subject: Python 0.9.1 as posted in alt.sources --- src/Grammar | 72 +++ src/Makefile | 508 +++++++++++++++ src/PROTO.h | 79 +++ src/README | 11 + src/To.do | 11 + src/acceler.c | 136 ++++ src/allobjects.h | 50 ++ src/amoebamodule.c | 774 +++++++++++++++++++++++ src/asa.c | 494 +++++++++++++++ src/asa.h | 33 + src/assert.h | 25 + src/audiomodule.c | 615 ++++++++++++++++++ src/bitset.c | 99 +++ src/bitset.h | 46 ++ src/bltinmodule.c | 559 +++++++++++++++++ src/bltinmodule.h | 27 + src/ceval.c | 1436 ++++++++++++++++++++++++++++++++++++++++++ src/ceval.h | 33 + src/cgen | 458 ++++++++++++++ src/cgensupport.c | 393 ++++++++++++ src/cgensupport.h | 39 ++ src/classobject.c | 298 +++++++++ src/classobject.h | 44 ++ src/compile.c | 1772 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/compile.h | 47 ++ src/config.c | 180 ++++++ src/configmac.c | 109 ++++ src/cstubs | 999 +++++++++++++++++++++++++++++ src/dictobject.c | 605 ++++++++++++++++++ src/dictobject.h | 44 ++ src/errcode.h | 36 ++ src/errors.c | 196 ++++++ src/errors.h | 58 ++ src/fgetsintr.c | 94 +++ src/fgetsintr.h | 25 + src/fileobject.c | 293 +++++++++ src/fileobject.h | 33 + src/firstsets.c | 133 ++++ src/floatobject.c | 271 ++++++++ src/floatobject.h | 44 ++ src/fmod.c | 51 ++ src/frameobject.c | 156 +++++ src/frameobject.h | 80 +++ src/funcobject.c | 113 ++++ src/funcobject.h | 33 + src/getcwd.c | 102 +++ src/graminit.c | 1094 ++++++++++++++++++++++++++++++++ src/graminit.h | 66 ++ src/grammar.c | 233 +++++++ src/grammar.h | 105 ++++ src/grammar1.c | 75 +++ src/import.c | 259 ++++++++ src/import.h | 31 + src/intobject.c | 307 +++++++++ src/intobject.h | 72 +++ src/intrcheck.c | 144 +++++ src/listnode.c | 93 +++ src/listobject.c | 519 +++++++++++++++ src/listobject.h | 59 ++ src/macmodule.c | 246 ++++++++ src/malloc.h | 63 ++ src/mathmodule.c | 180 ++++++ src/metagrammar.c | 176 ++++++ src/metagrammar.h | 30 + src/methodobject.c | 147 +++++ src/methodobject.h | 42 ++ src/modsupport.c | 381 +++++++++++ src/modsupport.h | 27 + src/moduleobject.c | 154 +++++ src/moduleobject.h | 33 + src/node.c | 100 +++ src/node.h | 58 ++ src/object.c | 290 +++++++++ src/object.h | 324 ++++++++++ src/objimpl.h | 50 ++ src/opcode.h | 109 ++++ src/panelmodule.c | 1090 ++++++++++++++++++++++++++++++++ src/parser.c | 423 +++++++++++++ src/parser.h | 50 ++ src/parsetok.c | 158 +++++ src/parsetok.h | 29 + src/patchlevel.h | 1 + src/pgen.c | 751 ++++++++++++++++++++++ src/pgen.h | 30 + src/pgenheaders.h | 50 ++ src/pgenmain.c | 148 +++++ src/posixmodule.c | 427 +++++++++++++ src/printgrammar.c | 149 +++++ src/profmain.c | 133 ++++ src/pythonmain.c | 440 +++++++++++++ src/pythonrun.h | 47 ++ src/regexp.c | 1394 +++++++++++++++++++++++++++++++++++++++++ src/regexp.h | 51 ++ src/regexpmodule.c | 191 ++++++ src/regmagic.h | 29 + src/regsub.c | 115 ++++ src/rltokenizer.c | 26 + src/sc_errors.c | 145 +++++ src/sc_errors.h | 41 ++ src/sc_global.h | 137 ++++ src/sc_interpr.c | 1352 +++++++++++++++++++++++++++++++++++++++ src/scdbg.c | 152 +++++ src/sigtype.h | 51 ++ src/stdwinmodule.c | 1697 +++++++++++++++++++++++++++++++++++++++++++++++++ src/stdwinobject.h | 31 + src/strdup.c | 39 ++ src/strerror.c | 47 ++ src/stringobject.c | 347 ++++++++++ src/stringobject.h | 63 ++ src/strtol.c | 122 ++++ src/structmember.c | 158 +++++ src/structmember.h | 64 ++ src/stubcode.h | 28 + src/sysmodule.c | 214 +++++++ src/sysmodule.h | 30 + src/timemodule.c | 229 +++++++ src/token.h | 69 ++ src/tokenizer.c | 523 ++++++++++++++++ src/tokenizer.h | 53 ++ src/traceback.c | 217 +++++++ src/traceback.h | 30 + src/tupleobject.c | 287 +++++++++ src/tupleobject.h | 56 ++ src/typeobject.c | 61 ++ src/xxobject.c | 131 ++++ 125 files changed, 29287 insertions(+) create mode 100644 src/Grammar create mode 100644 src/Makefile create mode 100644 src/PROTO.h create mode 100644 src/README create mode 100644 src/To.do create mode 100644 src/acceler.c create mode 100644 src/allobjects.h create mode 100644 src/amoebamodule.c create mode 100644 src/asa.c create mode 100644 src/asa.h create mode 100644 src/assert.h create mode 100644 src/audiomodule.c create mode 100644 src/bitset.c create mode 100644 src/bitset.h create mode 100644 src/bltinmodule.c create mode 100644 src/bltinmodule.h create mode 100644 src/ceval.c create mode 100644 src/ceval.h create mode 100644 src/cgen create mode 100644 src/cgensupport.c create mode 100644 src/cgensupport.h create mode 100644 src/classobject.c create mode 100644 src/classobject.h create mode 100644 src/compile.c create mode 100644 src/compile.h create mode 100644 src/config.c create mode 100644 src/configmac.c create mode 100644 src/cstubs create mode 100644 src/dictobject.c create mode 100644 src/dictobject.h create mode 100644 src/errcode.h create mode 100644 src/errors.c create mode 100644 src/errors.h create mode 100644 src/fgetsintr.c create mode 100644 src/fgetsintr.h create mode 100644 src/fileobject.c create mode 100644 src/fileobject.h create mode 100644 src/firstsets.c create mode 100644 src/floatobject.c create mode 100644 src/floatobject.h create mode 100644 src/fmod.c create mode 100644 src/frameobject.c create mode 100644 src/frameobject.h create mode 100644 src/funcobject.c create mode 100644 src/funcobject.h create mode 100644 src/getcwd.c create mode 100644 src/graminit.c create mode 100644 src/graminit.h create mode 100644 src/grammar.c create mode 100644 src/grammar.h create mode 100644 src/grammar1.c create mode 100644 src/import.c create mode 100644 src/import.h create mode 100644 src/intobject.c create mode 100644 src/intobject.h create mode 100644 src/intrcheck.c create mode 100644 src/listnode.c create mode 100644 src/listobject.c create mode 100644 src/listobject.h create mode 100644 src/macmodule.c create mode 100644 src/malloc.h create mode 100644 src/mathmodule.c create mode 100644 src/metagrammar.c create mode 100644 src/metagrammar.h create mode 100644 src/methodobject.c create mode 100644 src/methodobject.h create mode 100644 src/modsupport.c create mode 100644 src/modsupport.h create mode 100644 src/moduleobject.c create mode 100644 src/moduleobject.h create mode 100644 src/node.c create mode 100644 src/node.h create mode 100644 src/object.c create mode 100644 src/object.h create mode 100644 src/objimpl.h create mode 100644 src/opcode.h create mode 100644 src/panelmodule.c create mode 100644 src/parser.c create mode 100644 src/parser.h create mode 100644 src/parsetok.c create mode 100644 src/parsetok.h create mode 100644 src/patchlevel.h create mode 100644 src/pgen.c create mode 100644 src/pgen.h create mode 100644 src/pgenheaders.h create mode 100644 src/pgenmain.c create mode 100644 src/posixmodule.c create mode 100644 src/printgrammar.c create mode 100644 src/profmain.c create mode 100644 src/pythonmain.c create mode 100644 src/pythonrun.h create mode 100644 src/regexp.c create mode 100644 src/regexp.h create mode 100644 src/regexpmodule.c create mode 100644 src/regmagic.h create mode 100644 src/regsub.c create mode 100644 src/rltokenizer.c create mode 100644 src/sc_errors.c create mode 100644 src/sc_errors.h create mode 100644 src/sc_global.h create mode 100644 src/sc_interpr.c create mode 100644 src/scdbg.c create mode 100644 src/sigtype.h create mode 100644 src/stdwinmodule.c create mode 100644 src/stdwinobject.h create mode 100644 src/strdup.c create mode 100644 src/strerror.c create mode 100644 src/stringobject.c create mode 100644 src/stringobject.h create mode 100644 src/strtol.c create mode 100644 src/structmember.c create mode 100644 src/structmember.h create mode 100644 src/stubcode.h create mode 100644 src/sysmodule.c create mode 100644 src/sysmodule.h create mode 100644 src/timemodule.c create mode 100644 src/token.h create mode 100644 src/tokenizer.c create mode 100644 src/tokenizer.h create mode 100644 src/traceback.c create mode 100644 src/traceback.h create mode 100644 src/tupleobject.c create mode 100644 src/tupleobject.h create mode 100644 src/typeobject.c create mode 100644 src/xxobject.c (limited to 'src') diff --git a/src/Grammar b/src/Grammar new file mode 100644 index 0000000..574acd6 --- /dev/null +++ b/src/Grammar @@ -0,0 +1,72 @@ +# Grammar for Python, version 4 + +# Changes compared to version 3: +# Removed 'dir' statement. +# Function call argument is a testlist instead of exprlist. + +# Changes compared to version 2: +# The syntax of Boolean operations is changed to use more +# conventional priorities: or < and < not. + +# Changes compared to version 1: +# modules and scripts are unified; +# 'quit' is gone (use ^D); +# empty_stmt is gone, replaced by explicit NEWLINE where appropriate; +# 'import' and 'def' aren't special any more; +# added 'from' NAME option on import clause, and '*' to import all; +# added class definition. + +# Start symbols for the grammar: +# single_input is a single interactive statement; +# file_input is a module or sequence of commands read from an input file; +# expr_input is the input for the input() function; +# eval_input is the input for the eval() function. + +# NB: compound_stmt in single_input is followed by extra NEWLINE! +single_input: NEWLINE | simple_stmt | compound_stmt NEWLINE +file_input: (NEWLINE | stmt)* ENDMARKER +expr_input: testlist NEWLINE +eval_input: testlist ENDMARKER + +funcdef: 'def' NAME parameters ':' suite +parameters: '(' [fplist] ')' +fplist: fpdef (',' fpdef)* +fpdef: NAME | '(' fplist ')' + +stmt: simple_stmt | compound_stmt +simple_stmt: expr_stmt | print_stmt | pass_stmt | del_stmt | flow_stmt | import_stmt +expr_stmt: (exprlist '=')* exprlist NEWLINE +# For assignments, additional restrictions enforced by the interpreter +print_stmt: 'print' (test ',')* [test] NEWLINE +del_stmt: 'del' exprlist NEWLINE +pass_stmt: 'pass' NEWLINE +flow_stmt: break_stmt | return_stmt | raise_stmt +break_stmt: 'break' NEWLINE +return_stmt: 'return' [testlist] NEWLINE +raise_stmt: 'raise' expr [',' expr] NEWLINE +import_stmt: 'import' NAME (',' NAME)* NEWLINE | 'from' NAME 'import' ('*' | NAME (',' NAME)*) NEWLINE +compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | funcdef | classdef +if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite] +while_stmt: 'while' test ':' suite ['else' ':' suite] +for_stmt: 'for' exprlist 'in' exprlist ':' suite ['else' ':' suite] +try_stmt: 'try' ':' suite (except_clause ':' suite)* ['finally' ':' suite] +except_clause: 'except' [expr [',' expr]] +suite: simple_stmt | NEWLINE INDENT NEWLINE* (stmt NEWLINE*)+ DEDENT + +test: and_test ('or' and_test)* +and_test: not_test ('and' not_test)* +not_test: 'not' not_test | comparison +comparison: expr (comp_op expr)* +comp_op: '<'|'>'|'='|'>' '='|'<' '='|'<' '>'|'in'|'not' 'in'|'is'|'is' 'not' +expr: term (('+'|'-') term)* +term: factor (('*'|'/'|'%') factor)* +factor: ('+'|'-') factor | atom trailer* +atom: '(' [testlist] ')' | '[' [testlist] ']' | '{' '}' | '`' testlist '`' | NAME | NUMBER | STRING +trailer: '(' [testlist] ')' | '[' subscript ']' | '.' NAME +subscript: expr | [expr] ':' [expr] +exprlist: expr (',' expr)* [','] +testlist: test (',' test)* [','] + +classdef: 'class' NAME parameters ['=' baselist] ':' suite +baselist: atom arguments (',' atom arguments)* +arguments: '(' [testlist] ')' diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..d47eceb --- /dev/null +++ b/src/Makefile @@ -0,0 +1,508 @@ +# /*********************************************************** +# Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +# Netherlands. +# +# All Rights Reserved +# +# Permission to use, copy, modify, and distribute this software and its +# documentation for any purpose and without fee is hereby granted, +# provided that the above copyright notice appear in all copies and that +# both that copyright notice and this permission notice appear in +# supporting documentation, and that the names of Stichting Mathematisch +# Centrum or CWI not be used in advertising or publicity pertaining to +# distribution of the software without specific, written prior permission. +# +# STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +# THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +# FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +# FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# +# ******************************************************************/ + +# Makefile for Python +# =================== +# +# If you are in a hurry, you can just edit this Makefile to choose the +# correct settings for SYSV and RANLIB below, and type "make" in this +# directory. If you are using a recent version of SunOS (or Ultrix?) +# you don't even have to edit: the Makefile comes pre-configured for +# such systems with all configurable options turned off, building the +# minimal portable version of the Python interpreter. +# +# If have more time, read the section on configurable options below. +# It may still be wise to begin building the minimal portable Python, +# to see if it works at all, and select options later. You don't have +# to rebuild all objects when you turn on options; all dependencies +# are concentrated in the file "config.c" which is rebuilt whenever +# the Makefile changes. (Except if you turn on the GNU Readline option +# you may have to toss out the tokenizer.o object.) + + +# Operating System Defines (ALWAYS READ THIS) +# =========================================== + +# Uncomment the following line if you are using a System V derivative. +# This must be used, for instance, on an SGI IRIS. Don't use it for +# SunOS. (This is only needed by posixmodule.c...) + +#SYSVDEF= -DSYSV + +# Choose one of the following two lines depending on whether your system +# requires the use of 'ranlib' after creating a library, or not. + +#RANLIB = true # For System V +RANLIB = ranlib # For BSD + +# If your system doesn't have symbolic links, uncomment the following +# line. + +#NOSYMLINKDEF= -DNO_LSTAT + + +# Installation Options +# ==================== + +# You may want to change DEFPYTHONPATH to reflect where you install the +# Python module library. The default contains "../lib" so running +# the interpreter from the source/build directory as distributed will +# find the library (admittedly a hack). + +DEFPYTHONPATH= .:/usr/local/lib/python:/ufs/guido/lib/python:../lib + + +# For "Pure" BSD Systems +# ====================== +# +# "Pure" BSD systems (as opposed to enhanced BSD derivatives like SunOS) +# often miss certain standard library functions. Source for +# these is provided, you just have to turn it on. This may work for +# other systems as well, where these things are needed. + +# If your system does not have a strerror() function in the library, +# uncomment the following two lines to use one I wrote. (Actually, this +# is missing in most systems I have encountered, so it is turned on +# in the Makefile. Turn it off if your system doesn't have sys_errlist.) + +STRERROR_SRC= strerror.c +STRERROR_OBJ= strerror.o + +# If your BSD system does not have a fmod() function in the library, +# uncomment the following two lines to use one I wrote. + +#FMOD_SRC= fmod.c +#FMOD_OBJ= fmod.o + +# If your BSD system does not have a strtol() function in the library, +# uncomment the following two lines to use one I wrote. + +#STRTOL_SRC= strtol.c +#STRTOL_OBJ= strtol.o + +# If your BSD system does not have a getcwd() function in the library, +# but it does have a getwd() function, uncomment the following two lines +# to use one I wrote. (If you don't have getwd() either, turn on the +# NO_GETWD #define in getcwd.c.) + +#GETCWD_SRC= getcwd.c +#GETCWD_OBJ= getcwd.o + +# If your signal() function believes signal handlers return int, +# uncomment the following line. + +#SIGTYPEDEF= -DSIGTYPE=int + + +# Further porting hints +# ===================== +# +# If you don't have the header file , but you do have +# , create a file "string.h" in this directory which contains +# the single line "#include ", and add "-I." to CFLAGS. +# If you don't have the functions strchr and strrchr, add definitions +# "-Dstrchr=index -Dstrrchr=rindex" to CFLAGS. (NB: CFLAGS is not +# defined in this Makefile.) + + +# Configurable Options +# ==================== +# +# Python can be configured to interface to various system libraries that +# are not available on all systems. It is also possible to configure +# the input module to use the GNU Readline library for interactive +# input. For each configuration choice you must uncomment the relevant +# section of the Makefile below. Note: you may also have to change a +# pathname and/or an architecture identifier that is hardcoded in the +# Makefile. +# +# Read the comments to determine if you can use the option. (You can +# always leave all options off and build a minimal portable version of +# Python.) + + +# BSD Time Option +# =============== +# +# This option does not add a new module but adds two functions to +# an existing module. +# +# It implements time.millisleep() and time.millitimer() +# using the BSD system calls select() and gettimeofday(). +# +# Uncomment the following line to select this option. + +#BSDTIMEDEF= -DBSD_TIME + + +# GNU Readline Option +# =================== +# +# If you have the sources of the GNU Readline library you can have +# full interactive command line editing and history in Python. +# The GNU Readline library is distributed with the BASH shell +# (I only know of version 1.05). You must build the GNU Readline +# library and the alloca routine it needs in their own source +# directories (which are subdirectories of the basg source directory), +# and plant a pointer to the BASH source directory in this Makefile. +# +# Uncomment and edit the following block to use the GNU Readline option. +# - Edit the definition of BASHDIR to point to the bash source tree. +# You may have to fix the definition of LIBTERMCAP; leave the LIBALLOCA +# definition commented if alloca() is in your C library. + +#BASHDIR= ../../bash-1.05 +#LIBREADLINE= $(BASHDIR)/readline/libreadline.a +#LIBALLOCA= $(BASHDIR)/alloc-files/alloca.o +#LIBTERMCAP= -ltermcap +#RL_USE = -DUSE_READLINE +#RL_LIBS= $(LIBREADLINE) $(LIBALLOCA) $(LIBTERMCAP) +#RL_LIBDEPS= $(LIBREADLINE) $(LIBALLOCA) + + +# STDWIN Option +# ============= +# +# If you have the sources of STDWIN (by the same author) you can +# configure Python to incorporate the built-in module 'stdwin'. +# This requires a fairly recent version of STDWIN (dated late 1990). +# +# Uncomment and edit the following block to use the STDWIN option. +# - Edit the STDWINDIR defition to reflect the top of the STDWIN source +# tree. +# - Edit the ARCH definition to reflect your system's architecture +# (usually the program 'arch' or 'machine' returns this). +# You may have to edit the LIBX11 defition to reflect the location of +# the X11 runtime library if it is non-standard. + +#STDWINDIR= ../../stdwin +#ARCH= sgi +#LIBSTDWIN= $(STDWINDIR)/Build/$(ARCH)/x11/lib/lib.a +#LIBX11 = -lX11 +#STDW_INCL= -I$(STDWINDIR)/H +#STDW_USE= -DUSE_STDWIN +#STDW_LIBS= $(LIBSTDWIN) $(LIBX11) +#STDW_LIBDEPS= $(LIBSTDWIN) +#STDW_SRC= stdwinmodule.c +#STDW_OBJ= stdwinmodule.o + + +# Amoeba Option +# ============= +# +# If you have the Amoeba 4.0 distribution (Beta or otherwise) you can +# configure Python to incorporate the built-in module 'amoeba'. +# (Python can also be built for native Amoeba, but it requires more +# work and thought. Contact the author.) +# +# Uncomment and edit the following block to use the Amoeba option. +# - Edit the AMOEBADIR defition to reflect the top of the Amoeba source +# tree. +# - Edit the AM_CONF definition to reflect the machine/operating system +# configuration needed by Amoeba (this is the name of a subdirectory +# of $(AMOEBADIR)/conf/unix, e.g., vax.ultrix). + +#AMOEBADIR= /usr/amoeba +#AM_CONF= mipseb.irix +#LIBAMUNIX= $(AMOEBADIR)/conf/unix/$(AM_CONF)/lib/amunix/libamunix.a +#AM_INCL= -I$(AMOEBADIR)/src/h +#AM_USE = -DUSE_AMOEBA +#AM_LIBDEPS= $(LIBAMUNIX) +#AM_LIBS= $(LIBAMUNIX) +#AM_SRC = amoebamodule.c sc_interpr.c sc_errors.c +#AM_OBJ = amoebamodule.o sc_interpr.o sc_errors.o + + +# Silicon Graphics IRIS Options +# ============================= +# +# The following three options are only relevant if you are using a +# Silicon Graphics IRIS machine. These have been tested with IRIX 3.3.1 +# on a 4D/25. + + +# GL Option +# ========= +# +# This option incorporates the built-in module 'gl', which provides a +# complete interface to the Silicon Graphics GL library. It adds +# about 70K to the Python text size and about 260K to the unstripped +# binary size. +# +# NOTE WHEN BUILDING FOR THE FIRST TIME: +# There is a circular dependency in the build process: you need to have +# a working Python interpreter before you can build a Python interpreter +# that incorporates the 'gl' module -- the source file 'glmodule.c' is +# not distributed (it's about 140K!) and a Python script is used to +# create it. Thus, you first have to build python without the the GL +# and Panel options, then edit the Makefile to turn them (or at least GL) +# on and rebuild. You may also have to set PYTHONPATH to point to +# the place where the module library is for the generation script to +# work. +# +# Uncomment the following block to use the GL option. + +#GL_USE = -DUSE_GL +#GL_LIBDEPS= +#GL_LIBS= -lgl_s +#GL_SRC = glmodule.c cgensupport.c +#GL_OBJ = glmodule.o cgensupport.o + + +# Panel Option +# ============ +# +# If you have source to the NASA Ames Panel Library, you can configure +# Python to incorporate the built-in module 'pnl', which is used byu +# the standard module 'panel' to provide an interface to most features +# of the Panel Library. This option requires that you also turn on the +# GL option. It adds about 100K to the Python text size and about 160K +# to the unstripped binary size. This requires Panel Library version 9.7 +# (for lower versions you may have to remove some functionality -- send +# me the patches if you bothered to do this). +# +# Uncomment and edit the following block to use the Panel option. +# - Edit the PANELDIR definition to point to the top-level directory +# of the Panel distribution tree. + +#PANELDIR= /usr/people/guido/src/pl +#PANELLIBDIR= $(PANELDIR)/library +#LIBPANEL= $(PANELLIBDIR)/lib/libpanel.a +#PANEL_USE= -DUSE_PANEL +#PANEL_INCL= -I$(PANELLIBDIR)/include +#PANEL_LIBDEPS= $(LIBPANEL) +#PANEL_LIBS= $(LIBPANEL) +#PANEL_SRC= panelmodule.c +#PANEL_OBJ= panelmodule.o + + +# Audio Option +# ============ +# +# This option lets you play with /dev/audio on the IRIS 4D/25. +# It incorporates the built-in module 'audio'. +# Warning: using the asynchronous I/O facilities of this module can +# create a second 'thread', which looks in the listings of 'ps' like a +# forked child. However, it shares its address space with the parent. +# +# Uncomment the following block to use the Audio option. + +#AUDIO_USE= -DUSE_AUDIO +#AUDIO_SRC= audiomodule.c asa.c +#AUDIO_OBJ= audiomodule.o asa.o + + +# Major Definitions +# ================= + +STANDARD_OBJ= acceler.o bltinmodule.o ceval.o classobject.o \ + compile.o dictobject.o errors.o fgetsintr.o \ + fileobject.o floatobject.o $(FMOD_OBJ) frameobject.o \ + funcobject.o $(GETCWD_OBJ) \ + graminit.o grammar1.o import.o \ + intobject.o intrcheck.o listnode.o listobject.o \ + mathmodule.o methodobject.o modsupport.o \ + moduleobject.o node.o object.o parser.o \ + parsetok.o posixmodule.o regexp.o regexpmodule.o \ + strdup.o $(STRERROR_OBJ) \ + stringobject.o $(STRTOL_OBJ) structmember.o \ + sysmodule.o timemodule.o tokenizer.o traceback.o \ + tupleobject.o typeobject.o + +STANDARD_SRC= acceler.c bltinmodule.c ceval.c classobject.c \ + compile.c dictobject.c errors.c fgetsintr.c \ + fileobject.c floatobject.c $(FMOD_SRC) frameobject.c \ + funcobject.c $(GETCWD_SRC) \ + graminit.c grammar1.c import.c \ + intobject.c intrcheck.c listnode.c listobject.c \ + mathmodule.c methodobject.c modsupport.c \ + moduleobject.c node.c object.c parser.c \ + parsetok.c posixmodule.c regexp.c regexpmodule.c \ + strdup.c $(STRERROR_SRC) \ + stringobject.c $(STRTOL_SRC) structmember.c \ + sysmodule.c timemodule.c tokenizer.c traceback.c \ + tupleobject.c typeobject.c + +CONFIGDEFS= $(STDW_USE) $(AM_USE) $(AUDIO_USE) $(GL_USE) $(PANEL_USE) \ + '-DPYTHONPATH="$(DEFPYTHONPATH)"' + +CONFIGINCLS= $(STDW_INCL) + +LIBDEPS= libpython.a $(STDW_LIBDEPS) $(AM_LIBDEPS) \ + $(GL_LIBDEPS) $(PANEL_LIBSDEP) $(RL_LIBDEPS) + +# NB: the ordering of items in LIBS is significant! +LIBS= libpython.a $(STDW_LIBS) $(AM_LIBS) \ + $(PANEL_LIBS) $(GL_LIBS) $(RL_LIBS) -lm + +LIBOBJECTS= $(STANDARD_OBJ) $(STDW_OBJ) $(AM_OBJ) $(AUDIO_OBJ) \ + $(GL_OBJ) $(PANEL_OBJ) + +LIBSOURCES= $(STANDARD_SRC) $(STDW_SRC) $(AM_SRC) $(AUDIO_SRC) \ + $(GL_SRC) $(PANEL_SRC) + +OBJECTS= pythonmain.o config.o + +SOURCES= $(LIBSOURCES) pythonmain.c config.c + +GENOBJECTS= acceler.o fgetsintr.o grammar1.o \ + intrcheck.o listnode.o node.o parser.o \ + parsetok.o strdup.o tokenizer.o bitset.o \ + firstsets.o grammar.o metagrammar.o pgen.o \ + pgenmain.o printgrammar.o + +GENSOURCES= acceler.c fgetsintr.c grammar1.c \ + intrcheck.c listnode.c node.c parser.c \ + parsetok.c strdup.c tokenizer.c bitset.c \ + firstsets.c grammar.c metagrammar.c pgen.c \ + pgenmain.c printgrammar.c + + +# Main Targets +# ============ + +python: libpython.a $(OBJECTS) $(LIBDEPS) Makefile + $(CC) $(CFLAGS) $(OBJECTS) $(LIBS) -o @python + mv @python python + +libpython.a: $(LIBOBJECTS) + -rm -f @lib + ar cr @lib $(LIBOBJECTS) + $(RANLIB) @lib + mv @lib libpython.a + +python_gen: $(GENOBJECTS) $(RL_LIBDEPS) + $(CC) $(CFLAGS) $(GENOBJECTS) $(RL_LIBS) -o python_gen + + +# Utility Targets +# =============== + +# Don't take the output from lint too seriously. I have not attempted +# to make Python lint-free. But I use function prototypes. + +LINTFLAGS= -h + +LINTCPPFLAGS= $(CONFIGDEFS) $(CONFIGINCLS) $(SYSVDEF) \ + $(AM_INCL) $(PANEL_INCL) + +LINT= lint + +lint:: $(SOURCES) + $(LINT) $(LINTFLAGS) $(LINTCPPFLAGS) $(SOURCES) + +lint:: $(GENSOURCES) + $(LINT) $(LINTFLAGS) $(GENSOURCES) + +# Generating dependencies is only necessary if you intend to hack Python. +# You may change $(MKDEP) to your favorite dependency generator (it should +# edit the Makefile in place). + +MKDEP= mkdep + +depend:: + $(MKDEP) $(LINTCPPFLAGS) $(SOURCES) $(GENSOURCES) + +# You may change $(CTAGS) to suit your taste... + +CTAGS= ctags -t -w + +HEADERS= *.h + +tags: $(SOURCES) $(GENSOURCES) $(HEADERS) + $(CTAGS) $(SOURCES) $(GENSOURCES) $(HEADERS) + +clean:: + -rm -f *.o core [,#@]* + +clobber:: clean + -rm -f python python_gen libpython.a tags + + +# Build Special Objects +# ===================== + +# You may change $(COMPILE) to reflect the default .c.o rule... + +COMPILE= $(CC) -c $(CFLAGS) + +amoebamodule.o: amoebamodule.c + $(COMPILE) $(AM_INCL) $*.c + +config.o: config.c Makefile + $(COMPILE) $(CONFIGDEFS) $(CONFIGINCLS) $*.c + +fgetsintr.o: fgetsintr.c + $(COMPILE) $(SIGTYPEDEF) $*.c + +intrcheck.o: intrcheck.c + $(COMPILE) $(SIGTYPEDEF) $*.c + +panelmodule.o: panelmodule.c + $(COMPILE) $(PANEL_INCL) $*.c + +posixmodule.o: posixmodule.c + $(COMPILE) $(SYSVDEF) $(NOSYMLINKDEF) $*.c + +sc_interpr.o: sc_interpr.c + $(COMPILE) $(AM_INCL) $*.c + +sc_error.o: sc_error.c + $(COMPILE) $(AM_INCL) $*.c + +stdwinmodule.o: stdwinmodule.c + $(COMPILE) $(STDW_INCL) $*.c + +timemodule.o: timemodule.c + $(COMPILE) $(SIGTYPEDEF) $(BSDTIMEDEF) $*.c + +tokenizer.o: tokenizer.c + $(COMPILE) $(RL_USE) $*.c + +.PRECIOUS: python libpython.a glmodule.c graminit.c graminit.h + + +# Generated Sources +# ================= +# +# Some source files are (or may be) generated. +# The rules for doing so are given here. + +# Build "glmodule.c", the GL interface. +# See important note at "GL Option" above. +# You may have to set and export PYTHONPATH for this to work. +# Ignore the messages emitted by the cgen script as long as its exit +# status is zero. +# Also ignore the warnings emitted while compiling glmodule.c; it works. + +glmodule.c: cstubs cgen + python cgen @glmodule.c + mv @glmodule.c glmodule.c + +# The dependencies for graminit.[ch] are not turned on in the +# distributed Makefile because the files themselves are distributed. +# Turn them on if you want to hack the grammar. + +#graminit.c graminit.h: Grammar python_gen +# python_gen Grammar diff --git a/src/PROTO.h b/src/PROTO.h new file mode 100644 index 0000000..88b94fe --- /dev/null +++ b/src/PROTO.h @@ -0,0 +1,79 @@ +/*********************************************************** +Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +Netherlands. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* +The macro PROTO(x) is used to put function prototypes in the source. +This is defined differently for compilers that support prototypes than +for compilers that don't. It should be used as follows: + int some_function PROTO((int arg1, char *arg2)); +A variant FPROTO(x) is used for cases where Standard C allows prototypes +but Think C doesn't (mostly function pointers). + +This file also defines the macro HAVE_PROTOTYPES if and only if +the PROTO() macro expands the prototype. It is also allowed to predefine +HAVE_PROTOTYPES to force prototypes on. +*/ + +#ifndef PROTO + +#ifdef __STDC__ +#define HAVE_PROTOTYPES +#endif + +#ifdef THINK_C +#undef HAVE_PROTOTYPES +#define HAVE_PROTOTYPES +#endif + +#ifdef sgi +#ifdef mips +#define HAVE_PROTOTYPES +#endif +#endif + +#ifdef HAVE_PROTOTYPES +#define PROTO(x) x +#else +#define PROTO(x) () +#endif + +#endif /* PROTO */ + + +/* FPROTO() is for cases where Think C doesn't like prototypes */ + +#ifdef THINK_C +#define FPROTO(arglist) () +#else /* !THINK_C */ +#define FPROTO(arglist) PROTO(arglist) +#endif /* !THINK_C */ + +#ifndef HAVE_PROTOTYPES +#define const /*empty*/ +#else /* HAVE_PROTOTYPES */ +#ifdef THINK_C +#undef const +#define const /*empty*/ +#endif /* THINK_C */ +#endif /* HAVE_PROTOTYPES */ diff --git a/src/README b/src/README new file mode 100644 index 0000000..714cd5b --- /dev/null +++ b/src/README @@ -0,0 +1,11 @@ +This directory contains the source for the Python interpreter. + +To build the interpreter, edit the Makefile, follow the instructions +there, and type "make python". + +To use the interpreter, you must set the environment variable PYTHONPATH +to point to the directory containing the standard modules. These are +distributed as a sister directory called 'lib' of this source directory. +Try importing the module 'testall' to see if everything works. + +Good Luck! diff --git a/src/To.do b/src/To.do new file mode 100644 index 0000000..893e96d --- /dev/null +++ b/src/To.do @@ -0,0 +1,11 @@ +- return better errors for file objects (also check read/write allowed, etc.) + +- introduce more specific exceptions (e.g., zero divide, index failure, ...) + +- why do reads from stdin fail when I suspend the process? + +- introduce macros to set/inspect errno for syscalls, to support things + like getoserr() + +- fix interrupt handling (interruptable system calls should call + intrcheck() to clear the interrupt status) diff --git a/src/acceler.c b/src/acceler.c new file mode 100644 index 0000000..5ed37d3 --- /dev/null +++ b/src/acceler.c @@ -0,0 +1,136 @@ +/*********************************************************** +Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +Netherlands. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* Parser accelerator module */ + +/* The parser as originally conceived had disappointing performance. + This module does some precomputation that speeds up the selection + of a DFA based upon a token, turning a search through an array + into a simple indexing operation. The parser now cannot work + without the accelerators installed. Note that the accelerators + are installed dynamically when the parser is initialized, they + are not part of the static data structure written on graminit.[ch] + by the parser generator. */ + +#include "pgenheaders.h" +#include "grammar.h" +#include "token.h" +#include "parser.h" + +/* Forward references */ +static void fixdfa PROTO((grammar *, dfa *)); +static void fixstate PROTO((grammar *, dfa *, state *)); + +void +addaccelerators(g) + grammar *g; +{ + dfa *d; + int i; +#ifdef DEBUG + printf("Adding parser accellerators ...\n"); +#endif + d = g->g_dfa; + for (i = g->g_ndfas; --i >= 0; d++) + fixdfa(g, d); + g->g_accel = 1; +#ifdef DEBUG + printf("Done.\n"); +#endif +} + +static void +fixdfa(g, d) + grammar *g; + dfa *d; +{ + state *s; + int j; + s = d->d_state; + for (j = 0; j < d->d_nstates; j++, s++) + fixstate(g, d, s); +} + +static void +fixstate(g, d, s) + grammar *g; + dfa *d; + state *s; +{ + arc *a; + int k; + int *accel; + int nl = g->g_ll.ll_nlabels; + s->s_accept = 0; + accel = NEW(int, nl); + for (k = 0; k < nl; k++) + accel[k] = -1; + a = s->s_arc; + for (k = s->s_narcs; --k >= 0; a++) { + int lbl = a->a_lbl; + label *l = &g->g_ll.ll_label[lbl]; + int type = l->lb_type; + if (a->a_arrow >= (1 << 7)) { + printf("XXX too many states!\n"); + continue; + } + if (ISNONTERMINAL(type)) { + dfa *d1 = finddfa(g, type); + int ibit; + if (type - NT_OFFSET >= (1 << 7)) { + printf("XXX too high nonterminal number!\n"); + continue; + } + for (ibit = 0; ibit < g->g_ll.ll_nlabels; ibit++) { + if (testbit(d1->d_first, ibit)) { + if (accel[ibit] != -1) + printf("XXX ambiguity!\n"); + accel[ibit] = a->a_arrow | (1 << 7) | + ((type - NT_OFFSET) << 8); + } + } + } + else if (lbl == EMPTY) + s->s_accept = 1; + else if (lbl >= 0 && lbl < nl) + accel[lbl] = a->a_arrow; + } + while (nl > 0 && accel[nl-1] == -1) + nl--; + for (k = 0; k < nl && accel[k] == -1;) + k++; + if (k < nl) { + int i; + s->s_accel = NEW(int, nl-k); + if (s->s_accel == NULL) { + fprintf(stderr, "no mem to add parser accelerators\n"); + exit(1); + } + s->s_lower = k; + s->s_upper = nl; + for (i = 0; k < nl; i++, k++) + s->s_accel[i] = accel[k]; + } + DEL(accel); +} diff --git a/src/allobjects.h b/src/allobjects.h new file mode 100644 index 0000000..b6b487b --- /dev/null +++ b/src/allobjects.h @@ -0,0 +1,50 @@ +/*********************************************************** +Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +Netherlands. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* "allobjects.c" -- Source for precompiled header "allobjects.h" */ + +#include +#include + +#include "PROTO.h" + +#include "object.h" +#include "objimpl.h" + +#include "intobject.h" +#include "floatobject.h" +#include "stringobject.h" +#include "tupleobject.h" +#include "listobject.h" +#include "dictobject.h" +#include "methodobject.h" +#include "moduleobject.h" +#include "funcobject.h" +#include "classobject.h" +#include "fileobject.h" + +#include "errors.h" +#include "malloc.h" + +extern char *strdup PROTO((const char *)); diff --git a/src/amoebamodule.c b/src/amoebamodule.c new file mode 100644 index 0000000..c9131b7 --- /dev/null +++ b/src/amoebamodule.c @@ -0,0 +1,774 @@ +/*********************************************************** +Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +Netherlands. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* Amoeba module implementation */ + +/* Amoeba includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* C includes */ +#include +#include + +/* POSIX includes */ +#include +#include +#include + +/* Python includes */ +#include "allobjects.h" +#include "modsupport.h" +#include "sc_global.h" +#include "stubcode.h" + +extern char *err_why(); +extern char *ar_cap(); + +#define STUBCODE "+stubcode" + +static object *AmoebaError; +object *StubcodeError; + +static object *sc_dict; + +/* Module initialization */ + +extern struct methodlist amoeba_methods[]; /* Forward */ +extern object *convertcapv(); /* Forward */ + +static void +ins(d, name, v) + object *d; + char *name; + object *v; +{ + if (v == NULL || dictinsert(d, name, v) != 0) + fatal("can't initialize amoeba module"); +} + +void +initamoeba() +{ + object *m, *d, *v; + + m = initmodule("amoeba", amoeba_methods); + d = getmoduledict(m); + + /* Define capv */ + v = convertcapv(); + ins(d, "capv", v); + DECREF(v); + + /* Set timeout */ + timeout((interval)2000); + + /* Initialize amoeba.error exception */ + AmoebaError = newstringobject("amoeba.error"); + ins(d, "error", AmoebaError); + StubcodeError = newstringobject("amoeba.stubcode_error"); + ins(d, "stubcode_error", StubcodeError); + sc_dict = newdictobject(); +} + + +/* Set an Amoeba-specific error, and return NULL */ + +object * +amoeba_error(err) + errstat err; +{ + object *v = newtupleobject(2); + if (v != NULL) { + settupleitem(v, 0, newintobject((long)err)); + settupleitem(v, 1, newstringobject(err_why(err))); + } + err_setval(AmoebaError, v); + if (v != NULL) + DECREF(v); + return NULL; +} + + +/* Capability object implementation */ + +extern typeobject Captype; /* Forward */ + +#define is_capobject(v) ((v)->ob_type == &Captype) + +typedef struct { + OB_HEAD + capability ob_cap; +} capobject; + +object * +newcapobject(cap) + capability *cap; +{ + capobject *v = NEWOBJ(capobject, &Captype); + if (v == NULL) + return NULL; + v->ob_cap = *cap; + return (object *)v; +} + +getcapability(v, cap) + object *v; + capability *cap; +{ + + if (!is_capobject(v)) + return err_badarg(); + *cap = ((capobject *)v)->ob_cap; + return 0; +} + +/* + * is_capobj exports the is_capobject macro to the stubcode modules + */ + +int +is_capobj(v) + object *v; +{ + + return is_capobject(v); +} + +/* Methods */ + +static void +capprint(v, fp, flags) + capobject *v; + FILE *fp; + int flags; +{ + /* XXX needs lock when multi-threading */ + fputs(ar_cap(&v->ob_cap), fp); +} + +static object * +caprepr(v) + capobject *v; +{ + /* XXX needs lock when multi-threading */ + return newstringobject(ar_cap(&v->ob_cap)); +} + +extern object *sc_interpreter(); + +extern struct methodlist cap_methods[]; /* Forward */ + +object * +sc_makeself(cap, stubcode, name) + object *cap, *stubcode; + char *name; +{ + object *sc_name, *sc_self; + + sc_name = newstringobject(name); + if (sc_name == NULL) + return NULL; + sc_self = newtupleobject(3); + if (sc_self == NULL) { + DECREF(sc_name); + return NULL; + } + if (settupleitem(sc_self, NAME, sc_name) != 0) { + DECREF(sc_self); + return NULL; + } + INCREF(cap); + if (settupleitem(sc_self, CAP, cap) != 0) { + DECREF(sc_self); + return NULL; + } + INCREF(stubcode); + if (settupleitem(sc_self, STUBC, stubcode) != 0) { + DECREF(sc_self); + return NULL; + } + return sc_self; +} + + +static void +swapcode(code, len) + char *code; + int len; +{ + int i = sizeof(TscOperand); + TscOpcode opcode; + TscOperand operand; + + while (i < len) { + memcpy(&opcode, &code[i], sizeof(TscOpcode)); + SwapOpcode(opcode); + memcpy(&code[i], &opcode, sizeof(TscOpcode)); + i += sizeof(TscOpcode); + if (opcode & OPERAND) { + memcpy(&operand, &code[i], sizeof(TscOperand)); + SwapOperand(operand); + memcpy(&code[i], &operand, sizeof(TscOperand)); + i += sizeof(TscOperand); + } + } +} + +object * +sc_findstubcode(v, name) + object *v; + char *name; +{ + int fd, fsize; + char *fname, *buffer; + struct stat statbuf; + object *sc_stubcode, *ret; + TscOperand sc_magic; + + /* + * Only look in the current directory for now. + */ + fname = malloc(strlen(name) + 4); + if (fname == NULL) { + return err_nomem(); + } + sprintf(fname, "%s.sc", name); + if ((fd = open(fname, O_RDONLY)) == -1) { + extern int errno; + + if (errno == 2) { + /* + ** errno == 2 is file not found. + */ + err_setstr(NameError, fname); + return NULL; + } + free(fname); + return err_errno(newstringobject(name)); + } + fstat(fd, &statbuf); + fsize = (int)statbuf.st_size; + buffer = malloc(fsize); + if (buffer == NULL) { + free(fname); + close(fd); + return err_nomem(); + } + if (read(fd, buffer, fsize) != fsize) { + close(fd); + free(fname); + return err_errno(newstringobject(name)); + } + close(fd); + free(fname); + memcpy(&sc_magic, buffer, sizeof(TscOperand)); + if (sc_magic != SC_MAGIC) { + SwapOperand(sc_magic); + if (sc_magic != SC_MAGIC) { + free(buffer); + return NULL; + } else { + swapcode(buffer, fsize); + } + } + sc_stubcode = newsizedstringobject( &buffer[sizeof(TscOperand)], + fsize - sizeof(TscOperand)); + free(buffer); + if (sc_stubcode == NULL) { + return NULL; + } + if (dictinsert(sc_dict, name, sc_stubcode) != 0) { + DECREF(sc_stubcode); + return NULL; + } + DECREF(sc_stubcode); /* XXXX */ + sc_stubcode = sc_makeself(v, sc_stubcode, name); + if (sc_stubcode == NULL) { + return NULL; + } + return sc_stubcode; +} + +object * +capgetattr(v, name) + capobject *v; + char *name; +{ + object *sc_method, *sc_stubcodemethod; + + if (sc_dict == NULL) { + /* + ** For some reason the dictionary has not been + ** initialized. Try to find one of the built in + ** methods. + */ + return findmethod(cap_methods, (object *)v, name); + } + sc_stubcodemethod = dictlookup(sc_dict, name); + if (sc_stubcodemethod != NULL) { + /* + ** There is a stubcode method in the dictionary. + ** Execute the stubcode interpreter with the right + ** arguments. + */ + object *self, *ret; + + self = sc_makeself((object *)v, sc_stubcodemethod, name); + if (self == NULL) { + return NULL; + } + ret = findmethod(cap_methods, self, STUBCODE); + DECREF(self); + return ret; + } + err_clear(); + sc_method = findmethod(cap_methods, (object *)v, name); + if (sc_method == NULL) { + /* + ** The method is not built in and not in the + ** dictionary. Try to find it as a stubcode file. + */ + object *self, *ret; + + err_clear(); + self = sc_findstubcode((object *)v, name); + if (self == NULL) { + return NULL; + } + ret = findmethod(cap_methods, self, STUBCODE); + DECREF(self); + return ret; + } + return sc_method; +} + +int +capcompare(v, w) + capobject *v, *w; +{ + int cmp = bcmp((char *)&v->ob_cap.cap_port, + (char *)&w->ob_cap, PORTSIZE); + if (cmp != 0) + return cmp; + return prv_number(&v->ob_cap.cap_priv) - + prv_number(&w->ob_cap.cap_priv); +} + +static typeobject Captype = { + OB_HEAD_INIT(&Typetype) + 0, + "capability", + sizeof(capobject), + 0, + free, /*tp_dealloc*/ + capprint, /*tp_print*/ + capgetattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + capcompare, /*tp_comp +are*/ + caprepr, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ +}; + + +/* Return a dictionary corresponding to capv */ + +extern struct caplist *capv; + +static object * +convertcapv() +{ + object *d; + struct caplist *c; + d = newdictobject(); + if (d == NULL) + return NULL; + if (capv == NULL) + return d; + for (c = capv; c->cl_name != NULL; c++) { + object *v = newcapobject(c->cl_cap); + if (v == NULL || dictinsert(d, c->cl_name, v) != 0) { + DECREF(d); + return NULL; + } + DECREF(v); + } + return d; +} + + +/* Strongly Amoeba-specific argument handlers */ + +static int +getcaparg(v, a) + object *v; + capability *a; +{ + if (v == NULL || !is_capobject(v)) + return err_badarg(); + *a = ((capobject *)v) -> ob_cap; + return 1; +} + +static int +getstrcapargs(v, a, b) + object *v; + object **a; + capability *b; +{ + if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2) + return err_badarg(); + return getstrarg(gettupleitem(v, 0), a) && + getcaparg(gettupleitem(v, 1), b); +} + + +/* Amoeba methods */ + +static object * +amoeba_name_lookup(self, args) + object *self; + object *args; +{ + object *name; + capability cap; + errstat err; + if (!getstrarg(args, &name)) + return NULL; + err = name_lookup(getstringvalue(name), &cap); + if (err != STD_OK) + return amoeba_error(err); + return newcapobject(&cap); +} + +static object * +amoeba_name_append(self, args) + object *self; + object *args; +{ + object *name; + capability cap; + errstat err; + if (!getstrcapargs(args, &name, &cap)) + return NULL; + err = name_append(getstringvalue(name), &cap); + if (err != STD_OK) + return amoeba_error(err); + INCREF(None); + return None; +} + +static object * +amoeba_name_replace(self, args) + object *self; + object *args; +{ + object *name; + capability cap; + errstat err; + if (!getstrcapargs(args, &name, &cap)) + return NULL; + err = name_replace(getstringvalue(name), &cap); + if (err != STD_OK) + return amoeba_error(err); + INCREF(None); + return None; +} + +static object * +amoeba_name_delete(self, args) + object *self; + object *args; +{ + object *name; + errstat err; + if (!getstrarg(args, &name)) + return NULL; + err = name_delete(getstringvalue(name)); + if (err != STD_OK) + return amoeba_error(err); + INCREF(None); + return None; +} + +static object * +amoeba_timeout(self, args) + object *self; + object *args; +{ + int i; + object *v; + interval tout; + if (!getintarg(args, &i)) + return NULL; + tout = timeout((interval)i); + v = newintobject((long)tout); + if (v == NULL) + timeout(tout); + return v; +} + +static struct methodlist amoeba_methods[] = { + {"name_append", amoeba_name_append}, + {"name_delete", amoeba_name_delete}, + {"name_lookup", amoeba_name_lookup}, + {"name_replace", amoeba_name_replace}, + {"timeout", amoeba_timeout}, + {NULL, NULL} /* Sentinel */ +}; + +/* Capability methods */ + +static object * +cap_b_size(self, args) + capobject *self; + object *args; +{ + errstat err; + b_fsize size; + if (!getnoarg(args)) + return NULL; + err = b_size(&self->ob_cap, &size); + if (err != STD_OK) + return amoeba_error(err); + return newintobject((long)size); +} + +static object * +cap_b_read(self, args) + capobject *self; + object *args; +{ + errstat err; + char *buf; + object *v; + long offset, size; + b_fsize nread; + if (!getlonglongargs(args, &offset, &size)) + return NULL; + buf = malloc((unsigned int)size); + if (buf == NULL) { + return err_nomem(); + } + err = b_read(&self->ob_cap, (b_fsize)offset, buf, (b_fsize)size, + &nread); + if (err != STD_OK) { + free(buf); + return amoeba_error(err); + } + v = newsizedstringobject(buf, (int)nread); + free(buf); + return v; +} + +static object * +cap_dir_lookup(self, args) + capobject *self; + object *args; +{ + object *name; + capability cap; + errstat err; + if (!getstrarg(args, &name)) + return NULL; + err = dir_lookup(&self->ob_cap, getstringvalue(name), &cap); + if (err != STD_OK) + return amoeba_error(err); + return newcapobject(&cap); +} + +static object * +cap_dir_append(self, args) + capobject *self; + object *args; +{ + object *name; + capability cap; + errstat err; + if (!getstrcapargs(args, &name, &cap)) + return NULL; + err = dir_append(&self->ob_cap, getstringvalue(name), &cap); + if (err != STD_OK) + return amoeba_error(err); + INCREF(None); + return None; +} + +static object * +cap_dir_delete(self, args) + capobject *self; + object *args; +{ + object *name; + errstat err; + if (!getstrarg(args, &name)) + return NULL; + err = dir_delete(&self->ob_cap, getstringvalue(name)); + if (err != STD_OK) + return amoeba_error(err); + INCREF(None); + return None; +} + +static object * +cap_dir_replace(self, args) + capobject *self; + object *args; +{ + object *name; + capability cap; + errstat err; + if (!getstrcapargs(args, &name, &cap)) + return NULL; + err = dir_replace(&self->ob_cap, getstringvalue(name), &cap); + if (err != STD_OK) + return amoeba_error(err); + INCREF(None); + return None; +} + +static object * +cap_dir_list(self, args) + capobject *self; + object *args; +{ + errstat err; + struct dir_open *dd; + object *d; + char *name; + if (!getnoarg(args)) + return NULL; + if ((dd = dir_open(&self->ob_cap)) == NULL) + return amoeba_error(STD_COMBAD); + if ((d = newlistobject(0)) == NULL) { + dir_close(dd); + return NULL; + } + while ((name = dir_next(dd)) != NULL) { + object *v; + v = newstringobject(name); + if (v == NULL) { + DECREF(d); + d = NULL; + break; + } + if (addlistitem(d, v) != 0) { + DECREF(v); + DECREF(d); + d = NULL; + break; + } + DECREF(v); + } + dir_close(dd); + return d; +} + +object * +cap_std_info(self, args) + capobject *self; + object *args; +{ + char buf[256]; + errstat err; + int n; + if (!getnoarg(args)) + return NULL; + err = std_info(&self->ob_cap, buf, sizeof buf, &n); + if (err != STD_OK) + return amoeba_error(err); + return newsizedstringobject(buf, n); +} + +object * +cap_tod_gettime(self, args) + capobject *self; + object *args; +{ + header h; + errstat err; + bufsize n; + long sec; + int msec, tz, dst; + if (!getnoarg(args)) + return NULL; + h.h_port = self->ob_cap.cap_port; + h.h_priv = self->ob_cap.cap_priv; + h.h_command = TOD_GETTIME; + n = trans(&h, NILBUF, 0, &h, NILBUF, 0); + if (ERR_STATUS(n)) + return amoeba_error(ERR_CONVERT(n)); + tod_decode(&h, &sec, &msec, &tz, &dst); + return newintobject(sec); +} + +object * +cap_tod_settime(self, args) + capobject *self; + object *args; +{ + header h; + errstat err; + bufsize n; + long sec; + if (!getlongarg(args, &sec)) + return NULL; + h.h_port = self->ob_cap.cap_port; + h.h_priv = self->ob_cap.cap_priv; + h.h_command = TOD_SETTIME; + tod_encode(&h, sec, 0, 0, 0); + n = trans(&h, NILBUF, 0, &h, NILBUF, 0); + if (ERR_STATUS(n)) + return amoeba_error(ERR_CONVERT(n)); + INCREF(None); + return None; +} + +static struct methodlist cap_methods[] = { + { STUBCODE, sc_interpreter}, + {"b_read", cap_b_read}, + {"b_size", cap_b_size}, + {"dir_append", cap_dir_append}, + {"dir_delete", cap_dir_delete}, + {"dir_list", cap_dir_list}, + {"dir_lookup", cap_dir_lookup}, + {"dir_replace", cap_dir_replace}, + {"std_info", cap_std_info}, + {"tod_gettime", cap_tod_gettime}, + {"tod_settime", cap_tod_settime}, + {NULL, NULL} /* Sentinel */ +}; diff --git a/src/asa.c b/src/asa.c new file mode 100644 index 0000000..f7f7378 --- /dev/null +++ b/src/asa.c @@ -0,0 +1,494 @@ +/*********************************************************** +Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +Netherlands. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* Asynchronous audio module for Silicon Graphics 4D/20 under IRIX 3.3 + Copyright 1990 Stichting Mathematisch Centrum, Amsterdam + Author: Guido van Rossum, + Last modified: gu...@cwi.nl, Oct 14, 1990 + + Callers should #include "asa.h". + + This code is strongly IRIX 3.3 dependent. (Or are sproc() and + friends standard SYSV now?) + + Caution: if you put printf's in the slave for debugging, use "-lmpc" + to get the semaphore version of stdio! + + + This file contains two library layers and a test program: + + + The lower layer implements a simple asynchronous execution facility, + built directly on the system calls sproc() and [un]blockproc(). + + A slave thread sits in an infinite loop waiting for work assigned to + it by the master thread. Work is represented by a function pointer + and an argument of type void*. The function returns a void* pointer + which is transferred back to the master when it submits the next bit + of work. Submitting a NULL function pointer can be used by the + master to wait for completion of the previous work. This lower + layer could be generally useful, but is currently implemented by + static functions, for exclusive by the asynchronous audio layer. + + + The higher layer implements an asynchronous interface to the + /dev/audio device on the Silicon Graphics 4D/20. It defines the + following functions: + + int asa_init() + Required initialization function. The other functions will call + abort() when they are called before asa_init(). It creates the + slave process and returns a file descriptor for the audio + device which can be used to set the sampling rate and output + gain, etc. It prints a message to stderr and returns -1 if the + initialization failed. Calling this function more than onece is + harmless. + + void asa_start_read(char *buf, int len) + Starts an asynchronous read call on the audio device. This + waits for completion of the previous request, if any. + + void asa_start_write(char *buf, int len) + Starts an asynchronous write call on the audio device. This + waits for completion of the previous request, if any. + + int asa_poll() + Polls whether the last asynchronous read or write request is + finished. Returns -1 if no request was queued, 0 if the request + is not yet finished, and 1 if it is finished. + + int asa_wait() + Waits for completion if the last asynchronous read or write + request. It returns the result of the read or write request, + and sets the error code to the error code set by the request if + the result is -1. If no request was queued, this also returns + -1 but leaves the error code unchanged. Note: to get the error + code, don't inspect the global variable errno but call the + function oserror(). + + int asa_cancel() + Cancels the last asynchronous read or write request (by sending + the slave thread a signal for which it has a handler) then + returns its result and error code as asa_wait(). + + void asa_done() + Kills the slave process and closes the audio device. After + this, if further use of the module is required, asa_init() + should be called again. Calling this function when asa_init() + has not been called is harmless. + + + Finally, this file contains a simple test program that is compiled if + MAIN is defined (e.g., compile with cc -DMAIN). It makes a recording + and plays it back. The user must indicate begin and end of recording + and play-back by pressing the Return key. +*/ + + +#include +#include +#include +#include +#include + +#include "asa.h" + + +/* Asynchronous execution facility (lower layer) */ + + +/* Signal used to cancel requests in progress */ +#define MYSIG SIGUSR1 + +/* Respective process IDs */ +static pid_t master_pid = -1; +static pid_t slave_pid = -1; + +/* Work and result "queue" (1 element) */ +static void * (*work_func)(); +static void *work_arg; +static void *work_result; + +/* Signal handler for MYSIG -- interrupts read or write system call */ + +/*ARGSUSED*/ +static void +handler(sig) + int sig; +{ + /* Reinstate the handler (non-BSD signal semantics) */ + signal(sig, handler); +} + +/* Subroutine to fiddle signals */ + +static void +dosig(sig) + int sig; +{ + if (signal(sig, SIG_IGN) != SIG_IGN) + signal(sig, SIG_DFL); +} + +/* Slave control flow */ + +/*ARGSUSED*/ +static void +slave(arg) + void *arg; +{ + void * (*func)(); + void *arg; + void *result; + + /* Reset signal handlers that interactive programs often catch. + The assumption is that if the master has a handler for these + signals, it will be a cleanup function. The slave must die + from these. */ + dosig(SIGHUP); + dosig(SIGQUIT); + dosig(SIGTERM); + dosig(SIGPIPE); + + /* Ignore SIGINT if caught or ignored */ + if (signal(SIGINT, SIG_IGN) == SIG_DFL) + signal(SIGINT, SIG_DFL); + + /* Let the handler install itself */ + handler(MYSIG); + + /* Set slave_pid. This is also done in the master thread, but + there is a race condition whereby the slave begins execution + before the master has assigned the result of sproc() to + slave_pid. So we set it here as well -- since this sets the + same value it should be OK. */ + slave_pid = getpid(); + + /* Set the dummy result returned by the first rendezvous */ + result = NULL; + + /* Loop forever, waiting for and executing work */ + for (;;) { + /* First rendezvous: store previous result */ + if (blockproc(slave_pid) < 0) + perror("slave: [result] blockproc(slave_pid)"); + work_result = result; + if (unblockproc(master_pid) < 0) + perror("slave: [result] unblockproc(master_pid)"); + + /* Second rendezvous: fetch work */ + if (blockproc(slave_pid) < 0) + perror("slave: [func,arg] blockproc(slave_pid)"); + func = work_func; + arg = work_arg; + if (unblockproc(master_pid) < 0) + perror("slave: [func,arg] unblockproc(master_pid)"); + + /* Execute work, computing new result */ + if (func == NULL) { + result = arg; + } + else { + result = (*func)(arg); + } + } +} + +static int +slave_init() +{ + if (slave_pid > 0) + return slave_pid; + master_pid = getpid(); + + /* Reset the queue, in case this is a re-init after asa_done() */ + work_result = NULL; + work_func = NULL; + work_arg = NULL; + + /* Create the slave process, sharing all segments and properties */ + slave_pid = sproc(slave, PR_SALL, (char *)NULL); + if (slave_pid < 0) + perror("slave_init: sproc(slave, PR_SALL, NULL)"); + + /* Set up initial conditions---tricky! + Both the master and the slave start with one credit, since + both the result slot and the work/func slots are initially + free. + Note that we use setblockproccnt() for the master so a + possible indeterminate semaphore value caused by a previous + asa_done() at an unfortunate moment doesn't harm us. + */ + setblockproccnt(master_pid, 1); + unblockproc(slave_pid); + + return slave_pid; +} + +static void +slave_done() +{ + if (slave_pid > 0) { + if (kill(slave_pid, SIGKILL) < 0) + perror("slave_done: kill(slave_pid, SIGKILL)"); + } + slave_pid = -1; +} + +/* Queue new work and return result of previous work */ + +static void * +rendezvous(func, arg) + void * (*func)(); + void *arg; +{ + void *result; + + if (slave_pid <= 0) + abort(); /* Illegal call: not initialized properly */ + + /* First rendezvous: store new work */ + if (blockproc(master_pid) < 0) + perror("rendezvous: [func,arg] blockproc(master_pid)"); + work_func = func; + work_arg = arg; + if (unblockproc(slave_pid) < 0) + perror("rendezvous: [func,arg] unblockproc(slave_pid)"); + + /* Second rendezvous: fetch previous result */ + if (blockproc(master_pid) < 0) + perror("rendezvous: [result] blockproc(master_pid)"); + result = work_result; + if (unblockproc(slave_pid) < 0) + perror("rendezvous: [result] unblockproc(slave_pid)"); + + return result; +} + + +/* Asynchronous audio interface (higher layer) */ + + +int audio_fd = -1; /* File descriptor -- not initialized yet */ + +static struct queue { + int func; /* 0 = read, 1 = write */ + char *buf; + int len; + int result; + int error; +} queue[2]; + +static int qindex = 0; + +int +asa_init() +{ + int fd; + char *p; + + if (audio_fd >= 0) + return audio_fd; + fd = open("/dev/audio", 2); + if (fd < 0) { + perror("asa_init: Can't open /dev/audio"); + return -1; + } + if (slave_init() < 0) { + perror("asa_init: Can't create slave process"); + close(fd); + return -1; + } + audio_fd = fd; + return fd; +} + +void +asa_done() +{ + slave_done(); + if (audio_fd >= 0) { + if (close(audio_fd) < 0) + perror("asa_done: close(audio_fd)"); + } + audio_fd = -1; +} + +static void * +runjob(arg) + void *arg; +{ + extern int errno; + struct queue *q = (struct queue *)arg; + char *buf = q->buf; + int len = q->len; + int n = 0; + + if (q->func == 0) + n = read(audio_fd, buf, len); + else + n = write(audio_fd, buf, len); + if (q->func == 0 && n >= 0) { + while (--len >= n && buf[len] == '\0') + ; + n = len+1; + } + q->result = n; + q->error = oserror(); + return arg; +} + +static void +startjob(func, buf, len) + int func; + char *buf; + int len; +{ + struct queue *q; + + q = &queue[qindex]; + qindex = (qindex+1) & 1; + q->func = func; + q->buf = buf; + q->len = len; + (void) rendezvous(runjob, (void *)q); +} + +void +asa_start_read(buf, len) + char *buf; + int len; +{ + memset(buf, '\0', len); + startjob(0, buf, len); +} + +void +asa_start_write(buf, len) + char *buf; + int len; +{ + startjob(1, buf, len); +} + +int +asa_wait() +{ + struct queue *q; + + q = (struct queue *) rendezvous((void*(*)())NULL, (void *)NULL); + if (q == NULL) { + setoserror(0); + return -1; /* No work was queued */ + } + setoserror(q->error); + return q->result; +} + +int +asa_poll() +{ + int err; + + err = prctl(PR_ISBLOCKED, slave_pid); + if (err < 0) { + perror("prctl(PR_ISBLOCKED, slave_pid)"); + return -1; + } + else if (err == 0) + return 0; + else if (work_result == NULL) { + setoserror(0); + return -1; + } + else + return 1; +} + +int +asa_cancel() +{ + int result; + + kill(slave_pid, MYSIG); + result = asa_wait(); + return result; +} + + +#ifdef MAIN + +/* Test program */ + +#include + +main() +{ + static char buf[10*16*1024]; /* 10 seconds of sound at 16K/sec */ + int n; + int afd; + + if ((afd = asa_init()) < 0) + exit(1); + ioctl(afd, AUDIOCSETRATE, 3); + ioctl(afd, AUDIOCSETOUTGAIN, 0); + printf("Poll returns %d\n", asa_poll()); + go("Hit enter to start recording:\n"); + asa_start_read(buf, sizeof buf); + go("Hit enter to stop recording:\n"); + /*printf("Poll returns %d\n", asa_poll());*/ + n = asa_cancel(); + if (n < 0) + perror("Read failed"); + else { + printf("Got %d bytes\n", n); + printf("Poll returns %d\n", asa_poll()); + go("Hit enter to start playing:\n"); + ioctl(afd, AUDIOCSETOUTGAIN, 50); + asa_start_write(buf, n); + go("Hit enter to stop playing:\n"); + printf("Poll returns %d\n", asa_poll()); + n = asa_cancel(); + if (n < 0) + perror("Write failed"); + else + printf("Stopped at %d bytes\n", n); + } + ioctl(afd, AUDIOCSETOUTGAIN, 0); + asa_done(); + exit(n < 0 ? 1 : 0); +} + +go(str) + char *str; +{ + char line[100]; + + sleep(1); + fputs(str, stdout); + fflush(stdout); + fgets(line, sizeof line, stdin); +} + +#endif /* MAIN */ diff --git a/src/asa.h b/src/asa.h new file mode 100644 index 0000000..d9a7d10 --- /dev/null +++ b/src/asa.h @@ -0,0 +1,33 @@ +/*********************************************************** +Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +Netherlands. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* Interface for asynchronous audio module */ + +extern int asa_init(void); +extern void asa_done(void); +extern void asa_start_write(char *, int); +extern void asa_start_read(char *, int); +extern int asa_poll(void); +extern int asa_wait(void); +extern int asa_cancel(void); diff --git a/src/assert.h b/src/assert.h new file mode 100644 index 0000000..f21225e --- /dev/null +++ b/src/assert.h @@ -0,0 +1,25 @@ +/*********************************************************** +Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +Netherlands. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +#define assert(e) { if (!(e)) { printf("Assertion failed\n"); abort(); } } diff --git a/src/audiomodule.c b/src/audiomodule.c new file mode 100644 index 0000000..cca0102 --- /dev/null +++ b/src/audiomodule.c @@ -0,0 +1,615 @@ +/*********************************************************** +Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +Netherlands. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* Silicon Graphics audio module implementation */ +/* For SGI Personal IRIS 4D/20 under IRIX 3.3; mentions "IP6" */ +/* Note: The set-in-gain ioctl exists but is non-functional */ + +#include +#include +#include "asa.h" + +#include "allobjects.h" +#include "modsupport.h" + +static int audio_fd = -1; + +static int +init() +{ + if (audio_fd >= 0) + return 1; + if ((audio_fd = asa_init()) >= 0) + return 1; + err_setstr(RuntimeError, "can't initialize async audio"); + return 0; +} + + +/* POSIX methods */ + +static object * +audio_get_ioctl(self, args, code) + object *self; + object *args; + long code; +{ + long x; + if (!getnoarg(args)) + return NULL; + if (!init()) + return NULL; + if ((x = ioctl(audio_fd, code, (char *) NULL)) < 0) { + return NULL; + } + return newintobject(x); +} + +static object * +audio_set_ioctl(self, args, code) + object *self; + object *args; + long code; +{ + long x; + if (!getlongarg(args, &x)) + return NULL; + if (!init()) + return NULL; + if (ioctl(audio_fd, code, (char *) x) != 0) + return NULL; + INCREF(None); + return None; +} + +static object * +audio_getingain(self, args) + object *self; + object *args; +{ + return audio_get_ioctl(self, args, AUDIOCGETINGAIN); +} + +static object * +audio_getoutgain(self, args) + object *self; + object *args; +{ + return audio_get_ioctl(self, args, AUDIOCGETOUTGAIN); +} + +static object * +audio_setingain(self, args) + object *self; + object *args; +{ + return audio_set_ioctl(self, args, AUDIOCSETINGAIN); +} + +static object * +audio_setoutgain(self, args) + object *self; + object *args; +{ + return audio_set_ioctl(self, args, AUDIOCSETOUTGAIN); +} + +static object * +audio_setrate(self, args) + object *self; + object *args; +{ + return audio_set_ioctl(self, args, AUDIOCSETRATE); +} + +static object * +audio_setduration(self, args) + object *self; + object *args; +{ + return audio_set_ioctl(self, args, AUDIOCDURATION); +} + +/* Compute average bias, and remove it */ + +static void +unbias(buf, len) + char *buf; + int len; +{ + register int i; + register int c; + register long bias; + if (len == 0) + return; + bias = 0; + for (i = 0; i < len; i++) { + c = buf[i]; + if (c > 127) + c -= 256; + bias += c; + } + bias = (bias + len/2) / len; /* Rounded average */ + if (bias != 0) { + for (i = 0; i < len; i++) { + buf[i] -= bias; + } + } +} + +static object * +audio_read(self, args) + object *self; + object *args; +{ + int c, i, n; + object *v; + char *s; + if (!getintarg(args, &n)) + return NULL; + if (n <= 0) { + err_setstr(RuntimeError, "audio.read: arg <= 0"); + return NULL; + } + if (!init()) + return NULL; + v = newsizedstringobject((char *)NULL, n); + if (v == NULL) + return err_nomem(); + s = getstringvalue(v); + n = read(audio_fd, s, n); + if (intrcheck()) { + DECREF(v); + err_set(KeyboardInterrupt); + return NULL; + } + /* Check for errors */ + if (n < 0) { + DECREF(v); + return NULL; + } + /* But EOF is reported as an empty string */ + + unbias(s, n); + resizestring(&v, n); + return v; +} + +static object * +audio_write(self, args) + object *self; + object *args; +{ + int n, n2; + object *v; + if (!getstrarg(args, &v)) + return NULL; + if (!init()) + return NULL; + errno = 0; + n2 = write(audio_fd, getstringvalue(v), n = getstringsize(v)); + if (intrcheck()) { + err_set(KeyboardInterrupt); + return NULL; + } + /* Check for other errors */ + if (n2 != n) { + if (errno == 0) + errno = EIO; + return NULL; + } + INCREF(None); + return None; +} + +/* audio.amplify(sample, f1, f2). + Amplify a sample by a factor changing from f1/256 to (almost) f2/256. + Negative factors are allowed. Sound values that are to large + to fit in a byte are clipped. */ + +static object * +audio_amplify(self, args) + object *self; + object *args; +{ + object *v; + char *s, *t; + int f1, f2; + int i, n; + int c; + if (!getstrintintarg(args, &v, &f1, &f2)) + return NULL; + n = getstringsize(v); + s = getstringvalue(v); + v = newsizedstringobject((char *)NULL, n); + if (v == NULL) + return err_nomem(); + t = getstringvalue(v); + for (i = 0; i < n; i++) { + c = s[i]; + if (c > 127) c -= 256; /* If chars are unsigned */ + c = c * ( f1*(n-i) + f2*i ) / ( n*256 ); + if (c > 127) c = 127; + else if (c < -128) c = -128; + t[i] = c; + } + return v; +} + +/* audio.reverse(s): return a sample backwards */ + +static object * +audio_reverse(self, args) + object *self; + object *args; +{ + object *v; + char *s, *t; + int i, n; + if (!getstrarg(args, &v)) + return NULL; + n = getstringsize(v); + s = getstringvalue(v); + v = newsizedstringobject((char *)NULL, n); + if (v == NULL) + return err_nomem(); + t = getstringvalue(v); + for (i = 0; i < n; i++) { + t[n-1-i] = s[i]; + } + return v; +} + +/* audio.add(a, b): add two samples. + Bytes that exceed the range are clipped. + If one is shorter, the rest of the longer sample is returned unchanged. */ + +static object * +audio_add(self, args) + object *self; + object *args; +{ + object *a, *b, *v; + char *sa, *sb, *t; + int i, n, na, nb, c, ca, cb; + if (!getstrstrarg(args, &a, &b)) + return NULL; + na = getstringsize(a); + sa = getstringvalue(a); + nb = getstringsize(b); + sb = getstringvalue(b); + n = (na > nb) ? na : nb; + v = newsizedstringobject((char *)NULL, n); + if (v == NULL) + return err_nomem(); + t = getstringvalue(v); + for (i = 0; i < n; i++) { + c = 0; + if (i < na) { + ca = sa[i]; + if (ca > 127) ca = ca - 256; + c = c + ca; + } + if (i < nb) { + cb = sb[i]; + if (cb > 127) cb = cb - 256; + c = c + cb; + } + if (c > 127) c = 127; + else if (c < -128) c = -128; + t[i] = c; + } + return v; +} + +/* audio.chr2num(s) returns a list containing the numeric values + of the samples. */ + +static object * +audio_chr2num(self, args) + object *self; + object *args; +{ + object *v, *w; + char *s; + int c, i, n; + static object *ints[256]; + + /* To avoid filling memory with all those int objects, we create + integer objects for all the desired values and reference these. */ + if (ints[255] == NULL) { + for (i = 0; i < 256; i++) { + if (ints[i] != NULL) + continue; + c = i; + if (c > 127) c -= 256; + ints[i] = newintobject((long)c); + if (ints[i] == NULL) + return NULL; + } + } + + if (!getstrarg(args, &v)) + return NULL; + n = getstringsize(v); + s = getstringvalue(v); + v = newlistobject(n); + if (v == NULL) + return err_nomem(); + for (i = 0; i < n; i++) { + c = s[i] & 0xff; + w = ints[c]; + INCREF(w); + if (setlistitem(v, i, w) != 0) { + DECREF(v); + return NULL; + } + } + return v; +} + +/* audio.num2chr is the inverse of audio.chr2num. + Excess values are clipped. */ + +static object * +audio_num2chr(self, args) + object *self; + object *args; +{ + object *v, *w; + char *s; + int c, i, n; + if (!is_listobject(args)) { + err_badarg(); + return NULL; + } + n = getlistsize(args); + v = newsizedstringobject((char *)NULL, n); + if (v == NULL) + return NULL; + s = getstringvalue(v); + for (i = 0; i < n; i++) { + w = getlistitem(args, i); + if (!is_intobject(w)) { + DECREF(v); + err_badarg(); + return NULL; + } + s[i] = getintvalue(w); + } + return v; +} + +static object *stdaudio_buffer = NULL; + +static object * +audio_start_recording(self, args) + object *self; + object *args; +{ + int n; + object *v; + char *s; + if (!getintarg(args, &n)) + return NULL; + if (stdaudio_buffer != NULL) { + err_setstr(RuntimeError, "audio.start_recording: device busy"); + return NULL; + } + if (n <= 0) { + err_setstr(TypeError, "audio.start_recording: arg <= 0"); + return NULL; + } + if (!init()) + return NULL; + v = newsizedstringobject((char *)NULL, n); + if (v == NULL) + return err_nomem(); + s = getstringvalue(v); + asa_start_read(s, n); + stdaudio_buffer = v; + INCREF(None); + return None; +} + +static object * +audio_poll(self, args) + object *self; + object *args; +{ + int n; + if (!getnoarg(args)) + return NULL; + if (stdaudio_buffer == NULL) { + err_setstr(RuntimeError, "audio.poll: not busy"); + return NULL; + } + if (!init()) + return NULL; + if ((n = asa_poll()) < 0) + return NULL; + return newintobject(n); +} + +static object * +audio_wait_recording(self, args) + object *self; + object *args; +{ + object *v; + int n; + if (!getnoarg(args)) + return NULL; + if (stdaudio_buffer == NULL) { + err_setstr(RuntimeError, "audio.wait_recording: not busy"); + return NULL; + } + if (!init()) + return NULL; + if ((n = asa_wait()) < 0) + return NULL; + v = stdaudio_buffer; + stdaudio_buffer = NULL; + unbias(getstringvalue(v), n); + resizestring(&v, n); + return v; +} + +static object * +audio_stop_recording(self, args) + object *self; + object *args; +{ + int n; + object *v; + char *s; + if (!getnoarg(args)) + return NULL; + if (stdaudio_buffer == NULL) { + err_setstr(RuntimeError, "audio.stop_recording: not busy"); + return NULL; + } + if ((n = asa_cancel()) < 0) + return NULL; + v = stdaudio_buffer; + stdaudio_buffer = NULL; + s = getstringvalue(v); + unbias(s, n); + resizestring(&v, n); + return v; +} + +static object * +audio_start_playing(self, args) + object *self; + object *args; +{ + object *v; + if (!getstrarg(args, &v)) + return NULL; + if (stdaudio_buffer != NULL) { + err_setstr(RuntimeError, "audio.start_recording: device rbusy"); + return NULL; + } + asa_start_write(getstringvalue(v), (int)getstringsize(v)); + INCREF(v); + stdaudio_buffer = v; + INCREF(None); + return None; +} + +static object * +audio_wait_playing(self, args) + object *self; + object *args; +{ + int n; + if (!getnoarg(args)) + return NULL; + if (stdaudio_buffer == NULL) { + err_setstr(RuntimeError, "audio.wait_playing: not busy"); + return NULL; + } + if ((n = asa_wait()) < 0) + return NULL; + DECREF(stdaudio_buffer); + stdaudio_buffer = NULL; + /* XXX return newintobject((long)n); ??? */ + INCREF(None); + return None; +} + +static object * +audio_stop_playing(self, args) + object *self; + object *args; +{ + int n; + if (!getnoarg(args)) + return NULL; + if (stdaudio_buffer == NULL) { + err_setstr(RuntimeError, "audio.stop_playing: not busy"); + return NULL; + } + if ((n = asa_cancel()) < 0) + return NULL; + DECREF(stdaudio_buffer); + stdaudio_buffer = NULL; + return newintobject((long)n); +} + +static object * +audio_audio_done(self, args) + object *self; + object *args; +{ + if (!getnoarg(args)) + return NULL; + asa_done(); + if (stdaudio_buffer != NULL) + DECREF(stdaudio_buffer); + stdaudio_buffer = NULL; + audio_fd = -1; + INCREF(None); + return None; +} + + +static struct methodlist audio_methods[] = { + {"getingain", audio_getingain}, + {"getoutgain", audio_getoutgain}, + {"setingain", audio_setingain}, + {"setoutgain", audio_setoutgain}, + {"setrate", audio_setrate}, + {"setduration", audio_setduration}, + {"read", audio_read}, + {"write", audio_write}, + {"amplify", audio_amplify}, + {"reverse", audio_reverse}, + {"add", audio_add}, + {"chr2num", audio_chr2num}, + {"num2chr", audio_num2chr}, + + /* "asa" interface: */ + + {"start_recording", audio_start_recording}, + {"poll_recording", audio_poll}, + {"wait_recording", audio_wait_recording}, + {"stop_recording", audio_stop_recording}, + + {"start_playing", audio_start_playing}, + {"poll_playing", audio_poll}, + {"wait_playing", audio_wait_playing}, + {"stop_playing", audio_stop_playing}, + + {"done", audio_audio_done}, + + {NULL, NULL} /* Sentinel */ +}; + +void +initaudio() +{ + initmodule("audio", audio_methods); +} diff --git a/src/bitset.c b/src/bitset.c new file mode 100644 index 0000000..c08dcc7 --- /dev/null +++ b/src/bitset.c @@ -0,0 +1,99 @@ +/*********************************************************** +Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +Netherlands. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* Bitset primitives used by the parser generator */ + +#include "pgenheaders.h" +#include "bitset.h" + +bitset +newbitset(nbits) + int nbits; +{ + int nbytes = NBYTES(nbits); + bitset ss = NEW(BYTE, nbytes); + + if (ss == NULL) + fatal("no mem for bitset"); + + ss += nbytes; + while (--nbytes >= 0) + *--ss = 0; + return ss; +} + +void +delbitset(ss) + bitset ss; +{ + DEL(ss); +} + +int +addbit(ss, ibit) + bitset ss; + int ibit; +{ + int ibyte = BIT2BYTE(ibit); + BYTE mask = BIT2MASK(ibit); + + if (ss[ibyte] & mask) + return 0; /* Bit already set */ + ss[ibyte] |= mask; + return 1; +} + +#if 0 /* Now a macro */ +int +testbit(ss, ibit) + bitset ss; + int ibit; +{ + return (ss[BIT2BYTE(ibit)] & BIT2MASK(ibit)) != 0; +} +#endif + +int +samebitset(ss1, ss2, nbits) + bitset ss1, ss2; + int nbits; +{ + int i; + + for (i = NBYTES(nbits); --i >= 0; ) + if (*ss1++ != *ss2++) + return 0; + return 1; +} + +void +mergebitset(ss1, ss2, nbits) + bitset ss1, ss2; + int nbits; +{ + int i; + + for (i = NBYTES(nbits); --i >= 0; ) + *ss1++ |= *ss2++; +} diff --git a/src/bitset.h b/src/bitset.h new file mode 100644 index 0000000..5ec6882 --- /dev/null +++ b/src/bitset.h @@ -0,0 +1,46 @@ +/*********************************************************** +Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +Netherlands. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* Bitset interface */ + +#define BYTE char + +typedef BYTE *bitset; + +bitset newbitset PROTO((int nbits)); +void delbitset PROTO((bitset bs)); +/* int testbit PROTO((bitset bs, int ibit)); /* Now a macro, see below */ +int addbit PROTO((bitset bs, int ibit)); /* Returns 0 if already set */ +int samebitset PROTO((bitset bs1, bitset bs2, int nbits)); +void mergebitset PROTO((bitset bs1, bitset bs2, int nbits)); + +#define BITSPERBYTE (8*sizeof(BYTE)) +#define NBYTES(nbits) (((nbits) + BITSPERBYTE - 1) / BITSPERBYTE) + +#define BIT2BYTE(ibit) ((ibit) / BITSPERBYTE) +#define BIT2SHIFT(ibit) ((ibit) % BITSPERBYTE) +#define BIT2MASK(ibit) (1 << BIT2SHIFT(ibit)) +#define BYTE2BIT(ibyte) ((ibyte) * BITSPERBYTE) + +#define testbit(ss, ibit) (((ss)[BIT2BYTE(ibit)] & BIT2MASK(ibit)) != 0) diff --git a/src/bltinmodule.c b/src/bltinmodule.c new file mode 100644 index 0000000..151ba86 --- /dev/null +++ b/src/bltinmodule.c @@ -0,0 +1,559 @@ +/*********************************************************** +Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +Netherlands. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* Built-in functions */ + +#include "allobjects.h" + +#include "node.h" +#include "graminit.h" +#include "errcode.h" +#include "sysmodule.h" +#include "bltinmodule.h" +#include "import.h" +#include "pythonrun.h" +#include "compile.h" /* For ceval.h */ +#include "ceval.h" +#include "modsupport.h" + +static object * +builtin_abs(self, v) + object *self; + object *v; +{ + /* XXX This should be a method in the as_number struct in the type */ + if (v == NULL) { + /* */ + } + else if (is_intobject(v)) { + long x = getintvalue(v); + if (x < 0) + x = -x; + return newintobject(x); + } + else if (is_floatobject(v)) { + double x = getfloatvalue(v); + if (x < 0) + x = -x; + return newfloatobject(x); + } + err_setstr(TypeError, "abs() argument must be float or int"); + return NULL; +} + +static object * +builtin_chr(self, v) + object *self; + object *v; +{ + long x; + char s[1]; + if (v == NULL || !is_intobject(v)) { + err_setstr(TypeError, "chr() must have int argument"); + return NULL; + } + x = getintvalue(v); + if (x < 0 || x >= 256) { + err_setstr(RuntimeError, "chr() arg not in range(256)"); + return NULL; + } + s[0] = x; + return newsizedstringobject(s, 1); +} + +static object * +builtin_dir(self, v) + object *self; + object *v; +{ + object *d; + if (v == NULL) { + d = getlocals(); + } + else { + if (!is_moduleobject(v)) { + err_setstr(TypeError, + "dir() argument, must be module or absent"); + return NULL; + } + d = getmoduledict(v); + } + v = getdictkeys(d); + if (sortlist(v) != 0) { + DECREF(v); + v = NULL; + } + return v; +} + +static object * +builtin_divmod(self, v) + object *self; + object *v; +{ + object *x, *y; + long xi, yi, xdivy, xmody; + if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2) { + err_setstr(TypeError, "divmod() requires 2 int arguments"); + return NULL; + } + x = gettupleitem(v, 0); + y = gettupleitem(v, 1); + if (!is_intobject(x) || !is_intobject(y)) { + err_setstr(TypeError, "divmod() requires 2 int arguments"); + return NULL; + } + xi = getintvalue(x); + yi = getintvalue(y); + if (yi == 0) { + err_setstr(TypeError, "divmod() division by zero"); + return NULL; + } + if (yi < 0) { + xdivy = -xi / -yi; + } + else { + xdivy = xi / yi; + } + xmody = xi - xdivy*yi; + if (xmody < 0 && yi > 0 || xmody > 0 && yi < 0) { + xmody += yi; + xdivy -= 1; + } + v = newtupleobject(2); + x = newintobject(xdivy); + y = newintobject(xmody); + if (v == NULL || x == NULL || y == NULL || + settupleitem(v, 0, x) != 0 || + settupleitem(v, 1, y) != 0) { + XDECREF(v); + XDECREF(x); + XDECREF(y); + return NULL; + } + return v; +} + +static object * +exec_eval(v, start) + object *v; + int start; +{ + object *str = NULL, *globals = NULL, *locals = NULL; + int n; + if (v != NULL) { + if (is_stringobject(v)) + str = v; + else if (is_tupleobject(v) && + ((n = gettuplesize(v)) == 2 || n == 3)) { + str = gettupleitem(v, 0); + globals = gettupleitem(v, 1); + if (n == 3) + locals = gettupleitem(v, 2); + } + } + if (str == NULL || !is_stringobject(str) || + globals != NULL && !is_dictobject(globals) || + locals != NULL && !is_dictobject(locals)) { + err_setstr(TypeError, + "exec/eval arguments must be string[,dict[,dict]]"); + return NULL; + } + return run_string(getstringvalue(str), start, globals, locals); +} + +static object * +builtin_eval(self, v) + object *self; + object *v; +{ + return exec_eval(v, eval_input); +} + +static object * +builtin_exec(self, v) + object *self; + object *v; +{ + return exec_eval(v, file_input); +} + +static object * +builtin_float(self, v) + object *self; + object *v; +{ + if (v == NULL) { + /* */ + } + else if (is_floatobject(v)) { + INCREF(v); + return v; + } + else if (is_intobject(v)) { + long x = getintvalue(v); + return newfloatobject((double)x); + } + err_setstr(TypeError, "float() argument must be float or int"); + return NULL; +} + +static object * +builtin_input(self, v) + object *self; + object *v; +{ + FILE *in = sysgetfile("stdin", stdin); + FILE *out = sysgetfile("stdout", stdout); + node *n; + int err; + object *m, *d; + flushline(); + if (v != NULL) + printobject(v, out, PRINT_RAW); + m = add_module("__main__"); + d = getmoduledict(m); + return run_file(in, "", expr_input, d, d); +} + +static object * +builtin_int(self, v) + object *self; + object *v; +{ + if (v == NULL) { + /* */ + } + else if (is_intobject(v)) { + INCREF(v); + return v; + } + else if (is_floatobject(v)) { + double x = getfloatvalue(v); + return newintobject((long)x); + } + err_setstr(TypeError, "int() argument must be float or int"); + return NULL; +} + +static object * +builtin_len(self, v) + object *self; + object *v; +{ + long len; + typeobject *tp; + if (v == NULL) { + err_setstr(TypeError, "len() without argument"); + return NULL; + } + tp = v->ob_type; + if (tp->tp_as_sequence != NULL) { + len = (*tp->tp_as_sequence->sq_length)(v); + } + else if (tp->tp_as_mapping != NULL) { + len = (*tp->tp_as_mapping->mp_length)(v); + } + else { + err_setstr(TypeError, "len() of unsized object"); + return NULL; + } + return newintobject(len); +} + +static object * +min_max(v, sign) + object *v; + int sign; +{ + int i, n, cmp; + object *w, *x; + sequence_methods *sq; + if (v == NULL) { + err_setstr(TypeError, "min() or max() without argument"); + return NULL; + } + sq = v->ob_type->tp_as_sequence; + if (sq == NULL) { + err_setstr(TypeError, "min() or max() of non-sequence"); + return NULL; + } + n = (*sq->sq_length)(v); + if (n == 0) { + err_setstr(RuntimeError, "min() or max() of empty sequence"); + return NULL; + } + w = (*sq->sq_item)(v, 0); /* Implies INCREF */ + for (i = 1; i < n; i++) { + x = (*sq->sq_item)(v, i); /* Implies INCREF */ + cmp = cmpobject(x, w); + if (cmp * sign > 0) { + DECREF(w); + w = x; + } + else + DECREF(x); + } + return w; +} + +static object * +builtin_min(self, v) + object *self; + object *v; +{ + return min_max(v, -1); +} + +static object * +builtin_max(self, v) + object *self; + object *v; +{ + return min_max(v, 1); +} + +static object * +builtin_open(self, v) + object *self; + object *v; +{ + object *name, *mode; + if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2 || + !is_stringobject(name = gettupleitem(v, 0)) || + !is_stringobject(mode = gettupleitem(v, 1))) { + err_setstr(TypeError, "open() requires 2 string arguments"); + return NULL; + } + v = newfileobject(getstringvalue(name), getstringvalue(mode)); + return v; +} + +static object * +builtin_ord(self, v) + object *self; + object *v; +{ + if (v == NULL || !is_stringobject(v)) { + err_setstr(TypeError, "ord() must have string argument"); + return NULL; + } + if (getstringsize(v) != 1) { + err_setstr(RuntimeError, "ord() arg must have length 1"); + return NULL; + } + return newintobject((long)(getstringvalue(v)[0] & 0xff)); +} + +static object * +builtin_range(self, v) + object *self; + object *v; +{ + static char *errmsg = "range() requires 1-3 int arguments"; + int i, n; + long ilow, ihigh, istep; + if (v != NULL && is_intobject(v)) { + ilow = 0; ihigh = getintvalue(v); istep = 1; + } + else if (v == NULL || !is_tupleobject(v)) { + err_setstr(TypeError, errmsg); + return NULL; + } + else { + n = gettuplesize(v); + if (n < 1 || n > 3) { + err_setstr(TypeError, errmsg); + return NULL; + } + for (i = 0; i < n; i++) { + if (!is_intobject(gettupleitem(v, i))) { + err_setstr(TypeError, errmsg); + return NULL; + } + } + if (n == 3) { + istep = getintvalue(gettupleitem(v, 2)); + --n; + } + else + istep = 1; + ihigh = getintvalue(gettupleitem(v, --n)); + if (n > 0) + ilow = getintvalue(gettupleitem(v, 0)); + else + ilow = 0; + } + if (istep == 0) { + err_setstr(RuntimeError, "zero step for range()"); + return NULL; + } + /* XXX ought to check overflow of subtraction */ + if (istep > 0) + n = (ihigh - ilow + istep - 1) / istep; + else + n = (ihigh - ilow + istep + 1) / istep; + if (n < 0) + n = 0; + v = newlistobject(n); + if (v == NULL) + return NULL; + for (i = 0; i < n; i++) { + object *w = newintobject(ilow); + if (w == NULL) { + DECREF(v); + return NULL; + } + setlistitem(v, i, w); + ilow += istep; + } + return v; +} + +static object * +builtin_raw_input(self, v) + object *self; + object *v; +{ + FILE *in = sysgetfile("stdin", stdin); + FILE *out = sysgetfile("stdout", stdout); + char *p; + int err; + int n = 1000; + flushline(); + if (v != NULL) + printobject(v, out, PRINT_RAW); + v = newsizedstringobject((char *)NULL, n); + if (v != NULL) { + if ((err = fgets_intr(getstringvalue(v), n+1, in)) != E_OK) { + err_input(err); + DECREF(v); + return NULL; + } + else { + n = strlen(getstringvalue(v)); + if (n > 0 && getstringvalue(v)[n-1] == '\n') + n--; + resizestring(&v, n); + } + } + return v; +} + +static object * +builtin_reload(self, v) + object *self; + object *v; +{ + return reload_module(v); +} + +static object * +builtin_type(self, v) + object *self; + object *v; +{ + if (v == NULL) { + err_setstr(TypeError, "type() requres an argument"); + return NULL; + } + v = (object *)v->ob_type; + INCREF(v); + return v; +} + +static struct methodlist builtin_methods[] = { + {"abs", builtin_abs}, + {"chr", builtin_chr}, + {"dir", builtin_dir}, + {"divmod", builtin_divmod}, + {"eval", builtin_eval}, + {"exec", builtin_exec}, + {"float", builtin_float}, + {"input", builtin_input}, + {"int", builtin_int}, + {"len", builtin_len}, + {"max", builtin_max}, + {"min", builtin_min}, + {"open", builtin_open}, /* XXX move to OS module */ + {"ord", builtin_ord}, + {"range", builtin_range}, + {"raw_input", builtin_raw_input}, + {"reload", builtin_reload}, + {"type", builtin_type}, + {NULL, NULL}, +}; + +static object *builtin_dict; + +object * +getbuiltin(name) + char *name; +{ + return dictlookup(builtin_dict, name); +} + +/* Predefined exceptions */ + +object *RuntimeError; +object *EOFError; +object *TypeError; +object *MemoryError; +object *NameError; +object *SystemError; +object *KeyboardInterrupt; + +static object * +newstdexception(name, message) + char *name, *message; +{ + object *v = newstringobject(message); + if (v == NULL || dictinsert(builtin_dict, name, v) != 0) + fatal("no mem for new standard exception"); + return v; +} + +static void +initerrors() +{ + RuntimeError = newstdexception("RuntimeError", "run-time error"); + EOFError = newstdexception("EOFError", "end-of-file read"); + TypeError = newstdexception("TypeError", "type error"); + MemoryError = newstdexception("MemoryError", "out of memory"); + NameError = newstdexception("NameError", "undefined name"); + SystemError = newstdexception("SystemError", "system error"); + KeyboardInterrupt = + newstdexception("KeyboardInterrupt", "keyboard interrupt"); +} + +void +initbuiltin() +{ + object *m; + m = initmodule("builtin", builtin_methods); + builtin_dict = getmoduledict(m); + INCREF(builtin_dict); + initerrors(); + (void) dictinsert(builtin_dict, "None", None); +} diff --git a/src/bltinmodule.h b/src/bltinmodule.h new file mode 100644 index 0000000..fe16907 --- /dev/null +++ b/src/bltinmodule.h @@ -0,0 +1,27 @@ +/*********************************************************** +Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +Netherlands. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* Built-in module interface */ + +extern object *getbuiltin PROTO((char *)); diff --git a/src/ceval.c b/src/ceval.c new file mode 100644 index 0000000..6876208 --- /dev/null +++ b/src/ceval.c @@ -0,0 +1,1436 @@ +/*********************************************************** +Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +Netherlands. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* Execute compiled code */ + +#include "allobjects.h" + +#include "import.h" +#include "sysmodule.h" +#include "compile.h" +#include "frameobject.h" +#include "ceval.h" +#include "opcode.h" +#include "bltinmodule.h" +#include "traceback.h" + +#ifndef NDEBUG +#define TRACE +#endif + +#ifdef TRACE +static int +prtrace(v, str) + object *v; + char *str; +{ + printf("%s ", str); + printobject(v, stdout, 0); + printf("\n"); +} +#endif + +static frameobject *current_frame; + +object * +getlocals() +{ + if (current_frame == NULL) + return NULL; + else + return current_frame->f_locals; +} + +object * +getglobals() +{ + if (current_frame == NULL) + return NULL; + else + return current_frame->f_globals; +} + +void +printtraceback(fp) + FILE *fp; +{ + object *v = tb_fetch(); + if (v != NULL) { + fprintf(fp, "Stack backtrace (innermost last):\n"); + tb_print(v, fp); + DECREF(v); + } +} + + +/* XXX Mixing "print ...," and direct file I/O on stdin/stdout + XXX has some bad consequences. The needspace flag should + XXX really be part of the file object. */ + +static int needspace; + +void +flushline() +{ + FILE *fp = sysgetfile("stdout", stdout); + if (needspace) { + fprintf(fp, "\n"); + needspace = 0; + } +} + + +/* Test a value used as condition, e.g., in a for or if statement */ + +static int +testbool(v) + object *v; +{ + if (is_intobject(v)) + return getintvalue(v) != 0; + if (is_floatobject(v)) + return getfloatvalue(v) != 0.0; + if (v->ob_type->tp_as_sequence != NULL) + return (*v->ob_type->tp_as_sequence->sq_length)(v) != 0; + if (v->ob_type->tp_as_mapping != NULL) + return (*v->ob_type->tp_as_mapping->mp_length)(v) != 0; + if (v == None) + return 0; + /* All other objects are 'true' */ + return 1; +} + +static object * +add(v, w) + object *v, *w; +{ + if (v->ob_type->tp_as_number != NULL) + v = (*v->ob_type->tp_as_number->nb_add)(v, w); + else if (v->ob_type->tp_as_sequence != NULL) + v = (*v->ob_type->tp_as_sequence->sq_concat)(v, w); + else { + err_setstr(TypeError, "+ not supported by operands"); + return NULL; + } + return v; +} + +static object * +sub(v, w) + object *v, *w; +{ + if (v->ob_type->tp_as_number != NULL) + return (*v->ob_type->tp_as_number->nb_subtract)(v, w); + err_setstr(TypeError, "bad operand type(s) for -"); + return NULL; +} + +static object * +mul(v, w) + object *v, *w; +{ + typeobject *tp; + if (is_intobject(v) && w->ob_type->tp_as_sequence != NULL) { + /* int*sequence -- swap v and w */ + object *tmp = v; + v = w; + w = tmp; + } + tp = v->ob_type; + if (tp->tp_as_number != NULL) + return (*tp->tp_as_number->nb_multiply)(v, w); + if (tp->tp_as_sequence != NULL) { + if (!is_intobject(w)) { + err_setstr(TypeError, + "can't multiply sequence with non-int"); + return NULL; + } + if (tp->tp_as_sequence->sq_repeat == NULL) { + err_setstr(TypeError, "sequence does not support *"); + return NULL; + } + return (*tp->tp_as_sequence->sq_repeat) + (v, (int)getintvalue(w)); + } + err_setstr(TypeError, "bad operand type(s) for *"); + return NULL; +} + +static object * +divide(v, w) + object *v, *w; +{ + if (v->ob_type->tp_as_number != NULL) + return (*v->ob_type->tp_as_number->nb_divide)(v, w); + err_setstr(TypeError, "bad operand type(s) for /"); + return NULL; +} + +static object * +rem(v, w) + object *v, *w; +{ + if (v->ob_type->tp_as_number != NULL) + return (*v->ob_type->tp_as_number->nb_remainder)(v, w); + err_setstr(TypeError, "bad operand type(s) for %"); + return NULL; +} + +static object * +neg(v) + object *v; +{ + if (v->ob_type->tp_as_number != NULL) + return (*v->ob_type->tp_as_number->nb_negative)(v); + err_setstr(TypeError, "bad operand type(s) for unary -"); + return NULL; +} + +static object * +pos(v) + object *v; +{ + if (v->ob_type->tp_as_number != NULL) + return (*v->ob_type->tp_as_number->nb_positive)(v); + err_setstr(TypeError, "bad operand type(s) for unary +"); + return NULL; +} + +static object * +not(v) + object *v; +{ + int outcome = testbool(v); + object *w = outcome == 0 ? True : False; + INCREF(w); + return w; +} + +static object * +call_builtin(func, arg) + object *func; + object *arg; +{ + if (is_methodobject(func)) { + method meth = getmethod(func); + object *self = getself(func); + return (*meth)(self, arg); + } + if (is_classobject(func)) { + if (arg != NULL) { + err_setstr(TypeError, + "classobject() allows no arguments"); + return NULL; + } + return newclassmemberobject(func); + } + err_setstr(TypeError, "call of non-function"); + return NULL; +} + +static object * +call_function(func, arg) + object *func; + object *arg; +{ + object *newarg = NULL; + object *newlocals, *newglobals; + object *co, *v; + + if (is_classmethodobject(func)) { + object *self = classmethodgetself(func); + func = classmethodgetfunc(func); + if (arg == NULL) { + arg = self; + } + else { + newarg = newtupleobject(2); + if (newarg == NULL) + return NULL; + INCREF(self); + INCREF(arg); + settupleitem(newarg, 0, self); + settupleitem(newarg, 1, arg); + arg = newarg; + } + } + else { + if (!is_funcobject(func)) { + err_setstr(TypeError, "call of non-function"); + return NULL; + } + } + + co = getfunccode(func); + if (co == NULL) { + XDECREF(newarg); + return NULL; + } + if (!is_codeobject(co)) { + fprintf(stderr, "XXX Bad code\n"); + abort(); + } + newlocals = newdictobject(); + if (newlocals == NULL) { + XDECREF(newarg); + return NULL; + } + + newglobals = getfuncglobals(func); + INCREF(newglobals); + + v = eval_code((codeobject *)co, newglobals, newlocals, arg); + + DECREF(newlocals); + DECREF(newglobals); + + XDECREF(newarg); + + return v; +} + +static object * +apply_subscript(v, w) + object *v, *w; +{ + typeobject *tp = v->ob_type; + if (tp->tp_as_sequence == NULL && tp->tp_as_mapping == NULL) { + err_setstr(TypeError, "unsubscriptable object"); + return NULL; + } + if (tp->tp_as_sequence != NULL) { + int i; + if (!is_intobject(w)) { + err_setstr(TypeError, "sequence subscript not int"); + return NULL; + } + i = getintvalue(w); + return (*tp->tp_as_sequence->sq_item)(v, i); + } + return (*tp->tp_as_mapping->mp_subscript)(v, w); +} + +static object * +loop_subscript(v, w) + object *v, *w; +{ + sequence_methods *sq = v->ob_type->tp_as_sequence; + int i, n; + if (sq == NULL) { + err_setstr(TypeError, "loop over non-sequence"); + return NULL; + } + i = getintvalue(w); + n = (*sq->sq_length)(v); + if (i >= n) + return NULL; /* End of loop */ + return (*sq->sq_item)(v, i); +} + +static int +slice_index(v, isize, pi) + object *v; + int isize; + int *pi; +{ + if (v != NULL) { + if (!is_intobject(v)) { + err_setstr(TypeError, "slice index must be int"); + return -1; + } + *pi = getintvalue(v); + if (*pi < 0) + *pi += isize; + } + return 0; +} + +static object * +apply_slice(u, v, w) /* return u[v:w] */ + object *u, *v, *w; +{ + typeobject *tp = u->ob_type; + int ilow, ihigh, isize; + if (tp->tp_as_sequence == NULL) { + err_setstr(TypeError, "only sequences can be sliced"); + return NULL; + } + ilow = 0; + isize = ihigh = (*tp->tp_as_sequence->sq_length)(u); + if (slice_index(v, isize, &ilow) != 0) + return NULL; + if (slice_index(w, isize, &ihigh) != 0) + return NULL; + return (*tp->tp_as_sequence->sq_slice)(u, ilow, ihigh); +} + +static int +assign_subscript(w, key, v) /* w[key] = v */ + object *w; + object *key; + object *v; +{ + typeobject *tp = w->ob_type; + sequence_methods *sq; + mapping_methods *mp; + int (*func)(); + if ((sq = tp->tp_as_sequence) != NULL && + (func = sq->sq_ass_item) != NULL) { + if (!is_intobject(key)) { + err_setstr(TypeError, + "sequence subscript must be integer"); + return -1; + } + else + return (*func)(w, (int)getintvalue(key), v); + } + else if ((mp = tp->tp_as_mapping) != NULL && + (func = mp->mp_ass_subscript) != NULL) { + return (*func)(w, key, v); + } + else { + err_setstr(TypeError, + "can't assign to this subscripted object"); + return -1; + } +} + +static int +assign_slice(u, v, w, x) /* u[v:w] = x */ + object *u, *v, *w, *x; +{ + sequence_methods *sq = u->ob_type->tp_as_sequence; + int ilow, ihigh, isize; + if (sq == NULL) { + err_setstr(TypeError, "assign to slice of non-sequence"); + return -1; + } + if (sq == NULL || sq->sq_ass_slice == NULL) { + err_setstr(TypeError, "unassignable slice"); + return -1; + } + ilow = 0; + isize = ihigh = (*sq->sq_length)(u); + if (slice_index(v, isize, &ilow) != 0) + return -1; + if (slice_index(w, isize, &ihigh) != 0) + return -1; + return (*sq->sq_ass_slice)(u, ilow, ihigh, x); +} + +static int +cmp_exception(err, v) + object *err, *v; +{ + if (is_tupleobject(v)) { + int i, n; + n = gettuplesize(v); + for (i = 0; i < n; i++) { + if (err == gettupleitem(v, i)) + return 1; + } + return 0; + } + return err == v; +} + +static int +cmp_member(v, w) + object *v, *w; +{ + int i, n, cmp; + object *x; + sequence_methods *sq; + /* Special case for char in string */ + if (is_stringobject(w)) { + register char *s, *end; + register char c; + if (!is_stringobject(v) || getstringsize(v) != 1) { + err_setstr(TypeError, + "string member test needs char left operand"); + return -1; + } + c = getstringvalue(v)[0]; + s = getstringvalue(w); + end = s + getstringsize(w); + while (s < end) { + if (c == *s++) + return 1; + } + return 0; + } + sq = w->ob_type->tp_as_sequence; + if (sq == NULL) { + err_setstr(TypeError, + "'in' or 'not in' needs sequence right argument"); + return -1; + } + n = (*sq->sq_length)(w); + for (i = 0; i < n; i++) { + x = (*sq->sq_item)(w, i); + cmp = cmpobject(v, x); + XDECREF(x); + if (cmp == 0) + return 1; + } + return 0; +} + +static object * +cmp_outcome(op, v, w) + enum cmp_op op; + register object *v; + register object *w; +{ + register int cmp; + register int res = 0; + switch (op) { + case IS: + case IS_NOT: + res = (v == w); + if (op == IS_NOT) + res = !res; + break; + case IN: + case NOT_IN: + res = cmp_member(v, w); + if (res < 0) + return NULL; + if (op == NOT_IN) + res = !res; + break; + case EXC_MATCH: + res = cmp_exception(v, w); + break; + default: + cmp = cmpobject(v, w); + switch (op) { + case LT: res = cmp < 0; break; + case LE: res = cmp <= 0; break; + case EQ: res = cmp == 0; break; + case NE: res = cmp != 0; break; + case GT: res = cmp > 0; break; + case GE: res = cmp >= 0; break; + /* XXX no default? (res is initialized to 0 though) */ + } + } + v = res ? True : False; + INCREF(v); + return v; +} + +static int +import_from(locals, v, name) + object *locals; + object *v; + char *name; +{ + object *w, *x; + w = getmoduledict(v); + if (name[0] == '*') { + int i; + int n = getdictsize(w); + for (i = 0; i < n; i++) { + name = getdictkey(w, i); + if (name == NULL || name[0] == '_') + continue; + x = dictlookup(w, name); + if (x == NULL) { + /* XXX can't happen? */ + err_setstr(NameError, name); + return -1; + } + if (dictinsert(locals, name, x) != 0) + return -1; + } + return 0; + } + else { + x = dictlookup(w, name); + if (x == NULL) { + err_setstr(NameError, name); + return -1; + } + else + return dictinsert(locals, name, x); + } +} + +static object * +build_class(v, w) + object *v; /* None or tuple containing base classes */ + object *w; /* dictionary */ +{ + if (is_tupleobject(v)) { + int i; + for (i = gettuplesize(v); --i >= 0; ) { + object *x = gettupleitem(v, i); + if (!is_classobject(x)) { + err_setstr(TypeError, + "base is not a class object"); + return NULL; + } + } + } + else { + v = NULL; + } + if (!is_dictobject(w)) { + err_setstr(SystemError, "build_class with non-dictionary"); + return NULL; + } + return newclassobject(v, w); +} + + +/* Status code for main loop (reason for stack unwind) */ + +enum why_code { + WHY_NOT, /* No error */ + WHY_EXCEPTION, /* Exception occurred */ + WHY_RERAISE, /* Exception re-raised by 'finally' */ + WHY_RETURN, /* 'return' statement */ + WHY_BREAK /* 'break' statement */ +}; + +/* Interpreter main loop */ + +object * +eval_code(co, globals, locals, arg) + codeobject *co; + object *globals; + object *locals; + object *arg; +{ + register unsigned char *next_instr; + register int opcode; /* Current opcode */ + register int oparg; /* Current opcode argument, if any */ + register object **stack_pointer; + register enum why_code why; /* Reason for block stack unwind */ + register int err; /* Error status -- nonzero if error */ + register object *x; /* Result object -- NULL if error */ + register object *v; /* Temporary objects popped off stack */ + register object *w; + register object *u; + register object *t; + register frameobject *f; /* Current frame */ + int lineno; /* Current line number */ + object *retval; /* Return value iff why == WHY_RETURN */ + char *name; /* Name used by some instructions */ + FILE *fp; /* Used by print operations */ +#ifdef TRACE + int trace = dictlookup(globals, "__trace__") != NULL; +#endif + +/* Code access macros */ + +#define GETCONST(i) Getconst(f, i) +#define GETNAME(i) Getname(f, i) +#define FIRST_INSTR() (GETUSTRINGVALUE(f->f_code->co_code)) +#define INSTR_OFFSET() (next_instr - FIRST_INSTR()) +#define NEXTOP() (*next_instr++) +#define NEXTARG() (next_instr += 2, (next_instr[-1]<<8) + next_instr[-2]) +#define JUMPTO(x) (next_instr = FIRST_INSTR() + (x)) +#define JUMPBY(x) (next_instr += (x)) + +/* Stack manipulation macros */ + +#define STACK_LEVEL() (stack_pointer - f->f_valuestack) +#define EMPTY() (STACK_LEVEL() == 0) +#define TOP() (stack_pointer[-1]) +#define BASIC_PUSH(v) (*stack_pointer++ = (v)) +#define BASIC_POP() (*--stack_pointer) + +#ifdef TRACE +#define PUSH(v) (BASIC_PUSH(v), trace && prtrace(TOP(), "push")) +#define POP() (trace && prtrace(TOP(), "pop"), BASIC_POP()) +#else +#define PUSH(v) BASIC_PUSH(v) +#define POP() BASIC_POP() +#endif + + f = newframeobject( + current_frame, /*back*/ + co, /*code*/ + globals, /*globals*/ + locals, /*locals*/ + 50, /*nvalues*/ + 20); /*nblocks*/ + if (f == NULL) + return NULL; + + current_frame = f; + + next_instr = GETUSTRINGVALUE(f->f_code->co_code); + + stack_pointer = f->f_valuestack; + + if (arg != NULL) { + INCREF(arg); + PUSH(arg); + } + + why = WHY_NOT; + err = 0; + x = None; /* Not a reference, just anything non-NULL */ + lineno = -1; + + for (;;) { + static ticker; + + /* Do periodic things */ + + if (--ticker < 0) { + ticker = 100; + if (intrcheck()) { + err_set(KeyboardInterrupt); + why = WHY_EXCEPTION; + tb_here(f, INSTR_OFFSET(), lineno); + break; + } + } + + /* Extract opcode and argument */ + + opcode = NEXTOP(); + if (HAS_ARG(opcode)) + oparg = NEXTARG(); + +#ifdef TRACE + /* Instruction tracing */ + + if (trace) { + if (HAS_ARG(opcode)) { + printf("%d: %d, %d\n", + (int) (INSTR_OFFSET() - 3), + opcode, oparg); + } + else { + printf("%d: %d\n", + (int) (INSTR_OFFSET() - 1), opcode); + } + } +#endif + + /* Main switch on opcode */ + + switch (opcode) { + + /* BEWARE! + It is essential that any operation that fails sets either + x to NULL, err to nonzero, or why to anything but WHY_NOT, + and that no operation that succeeds does this! */ + + /* case STOP_CODE: this is an error! */ + + case POP_TOP: + v = POP(); + DECREF(v); + break; + + case ROT_TWO: + v = POP(); + w = POP(); + PUSH(v); + PUSH(w); + break; + + case ROT_THREE: + v = POP(); + w = POP(); + x = POP(); + PUSH(v); + PUSH(x); + PUSH(w); + break; + + case DUP_TOP: + v = TOP(); + INCREF(v); + PUSH(v); + break; + + case UNARY_POSITIVE: + v = POP(); + x = pos(v); + DECREF(v); + PUSH(x); + break; + + case UNARY_NEGATIVE: + v = POP(); + x = neg(v); + DECREF(v); + PUSH(x); + break; + + case UNARY_NOT: + v = POP(); + x = not(v); + DECREF(v); + PUSH(x); + break; + + case UNARY_CONVERT: + v = POP(); + x = reprobject(v); + DECREF(v); + PUSH(x); + break; + + case UNARY_CALL: + v = POP(); + if (is_classmethodobject(v) || is_funcobject(v)) + x = call_function(v, (object *)NULL); + else + x = call_builtin(v, (object *)NULL); + DECREF(v); + PUSH(x); + break; + + case BINARY_MULTIPLY: + w = POP(); + v = POP(); + x = mul(v, w); + DECREF(v); + DECREF(w); + PUSH(x); + break; + + case BINARY_DIVIDE: + w = POP(); + v = POP(); + x = divide(v, w); + DECREF(v); + DECREF(w); + PUSH(x); + break; + + case BINARY_MODULO: + w = POP(); + v = POP(); + x = rem(v, w); + DECREF(v); + DECREF(w); + PUSH(x); + break; + + case BINARY_ADD: + w = POP(); + v = POP(); + x = add(v, w); + DECREF(v); + DECREF(w); + PUSH(x); + break; + + case BINARY_SUBTRACT: + w = POP(); + v = POP(); + x = sub(v, w); + DECREF(v); + DECREF(w); + PUSH(x); + break; + + case BINARY_SUBSCR: + w = POP(); + v = POP(); + x = apply_subscript(v, w); + DECREF(v); + DECREF(w); + PUSH(x); + break; + + case BINARY_CALL: + w = POP(); + v = POP(); + if (is_classmethodobject(v) || is_funcobject(v)) + x = call_function(v, w); + else + x = call_builtin(v, w); + DECREF(v); + DECREF(w); + PUSH(x); + break; + + case SLICE+0: + case SLICE+1: + case SLICE+2: + case SLICE+3: + if ((opcode-SLICE) & 2) + w = POP(); + else + w = NULL; + if ((opcode-SLICE) & 1) + v = POP(); + else + v = NULL; + u = POP(); + x = apply_slice(u, v, w); + DECREF(u); + XDECREF(v); + XDECREF(w); + PUSH(x); + break; + + case STORE_SLICE+0: + case STORE_SLICE+1: + case STORE_SLICE+2: + case STORE_SLICE+3: + if ((opcode-STORE_SLICE) & 2) + w = POP(); + else + w = NULL; + if ((opcode-STORE_SLICE) & 1) + v = POP(); + else + v = NULL; + u = POP(); + t = POP(); + err = assign_slice(u, v, w, t); /* u[v:w] = t */ + DECREF(t); + DECREF(u); + XDECREF(v); + XDECREF(w); + break; + + case DELETE_SLICE+0: + case DELETE_SLICE+1: + case DELETE_SLICE+2: + case DELETE_SLICE+3: + if ((opcode-DELETE_SLICE) & 2) + w = POP(); + else + w = NULL; + if ((opcode-DELETE_SLICE) & 1) + v = POP(); + else + v = NULL; + u = POP(); + err = assign_slice(u, v, w, (object *)NULL); + /* del u[v:w] */ + DECREF(u); + XDECREF(v); + XDECREF(w); + break; + + case STORE_SUBSCR: + w = POP(); + v = POP(); + u = POP(); + /* v[w] = u */ + err = assign_subscript(v, w, u); + DECREF(u); + DECREF(v); + DECREF(w); + break; + + case DELETE_SUBSCR: + w = POP(); + v = POP(); + /* del v[w] */ + err = assign_subscript(v, w, (object *)NULL); + DECREF(v); + DECREF(w); + break; + + case PRINT_EXPR: + v = POP(); + fp = sysgetfile("stdout", stdout); + /* Print value except if procedure result */ + if (v != None) { + flushline(); + printobject(v, fp, 0); + fprintf(fp, "\n"); + } + DECREF(v); + break; + + case PRINT_ITEM: + v = POP(); + fp = sysgetfile("stdout", stdout); + if (needspace) + fprintf(fp, " "); + if (is_stringobject(v)) { + char *s = getstringvalue(v); + int len = getstringsize(v); + fwrite(s, 1, len, fp); + if (len > 0 && s[len-1] == '\n') + needspace = 0; + else + needspace = 1; + } + else { + printobject(v, fp, 0); + needspace = 1; + } + DECREF(v); + break; + + case PRINT_NEWLINE: + fp = sysgetfile("stdout", stdout); + fprintf(fp, "\n"); + needspace = 0; + break; + + case BREAK_LOOP: + why = WHY_BREAK; + break; + + case RAISE_EXCEPTION: + v = POP(); + w = POP(); + if (!is_stringobject(w)) + err_setstr(TypeError, + "exceptions must be strings"); + else + err_setval(w, v); + DECREF(v); + DECREF(w); + why = WHY_EXCEPTION; + break; + + case LOAD_LOCALS: + v = f->f_locals; + INCREF(v); + PUSH(v); + break; + + case RETURN_VALUE: + retval = POP(); + why = WHY_RETURN; + break; + + case REQUIRE_ARGS: + if (EMPTY()) { + err_setstr(TypeError, + "function expects argument(s)"); + why = WHY_EXCEPTION; + } + break; + + case REFUSE_ARGS: + if (!EMPTY()) { + err_setstr(TypeError, + "function expects no argument(s)"); + why = WHY_EXCEPTION; + } + break; + + case BUILD_FUNCTION: + v = POP(); + x = newfuncobject(v, f->f_globals); + DECREF(v); + PUSH(x); + break; + + case POP_BLOCK: + { + block *b = pop_block(f); + while (STACK_LEVEL() > b->b_level) { + v = POP(); + DECREF(v); + } + } + break; + + case END_FINALLY: + v = POP(); + if (is_intobject(v)) { + why = (enum why_code) getintvalue(v); + if (why == WHY_RETURN) + retval = POP(); + } + else if (is_stringobject(v)) { + w = POP(); + err_setval(v, w); + DECREF(w); + w = POP(); + tb_store(w); + DECREF(w); + why = WHY_RERAISE; + } + else if (v != None) { + err_setstr(SystemError, + "'finally' pops bad exception"); + why = WHY_EXCEPTION; + } + DECREF(v); + break; + + case BUILD_CLASS: + w = POP(); + v = POP(); + x = build_class(v, w); + PUSH(x); + DECREF(v); + DECREF(w); + break; + + case STORE_NAME: + name = GETNAME(oparg); + v = POP(); + err = dictinsert(f->f_locals, name, v); + DECREF(v); + break; + + case DELETE_NAME: + name = GETNAME(oparg); + if ((err = dictremove(f->f_locals, name)) != 0) + err_setstr(NameError, name); + break; + + case UNPACK_TUPLE: + v = POP(); + if (!is_tupleobject(v)) { + err_setstr(TypeError, "unpack non-tuple"); + why = WHY_EXCEPTION; + } + else if (gettuplesize(v) != oparg) { + err_setstr(RuntimeError, + "unpack tuple of wrong size"); + why = WHY_EXCEPTION; + } + else { + for (; --oparg >= 0; ) { + w = gettupleitem(v, oparg); + INCREF(w); + PUSH(w); + } + } + DECREF(v); + break; + + case UNPACK_LIST: + v = POP(); + if (!is_listobject(v)) { + err_setstr(TypeError, "unpack non-list"); + why = WHY_EXCEPTION; + } + else if (getlistsize(v) != oparg) { + err_setstr(RuntimeError, + "unpack list of wrong size"); + why = WHY_EXCEPTION; + } + else { + for (; --oparg >= 0; ) { + w = getlistitem(v, oparg); + INCREF(w); + PUSH(w); + } + } + DECREF(v); + break; + + case STORE_ATTR: + name = GETNAME(oparg); + v = POP(); + u = POP(); + err = setattr(v, name, u); /* v.name = u */ + DECREF(v); + DECREF(u); + break; + + case DELETE_ATTR: + name = GETNAME(oparg); + v = POP(); + err = setattr(v, name, (object *)NULL); + /* del v.name */ + DECREF(v); + break; + + case LOAD_CONST: + x = GETCONST(oparg); + INCREF(x); + PUSH(x); + break; + + case LOAD_NAME: + name = GETNAME(oparg); + x = dictlookup(f->f_locals, name); + if (x == NULL) { + x = dictlookup(f->f_globals, name); + if (x == NULL) + x = getbuiltin(name); + } + if (x == NULL) + err_setstr(NameError, name); + else + INCREF(x); + PUSH(x); + break; + + case BUILD_TUPLE: + x = newtupleobject(oparg); + if (x != NULL) { + for (; --oparg >= 0;) { + w = POP(); + err = settupleitem(x, oparg, w); + if (err != 0) + break; + } + PUSH(x); + } + break; + + case BUILD_LIST: + x = newlistobject(oparg); + if (x != NULL) { + for (; --oparg >= 0;) { + w = POP(); + err = setlistitem(x, oparg, w); + if (err != 0) + break; + } + PUSH(x); + } + break; + + case BUILD_MAP: + x = newdictobject(); + PUSH(x); + break; + + case LOAD_ATTR: + name = GETNAME(oparg); + v = POP(); + x = getattr(v, name); + DECREF(v); + PUSH(x); + break; + + case COMPARE_OP: + w = POP(); + v = POP(); + x = cmp_outcome((enum cmp_op)oparg, v, w); + DECREF(v); + DECREF(w); + PUSH(x); + break; + + case IMPORT_NAME: + name = GETNAME(oparg); + x = import_module(name); + XINCREF(x); + PUSH(x); + break; + + case IMPORT_FROM: + name = GETNAME(oparg); + v = TOP(); + err = import_from(f->f_locals, v, name); + break; + + case JUMP_FORWARD: + JUMPBY(oparg); + break; + + case JUMP_IF_FALSE: + if (!testbool(TOP())) + JUMPBY(oparg); + break; + + case JUMP_IF_TRUE: + if (testbool(TOP())) + JUMPBY(oparg); + break; + + case JUMP_ABSOLUTE: + JUMPTO(oparg); + break; + + case FOR_LOOP: + /* for v in s: ... + On entry: stack contains s, i. + On exit: stack contains s, i+1, s[i]; + but if loop exhausted: + s, i are popped, and we jump */ + w = POP(); /* Loop index */ + v = POP(); /* Sequence object */ + u = loop_subscript(v, w); + if (u != NULL) { + PUSH(v); + x = newintobject(getintvalue(w)+1); + PUSH(x); + DECREF(w); + PUSH(u); + } + else { + DECREF(v); + DECREF(w); + /* A NULL can mean "s exhausted" + but also an error: */ + if (err_occurred()) + why = WHY_EXCEPTION; + else + JUMPBY(oparg); + } + break; + + case SETUP_LOOP: + case SETUP_EXCEPT: + case SETUP_FINALLY: + setup_block(f, opcode, INSTR_OFFSET() + oparg, + STACK_LEVEL()); + break; + + case SET_LINENO: +#ifdef TRACE + if (trace) + printf("--- Line %d ---\n", oparg); +#endif + lineno = oparg; + break; + + default: + fprintf(stderr, + "XXX lineno: %d, opcode: %d\n", + lineno, opcode); + err_setstr(SystemError, "eval_code: unknown opcode"); + why = WHY_EXCEPTION; + break; + + } /* switch */ + + + /* Quickly continue if no error occurred */ + + if (why == WHY_NOT) { + if (err == 0 && x != NULL) + continue; /* Normal, fast path */ + why = WHY_EXCEPTION; + x = None; + err = 0; + } + +#ifndef NDEBUG + /* Double-check exception status */ + + if (why == WHY_EXCEPTION || why == WHY_RERAISE) { + if (!err_occurred()) { + fprintf(stderr, "XXX ghost error\n"); + err_setstr(SystemError, "ghost error"); + why = WHY_EXCEPTION; + } + } + else { + if (err_occurred()) { + fprintf(stderr, "XXX undetected error\n"); + why = WHY_EXCEPTION; + } + } +#endif + + /* Log traceback info if this is a real exception */ + + if (why == WHY_EXCEPTION) { + int lasti = INSTR_OFFSET() - 1; + if (HAS_ARG(opcode)) + lasti -= 2; + tb_here(f, lasti, lineno); + } + + /* For the rest, treat WHY_RERAISE as WHY_EXCEPTION */ + + if (why == WHY_RERAISE) + why = WHY_EXCEPTION; + + /* Unwind stacks if a (pseudo) exception occurred */ + + while (why != WHY_NOT && f->f_iblock > 0) { + block *b = pop_block(f); + while (STACK_LEVEL() > b->b_level) { + v = POP(); + XDECREF(v); + } + if (b->b_type == SETUP_LOOP && why == WHY_BREAK) { + why = WHY_NOT; + JUMPTO(b->b_handler); + break; + } + if (b->b_type == SETUP_FINALLY || + b->b_type == SETUP_EXCEPT && + why == WHY_EXCEPTION) { + if (why == WHY_EXCEPTION) { + object *exc, *val; + err_get(&exc, &val); + if (val == NULL) { + val = None; + INCREF(val); + } + v = tb_fetch(); + /* Make the raw exception data + available to the handler, + so a program can emulate the + Python main loop. Don't do + this for 'finally'. */ + if (b->b_type == SETUP_EXCEPT) { +#if 0 /* Oops, this breaks too many things */ + sysset("exc_traceback", v); +#endif + sysset("exc_value", val); + sysset("exc_type", exc); + err_clear(); + } + PUSH(v); + PUSH(val); + PUSH(exc); + } + else { + if (why == WHY_RETURN) + PUSH(retval); + v = newintobject((long)why); + PUSH(v); + } + why = WHY_NOT; + JUMPTO(b->b_handler); + break; + } + } /* unwind stack */ + + /* End the loop if we still have an error (or return) */ + + if (why != WHY_NOT) + break; + + } /* main loop */ + + /* Pop remaining stack entries */ + + while (!EMPTY()) { + v = POP(); + XDECREF(v); + } + + /* Restore previous frame and release the current one */ + + current_frame = f->f_back; + DECREF(f); + + if (why == WHY_RETURN) + return retval; + else + return NULL; +} diff --git a/src/ceval.h b/src/ceval.h new file mode 100644 index 0000000..7f57738 --- /dev/null +++ b/src/ceval.h @@ -0,0 +1,33 @@ +/*********************************************************** +Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +Netherlands. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* Interface to execute compiled code */ +/* This header depends on "compile.h" */ + +object *eval_code PROTO((codeobject *, object *, object *, object *)); + +object *getglobals PROTO((void)); +object *getlocals PROTO((void)); + +void printtraceback PROTO((FILE *)); diff --git a/src/cgen b/src/cgen new file mode 100644 index 0000000..c2f0d0c --- /dev/null +++ b/src/cgen @@ -0,0 +1,458 @@ +# Python script to parse cstubs file for gl and generate C stubs. +# usage: python cgen glmodule.c +# +# XXX BUG return arrays generate wrong code +# XXX need to change error returns into gotos to free mallocked arrays + + +import string +import sys + + +# Function to print to stderr +# +def err(args): + savestdout = sys.stdout + try: + sys.stdout = sys.stderr + for i in args: + print i, + print + finally: + sys.stdout = savestdout + + +# The set of digits that form a number +# +digits = '0123456789' + + +# Function to extract a string of digits from the front of the string. +# Returns the leading string of digits and the remaining string. +# If no number is found, returns '' and the original string. +# +def getnum(s): + n = '' + while s and s[0] in digits: + n = n + s[0] + s = s[1:] + return n, s + + +# Function to check if a string is a number +# +def isnum(s): + if not s: return 0 + for c in s: + if not c in digits: return 0 + return 1 + + +# Allowed function return types +# +return_types = ['void', 'short', 'long'] + + +# Allowed function argument types +# +arg_types = ['char', 'string', 'short', 'float', 'long', 'double'] + + +# Need to classify arguments as follows +# simple input variable +# simple output variable +# input array +# output array +# input giving size of some array +# +# Array dimensions can be specified as follows +# constant +# argN +# constant * argN +# retval +# constant * retval +# +# The dimensions given as constants * something are really +# arrays of points where points are 2- 3- or 4-tuples +# +# We have to consider three lists: +# python input arguments +# C stub arguments (in & out) +# python output arguments (really return values) +# +# There is a mapping from python input arguments to the input arguments +# of the C stub, and a further mapping from C stub arguments to the +# python return values + + +# Exception raised by checkarg() and generate() +# +arg_error = 'bad arg' + + +# Function to check one argument. +# Arguments: the type and the arg "name" (really mode plus subscript). +# Raises arg_error if something's wrong. +# Return type, mode, factor, rest of subscript; factor and rest may be empty. +# +def checkarg(type, arg): + # + # Turn "char *x" into "string x". + # + if type = 'char' and arg[0] = '*': + type = 'string' + arg = arg[1:] + # + # Check that the type is supported. + # + if type not in arg_types: + raise arg_error, ('bad type', type) + # + # Split it in the mode (first character) and the rest. + # + mode, rest = arg[:1], arg[1:] + # + # The mode must be 's' for send (= input) or 'r' for return argument. + # + if mode not in ('r', 's'): + raise arg_error, ('bad arg mode', mode) + # + # Is it a simple argument: if so, we are done. + # + if not rest: + return type, mode, '', '' + # + # Not a simple argument; must be an array. + # The 'rest' must be a subscript enclosed in [ and ]. + # The subscript must be one of the following forms, + # otherwise we don't handle it (where N is a number): + # N + # argN + # retval + # N*argN + # N*retval + # + if rest[:1] <> '[' or rest[-1:] <> ']': + raise arg_error, ('subscript expected', rest) + sub = rest[1:-1] + # + # Is there a leading number? + # + num, sub = getnum(sub) + if num: + # There is a leading number + if not sub: + # The subscript is just a number + return type, mode, num, '' + if sub[:1] = '*': + # There is a factor prefix + sub = sub[1:] + else: + raise arg_error, ('\'*\' expected', sub) + if sub = 'retval': + # size is retval -- must be a reply argument + if mode <> 'r': + raise arg_error, ('non-r mode with [retval]', mode) + elif sub[:3] <> 'arg' or not isnum(sub[3:]): + raise arg_error, ('bad subscript', sub) + # + return type, mode, num, sub + + +# List of functions for which we have generated stubs +# +functions = [] + + +# Generate the stub for the given function, using the database of argument +# information build by successive calls to checkarg() +# +def generate(type, func, database): + # + # Check that we can handle this case: + # no variable size reply arrays yet + # + n_in_args = 0 + n_out_args = 0 + # + for a_type, a_mode, a_factor, a_sub in database: + if a_mode = 's': + n_in_args = n_in_args + 1 + elif a_mode = 'r': + n_out_args = n_out_args + 1 + else: + # Can't happen + raise arg_error, ('bad a_mode', a_mode) + if (a_mode = 'r' and a_sub) or a_sub = 'retval': + e = 'Function', func, 'too complicated:' + err(e + (a_type, a_mode, a_factor, a_sub)) + print '/* XXX Too complicated to generate code for */' + return + # + functions.append(func) + # + # Stub header + # + print + print 'static object *' + print 'gl_' + func + '(self, args)' + print '\tobject *self;' + print '\tobject *args;' + print '{' + # + # Declare return value if any + # + if type <> 'void': + print '\t' + type, 'retval;' + # + # Declare arguments + # + for i in range(len(database)): + a_type, a_mode, a_factor, a_sub = database[i] + print '\t' + a_type, + if a_sub: + print '*', + print 'arg' + `i+1`, + if a_factor and not a_sub: + print '[', a_factor, ']', + print ';' + # + # Find input arguments derived from array sizes + # + for i in range(len(database)): + a_type, a_mode, a_factor, a_sub = database[i] + if a_mode = 's' and a_sub[:3] = 'arg' and isnum(a_sub[3:]): + # Sending a variable-length array + n = eval(a_sub[3:]) + if 1 <= n <= len(database): + b_type, b_mode, b_factor, b_sub = database[n-1] + if b_mode = 's': + database[n-1] = b_type, 'i', a_factor, `i` + n_in_args = n_in_args - 1 + # + # Assign argument positions in the Python argument list + # + in_pos = [] + i_in = 0 + for i in range(len(database)): + a_type, a_mode, a_factor, a_sub = database[i] + if a_mode = 's': + in_pos.append(i_in) + i_in = i_in + 1 + else: + in_pos.append(-1) + # + # Get input arguments + # + for i in range(len(database)): + a_type, a_mode, a_factor, a_sub = database[i] + if a_mode = 'i': + # + # Implicit argument; + # a_factor is divisor if present, + # a_sub indicates which arg (`database index`) + # + j = eval(a_sub) + print '\tif', + print '(!geti' + a_type + 'arraysize(args,', + print `n_in_args` + ',', + print `in_pos[j]` + ',', + print '&arg' + `i+1` + '))' + print '\t\treturn NULL;' + if a_factor: + print '\targ' + `i+1`, + print '= arg' + `i+1`, + print '/', a_factor + ';' + elif a_mode = 's': + if a_sub: # Allocate memory for varsize array + print '\tif ((arg' + `i+1`, '=', + print 'NEW(' + a_type + ',', + if a_factor: print a_factor, '*', + print a_sub, ')) == NULL)' + print '\t\treturn err_nomem();' + print '\tif', + if a_factor or a_sub: # Get a fixed-size array array + print '(!geti' + a_type + 'array(args,', + print `n_in_args` + ',', + print `in_pos[i]` + ',', + if a_factor: print a_factor, + if a_factor and a_sub: print '*', + if a_sub: print a_sub, + print ', arg' + `i+1` + '))' + else: # Get a simple variable + print '(!geti' + a_type + 'arg(args,', + print `n_in_args` + ',', + print `in_pos[i]` + ',', + print '&arg' + `i+1` + '))' + print '\t\treturn NULL;' + # + # Begin of function call + # + if type <> 'void': + print '\tretval =', func + '(', + else: + print '\t' + func + '(', + # + # Argument list + # + for i in range(len(database)): + if i > 0: print ',', + a_type, a_mode, a_factor, a_sub = database[i] + if a_mode = 'r' and not a_factor: + print '&', + print 'arg' + `i+1`, + # + # End of function call + # + print ');' + # + # Free varsize arrays + # + for i in range(len(database)): + a_type, a_mode, a_factor, a_sub = database[i] + if a_mode = 's' and a_sub: + print '\tDEL(arg' + `i+1` + ');' + # + # Return + # + if n_out_args: + # + # Multiple return values -- construct a tuple + # + if type <> 'void': + n_out_args = n_out_args + 1 + if n_out_args = 1: + for i in range(len(database)): + a_type, a_mode, a_factor, a_sub = database[i] + if a_mode = 'r': + break + else: + raise arg_error, 'expected r arg not found' + print '\treturn', + print mkobject(a_type, 'arg' + `i+1`) + ';' + else: + print '\t{ object *v = newtupleobject(', + print n_out_args, ');' + print '\t if (v == NULL) return NULL;' + i_out = 0 + if type <> 'void': + print '\t settupleitem(v,', + print `i_out` + ',', + print mkobject(type, 'retval') + ');' + i_out = i_out + 1 + for i in range(len(database)): + a_type, a_mode, a_factor, a_sub = database[i] + if a_mode = 'r': + print '\t settupleitem(v,', + print `i_out` + ',', + s = mkobject(a_type, 'arg' + `i+1`) + print s + ');' + i_out = i_out + 1 + print '\t return v;' + print '\t}' + else: + # + # Simple function return + # Return None or return value + # + if type = 'void': + print '\tINCREF(None);' + print '\treturn None;' + else: + print '\treturn', mkobject(type, 'retval') + ';' + # + # Stub body closing brace + # + print '}' + + +# Subroutine to return a function call to mknewobject() +# +def mkobject(type, arg): + return 'mknew' + type + 'object(' + arg + ')' + + +# Input line number +lno = 0 + + +# Input is divided in two parts, separated by a line containing '%%'. +# -- literally copied to stdout +# -- stub definitions + +# Variable indicating the current input part. +# +part = 1 + +# Main loop over the input +# +while 1: + try: + line = raw_input() + except EOFError: + break + # + lno = lno+1 + words = string.split(line) + # + if part = 1: + # + # In part 1, copy everything literally + # except look for a line of just '%%' + # + if words = ['%%']: + part = part + 1 + else: + # + # Look for names of manually written + # stubs: a single percent followed by the name + # of the function in Python. + # The stub name is derived by prefixing 'gl_'. + # + if words and words[0][0] = '%': + func = words[0][1:] + if (not func) and words[1:]: + func = words[1] + if func: + functions.append(func) + else: + print line + elif not words: + pass # skip empty line + elif words[0] = '#include': + print line + elif words[0][:1] = '#': + pass # ignore comment + elif words[0] not in return_types: + err('Line', lno, ': bad return type :', words[0]) + elif len(words) < 2: + err('Line', lno, ': no funcname :', line) + else: + if len(words) % 2 <> 0: + err('Line', lno, ': odd argument list :', words[2:]) + else: + database = [] + try: + for i in range(2, len(words), 2): + x = checkarg(words[i], words[i+1]) + database.append(x) + print + print '/*', + for w in words: print w, + print '*/' + generate(words[0], words[1], database) + except arg_error, msg: + err('Line', lno, ':', msg) + + +print +print 'static struct methodlist gl_methods[] = {' +for func in functions: + print '\t{"' + func + '", gl_' + func + '},' +print '\t{NULL, NULL} /* Sentinel */' +print '};' +print +print 'initgl()' +print '{' +print '\tinitmodule("gl", gl_methods);' +print '}' diff --git a/src/cgensupport.c b/src/cgensupport.c new file mode 100644 index 0000000..91adb2a --- /dev/null +++ b/src/cgensupport.c @@ -0,0 +1,393 @@ +/*********************************************************** +Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +Netherlands. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* Functions used by cgen output */ + +#include + +#include "PROTO.h" +#include "object.h" +#include "intobject.h" +#include "floatobject.h" +#include "stringobject.h" +#include "tupleobject.h" +#include "listobject.h" +#include "methodobject.h" +#include "moduleobject.h" +#include "modsupport.h" +#include "import.h" +#include "cgensupport.h" +#include "errors.h" + + +/* Functions to construct return values */ + +object * +mknewcharobject(c) + int c; +{ + char ch[1]; + ch[0] = c; + return newsizedstringobject(ch, 1); +} + +/* Functions to extract arguments. + These needs to know the total number of arguments supplied, + since the argument list is a tuple only of there is more than + one argument. */ + +int +getiobjectarg(args, nargs, i, p_arg) + register object *args; + int nargs, i; + object **p_arg; +{ + if (nargs != 1) { + if (args == NULL || !is_tupleobject(args) || + nargs != gettuplesize(args) || + i < 0 || i >= nargs) { + return err_badarg(); + } + else { + args = gettupleitem(args, i); + } + } + if (args == NULL) { + return err_badarg(); + } + *p_arg = args; + return 1; +} + +int +getilongarg(args, nargs, i, p_arg) + register object *args; + int nargs, i; + long *p_arg; +{ + if (nargs != 1) { + if (args == NULL || !is_tupleobject(args) || + nargs != gettuplesize(args) || + i < 0 || i >= nargs) { + return err_badarg(); + } + args = gettupleitem(args, i); + } + if (args == NULL || !is_intobject(args)) { + return err_badarg(); + } + *p_arg = getintvalue(args); + return 1; +} + +int +getishortarg(args, nargs, i, p_arg) + register object *args; + int nargs, i; + short *p_arg; +{ + long x; + if (!getilongarg(args, nargs, i, &x)) + return 0; + *p_arg = x; + return 1; +} + +static int +extractdouble(v, p_arg) + register object *v; + double *p_arg; +{ + if (v == NULL) { + /* Fall through to error return at end of function */ + } + else if (is_floatobject(v)) { + *p_arg = GETFLOATVALUE((floatobject *)v); + return 1; + } + else if (is_intobject(v)) { + *p_arg = GETINTVALUE((intobject *)v); + return 1; + } + return err_badarg(); +} + +static int +extractfloat(v, p_arg) + register object *v; + float *p_arg; +{ + if (v == NULL) { + /* Fall through to error return at end of function */ + } + else if (is_floatobject(v)) { + *p_arg = GETFLOATVALUE((floatobject *)v); + return 1; + } + else if (is_intobject(v)) { + *p_arg = GETINTVALUE((intobject *)v); + return 1; + } + return err_badarg(); +} + +int +getifloatarg(args, nargs, i, p_arg) + register object *args; + int nargs, i; + float *p_arg; +{ + object *v; + float x; + if (!getiobjectarg(args, nargs, i, &v)) + return 0; + if (!extractfloat(v, &x)) + return 0; + *p_arg = x; + return 1; +} + +int +getistringarg(args, nargs, i, p_arg) + object *args; + int nargs, i; + string *p_arg; +{ + object *v; + if (!getiobjectarg(args, nargs, i, &v)) + return NULL; + if (!is_stringobject(v)) { + return err_badarg(); + } + *p_arg = getstringvalue(v); + return 1; +} + +int +getichararg(args, nargs, i, p_arg) + object *args; + int nargs, i; + char *p_arg; +{ + string x; + if (!getistringarg(args, nargs, i, &x)) + return 0; + if (x[0] == '\0' || x[1] != '\0') { + /* Not exactly one char */ + return err_badarg(); + } + *p_arg = x[0]; + return 1; +} + +int +getilongarraysize(args, nargs, i, p_arg) + object *args; + int nargs, i; + long *p_arg; +{ + object *v; + if (!getiobjectarg(args, nargs, i, &v)) + return 0; + if (is_tupleobject(v)) { + *p_arg = gettuplesize(v); + return 1; + } + if (is_listobject(v)) { + *p_arg = getlistsize(v); + return 1; + } + return err_badarg(); +} + +int +getishortarraysize(args, nargs, i, p_arg) + object *args; + int nargs, i; + short *p_arg; +{ + long x; + if (!getilongarraysize(args, nargs, i, &x)) + return 0; + *p_arg = x; + return 1; +} + +/* XXX The following four are too similar. Should share more code. */ + +int +getilongarray(args, nargs, i, n, p_arg) + object *args; + int nargs, i; + int n; + long *p_arg; /* [n] */ +{ + object *v, *w; + if (!getiobjectarg(args, nargs, i, &v)) + return 0; + if (is_tupleobject(v)) { + if (gettuplesize(v) != n) { + return err_badarg(); + } + for (i = 0; i < n; i++) { + w = gettupleitem(v, i); + if (!is_intobject(w)) { + return err_badarg(); + } + p_arg[i] = getintvalue(w); + } + return 1; + } + else if (is_listobject(v)) { + if (getlistsize(v) != n) { + return err_badarg(); + } + for (i = 0; i < n; i++) { + w = getlistitem(v, i); + if (!is_intobject(w)) { + return err_badarg(); + } + p_arg[i] = getintvalue(w); + } + return 1; + } + else { + return err_badarg(); + } +} + +int +getishortarray(args, nargs, i, n, p_arg) + object *args; + int nargs, i; + int n; + short *p_arg; /* [n] */ +{ + object *v, *w; + if (!getiobjectarg(args, nargs, i, &v)) + return 0; + if (is_tupleobject(v)) { + if (gettuplesize(v) != n) { + return err_badarg(); + } + for (i = 0; i < n; i++) { + w = gettupleitem(v, i); + if (!is_intobject(w)) { + return err_badarg(); + } + p_arg[i] = getintvalue(w); + } + return 1; + } + else if (is_listobject(v)) { + if (getlistsize(v) != n) { + return err_badarg(); + } + for (i = 0; i < n; i++) { + w = getlistitem(v, i); + if (!is_intobject(w)) { + return err_badarg(); + } + p_arg[i] = getintvalue(w); + } + return 1; + } + else { + return err_badarg(); + } +} + +int +getidoublearray(args, nargs, i, n, p_arg) + object *args; + int nargs, i; + int n; + double *p_arg; /* [n] */ +{ + object *v, *w; + if (!getiobjectarg(args, nargs, i, &v)) + return 0; + if (is_tupleobject(v)) { + if (gettuplesize(v) != n) { + return err_badarg(); + } + for (i = 0; i < n; i++) { + w = gettupleitem(v, i); + if (!extractdouble(w, &p_arg[i])) + return 0; + } + return 1; + } + else if (is_listobject(v)) { + if (getlistsize(v) != n) { + return err_badarg(); + } + for (i = 0; i < n; i++) { + w = getlistitem(v, i); + if (!extractdouble(w, &p_arg[i])) + return 0; + } + return 1; + } + else { + return err_badarg(); + } +} + +int +getifloatarray(args, nargs, i, n, p_arg) + object *args; + int nargs, i; + int n; + float *p_arg; /* [n] */ +{ + object *v, *w; + if (!getiobjectarg(args, nargs, i, &v)) + return 0; + if (is_tupleobject(v)) { + if (gettuplesize(v) != n) { + return err_badarg(); + } + for (i = 0; i < n; i++) { + w = gettupleitem(v, i); + if (!extractfloat(w, &p_arg[i])) + return 0; + } + return 1; + } + else if (is_listobject(v)) { + if (getlistsize(v) != n) { + return err_badarg(); + } + for (i = 0; i < n; i++) { + w = getlistitem(v, i); + if (!extractfloat(w, &p_arg[i])) + return 0; + } + return 1; + } + else { + return err_badarg(); + } +} diff --git a/src/cgensupport.h b/src/cgensupport.h new file mode 100644 index 0000000..a056f5d --- /dev/null +++ b/src/cgensupport.h @@ -0,0 +1,39 @@ +/*********************************************************** +Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +Netherlands. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* Definitions used by cgen output */ + +typedef char *string; + +#define mknewlongobject(x) newintobject(x) +#define mknewshortobject(x) newintobject((long)x) +#define mknewfloatobject(x) newfloatobject(x) + +extern object *mknewcharobject PROTO((int c)); + +extern int getiobjectarg PROTO((object *args, int nargs, int i, object **p_a)); +extern int getilongarg PROTO((object *args, int nargs, int i, long *p_a)); +extern int getishortarg PROTO((object *args, int nargs, int i, short *p_a)); +extern int getifloatarg PROTO((object *args, int nargs, int i, float *p_a)); +extern int getistringarg PROTO((object *args, int nargs, int i, string *p_a)); diff --git a/src/classobject.c b/src/classobject.c new file mode 100644 index 0000000..fc32889 --- /dev/null +++ b/src/classobject.c @@ -0,0 +1,298 @@ +/*********************************************************** +Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +Netherlands. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* Class object implementation */ + +#include "allobjects.h" + +#include "structmember.h" + +typedef struct { + OB_HEAD + object *cl_bases; /* A tuple */ + object *cl_methods; /* A dictionary */ +} classobject; + +object * +newclassobject(bases, methods) + object *bases; /* NULL or tuple of classobjects! */ + object *methods; +{ + classobject *op; + op = NEWOBJ(classobject, &Classtype); + if (op == NULL) + return NULL; + if (bases != NULL) + INCREF(bases); + op->cl_bases = bases; + INCREF(methods); + op->cl_methods = methods; + return (object *) op; +} + +/* Class methods */ + +static void +class_dealloc(op) + classobject *op; +{ + int i; + if (op->cl_bases != NULL) + DECREF(op->cl_bases); + DECREF(op->cl_methods); + free((ANY *)op); +} + +static object * +class_getattr(op, name) + register classobject *op; + register char *name; +{ + register object *v; + v = dictlookup(op->cl_methods, name); + if (v != NULL) { + INCREF(v); + return v; + } + if (op->cl_bases != NULL) { + int n = gettuplesize(op->cl_bases); + int i; + for (i = 0; i < n; i++) { + v = class_getattr(gettupleitem(op->cl_bases, i), name); + if (v != NULL) + return v; + err_clear(); + } + } + err_setstr(NameError, name); + return NULL; +} + +typeobject Classtype = { + OB_HEAD_INIT(&Typetype) + 0, + "class", + sizeof(classobject), + 0, + class_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + class_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ +}; + + +/* We're not done yet: next, we define class member objects... */ + +typedef struct { + OB_HEAD + classobject *cm_class; /* The class object */ + object *cm_attr; /* A dictionary */ +} classmemberobject; + +object * +newclassmemberobject(class) + register object *class; +{ + register classmemberobject *cm; + if (!is_classobject(class)) { + err_badcall(); + return NULL; + } + cm = NEWOBJ(classmemberobject, &Classmembertype); + if (cm == NULL) + return NULL; + INCREF(class); + cm->cm_class = (classobject *)class; + cm->cm_attr = newdictobject(); + if (cm->cm_attr == NULL) { + DECREF(cm); + return NULL; + } + return (object *)cm; +} + +/* Class member methods */ + +static void +classmember_dealloc(cm) + register classmemberobject *cm; +{ + DECREF(cm->cm_class); + if (cm->cm_attr != NULL) + DECREF(cm->cm_attr); + free((ANY *)cm); +} + +static object * +classmember_getattr(cm, name) + register classmemberobject *cm; + register char *name; +{ + register object *v = dictlookup(cm->cm_attr, name); + if (v != NULL) { + INCREF(v); + return v; + } + v = class_getattr(cm->cm_class, name); + if (v == NULL) + return v; /* class_getattr() has set the error */ + if (is_funcobject(v)) { + object *w = newclassmethodobject(v, (object *)cm); + DECREF(v); + return w; + } + DECREF(v); + err_setstr(NameError, name); + return NULL; +} + +static int +classmember_setattr(cm, name, v) + classmemberobject *cm; + char *name; + object *v; +{ + if (v == NULL) + return dictremove(cm->cm_attr, name); + else + return dictinsert(cm->cm_attr, name, v); +} + +typeobject Classmembertype = { + OB_HEAD_INIT(&Typetype) + 0, + "class member", + sizeof(classmemberobject), + 0, + classmember_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + classmember_getattr, /*tp_getattr*/ + classmember_setattr, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ +}; + + +/* And finally, here are class method objects */ +/* (Really methods of class members) */ + +typedef struct { + OB_HEAD + object *cm_func; /* The method function */ + object *cm_self; /* The object to which this applies */ +} classmethodobject; + +object * +newclassmethodobject(func, self) + object *func; + object *self; +{ + register classmethodobject *cm; + if (!is_funcobject(func)) { + err_badcall(); + return NULL; + } + cm = NEWOBJ(classmethodobject, &Classmethodtype); + if (cm == NULL) + return NULL; + INCREF(func); + cm->cm_func = func; + INCREF(self); + cm->cm_self = self; + return (object *)cm; +} + +object * +classmethodgetfunc(cm) + register object *cm; +{ + if (!is_classmethodobject(cm)) { + err_badcall(); + return NULL; + } + return ((classmethodobject *)cm)->cm_func; +} + +object * +classmethodgetself(cm) + register object *cm; +{ + if (!is_classmethodobject(cm)) { + err_badcall(); + return NULL; + } + return ((classmethodobject *)cm)->cm_self; +} + +/* Class method methods */ + +#define OFF(x) offsetof(classmethodobject, x) + +static struct memberlist classmethod_memberlist[] = { + {"cm_func", T_OBJECT, OFF(cm_func)}, + {"cm_self", T_OBJECT, OFF(cm_self)}, + {NULL} /* Sentinel */ +}; + +static object * +classmethod_getattr(cm, name) + register classmethodobject *cm; + char *name; +{ + return getmember((char *)cm, classmethod_memberlist, name); +} + +static void +classmethod_dealloc(cm) + register classmethodobject *cm; +{ + DECREF(cm->cm_func); + DECREF(cm->cm_self); + free((ANY *)cm); +} + +typeobject Classmethodtype = { + OB_HEAD_INIT(&Typetype) + 0, + "class method", + sizeof(classmethodobject), + 0, + classmethod_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + classmethod_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ +}; diff --git a/src/classobject.h b/src/classobject.h new file mode 100644 index 0000000..49db837 --- /dev/null +++ b/src/classobject.h @@ -0,0 +1,44 @@ +/*********************************************************** +Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +Netherlands. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* Class object interface */ + +/* +Classes are really hacked in at the last moment. +It should be possible to use other object types as base classes, +but currently it isn't. We'll see if we can fix that later, sigh... +*/ + +extern typeobject Classtype, Classmembertype, Classmethodtype; + +#define is_classobject(op) ((op)->ob_type == &Classtype) +#define is_classmemberobject(op) ((op)->ob_type == &Classmembertype) +#define is_classmethodobject(op) ((op)->ob_type == &Classmethodtype) + +extern object *newclassobject PROTO((object *, object *)); +extern object *newclassmemberobject PROTO((object *)); +extern object *newclassmethodobject PROTO((object *, object *)); + +extern object *classmethodgetfunc PROTO((object *)); +extern object *classmethodgetself PROTO((object *)); diff --git a/src/compile.c b/src/compile.c new file mode 100644 index 0000000..7904dba --- /dev/null +++ b/src/compile.c @@ -0,0 +1,1772 @@ +/*********************************************************** +Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +Netherlands. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* Compile an expression node to intermediate code */ + +/* XXX TO DO: + XXX Compute maximum needed stack sizes while compiling + XXX Generate simple jump for break/return outside 'try...finally' + XXX Include function name in code (and module names?) +*/ + +#include "allobjects.h" + +#include "node.h" +#include "token.h" +#include "graminit.h" +#include "compile.h" +#include "opcode.h" +#include "structmember.h" + +#include + +#define OFF(x) offsetof(codeobject, x) + +static struct memberlist code_memberlist[] = { + {"co_code", T_OBJECT, OFF(co_code)}, + {"co_consts", T_OBJECT, OFF(co_consts)}, + {"co_names", T_OBJECT, OFF(co_names)}, + {"co_filename", T_OBJECT, OFF(co_filename)}, + {NULL} /* Sentinel */ +}; + +static object * +code_getattr(co, name) + codeobject *co; + char *name; +{ + return getmember((char *)co, code_memberlist, name); +} + +static void +code_dealloc(co) + codeobject *co; +{ + XDECREF(co->co_code); + XDECREF(co->co_consts); + XDECREF(co->co_names); + XDECREF(co->co_filename); + DEL(co); +} + +typeobject Codetype = { + OB_HEAD_INIT(&Typetype) + 0, + "code", + sizeof(codeobject), + 0, + code_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + code_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ +}; + +static codeobject *newcodeobject PROTO((object *, object *, object *, char *)); + +static codeobject * +newcodeobject(code, consts, names, filename) + object *code; + object *consts; + object *names; + char *filename; +{ + codeobject *co; + int i; + /* Check argument types */ + if (code == NULL || !is_stringobject(code) || + consts == NULL || !is_listobject(consts) || + names == NULL || !is_listobject(names)) { + err_badcall(); + return NULL; + } + /* Make sure the list of names contains only strings */ + for (i = getlistsize(names); --i >= 0; ) { + object *v = getlistitem(names, i); + if (v == NULL || !is_stringobject(v)) { + err_badcall(); + return NULL; + } + } + co = NEWOBJ(codeobject, &Codetype); + if (co != NULL) { + INCREF(code); + co->co_code = (stringobject *)code; + INCREF(consts); + co->co_consts = consts; + INCREF(names); + co->co_names = names; + if ((co->co_filename = newstringobject(filename)) == NULL) { + DECREF(co); + co = NULL; + } + } + return co; +} + + +/* Data structure used internally */ +struct compiling { + object *c_code; /* string */ + object *c_consts; /* list of objects */ + object *c_names; /* list of strings (names) */ + int c_nexti; /* index into c_code */ + int c_errors; /* counts errors occurred */ + int c_infunction; /* set when compiling a function */ + int c_loops; /* counts nested loops */ + char *c_filename; /* filename of current node */ +}; + +/* Prototypes */ +static int com_init PROTO((struct compiling *, char *)); +static void com_free PROTO((struct compiling *)); +static void com_done PROTO((struct compiling *)); +static void com_node PROTO((struct compiling *, struct _node *)); +static void com_addbyte PROTO((struct compiling *, int)); +static void com_addint PROTO((struct compiling *, int)); +static void com_addoparg PROTO((struct compiling *, int, int)); +static void com_addfwref PROTO((struct compiling *, int, int *)); +static void com_backpatch PROTO((struct compiling *, int)); +static int com_add PROTO((struct compiling *, object *, object *)); +static int com_addconst PROTO((struct compiling *, object *)); +static int com_addname PROTO((struct compiling *, object *)); +static void com_addopname PROTO((struct compiling *, int, node *)); + +static int +com_init(c, filename) + struct compiling *c; + char *filename; +{ + if ((c->c_code = newsizedstringobject((char *)NULL, 0)) == NULL) + goto fail_3; + if ((c->c_consts = newlistobject(0)) == NULL) + goto fail_2; + if ((c->c_names = newlistobject(0)) == NULL) + goto fail_1; + c->c_nexti = 0; + c->c_errors = 0; + c->c_infunction = 0; + c->c_loops = 0; + c->c_filename = filename; + return 1; + + fail_1: + DECREF(c->c_consts); + fail_2: + DECREF(c->c_code); + fail_3: + return 0; +} + +static void +com_free(c) + struct compiling *c; +{ + XDECREF(c->c_code); + XDECREF(c->c_consts); + XDECREF(c->c_names); +} + +static void +com_done(c) + struct compiling *c; +{ + if (c->c_code != NULL) + resizestring(&c->c_code, c->c_nexti); +} + +static void +com_addbyte(c, byte) + struct compiling *c; + int byte; +{ + int len; + if (byte < 0 || byte > 255) { + fprintf(stderr, "XXX compiling bad byte: %d\n", byte); + abort(); + err_setstr(SystemError, "com_addbyte: byte out of range"); + c->c_errors++; + } + if (c->c_code == NULL) + return; + len = getstringsize(c->c_code); + if (c->c_nexti >= len) { + if (resizestring(&c->c_code, len+1000) != 0) { + c->c_errors++; + return; + } + } + getstringvalue(c->c_code)[c->c_nexti++] = byte; +} + +static void +com_addint(c, x) + struct compiling *c; + int x; +{ + com_addbyte(c, x & 0xff); + com_addbyte(c, x >> 8); /* XXX x should be positive */ +} + +static void +com_addoparg(c, op, arg) + struct compiling *c; + int op; + int arg; +{ + com_addbyte(c, op); + com_addint(c, arg); +} + +static void +com_addfwref(c, op, p_anchor) + struct compiling *c; + int op; + int *p_anchor; +{ + /* Compile a forward reference for backpatching */ + int here; + int anchor; + com_addbyte(c, op); + here = c->c_nexti; + anchor = *p_anchor; + *p_anchor = here; + com_addint(c, anchor == 0 ? 0 : here - anchor); +} + +static void +com_backpatch(c, anchor) + struct compiling *c; + int anchor; /* Must be nonzero */ +{ + unsigned char *code = (unsigned char *) getstringvalue(c->c_code); + int target = c->c_nexti; + int lastanchor = 0; + int dist; + int prev; + for (;;) { + /* Make the JUMP instruction at anchor point to target */ + prev = code[anchor] + (code[anchor+1] << 8); + dist = target - (anchor+2); + code[anchor] = dist & 0xff; + code[anchor+1] = dist >> 8; + if (!prev) + break; + lastanchor = anchor; + anchor -= prev; + } +} + +/* Handle constants and names uniformly */ + +static int +com_add(c, list, v) + struct compiling *c; + object *list; + object *v; +{ + int n = getlistsize(list); + int i; + for (i = n; --i >= 0; ) { + object *w = getlistitem(list, i); + if (cmpobject(v, w) == 0) + return i; + } + if (addlistitem(list, v) != 0) + c->c_errors++; + return n; +} + +static int +com_addconst(c, v) + struct compiling *c; + object *v; +{ + return com_add(c, c->c_consts, v); +} + +static int +com_addname(c, v) + struct compiling *c; + object *v; +{ + return com_add(c, c->c_names, v); +} + +static void +com_addopname(c, op, n) + struct compiling *c; + int op; + node *n; +{ + object *v; + int i; + char *name; + if (TYPE(n) == STAR) + name = "*"; + else { + REQ(n, NAME); + name = STR(n); + } + if ((v = newstringobject(name)) == NULL) { + c->c_errors++; + i = 255; + } + else { + i = com_addname(c, v); + DECREF(v); + } + com_addoparg(c, op, i); +} + +static object * +parsenumber(s) + char *s; +{ + extern long strtol(); + extern double atof(); + char *end = s; + long x; + x = strtol(s, &end, 0); + if (*end == '\0') + return newintobject(x); + if (*end == '.' || *end == 'e' || *end == 'E') + return newfloatobject(atof(s)); + err_setstr(RuntimeError, "bad number syntax"); + return NULL; +} + +static object * +parsestr(s) + char *s; +{ + object *v; + int len; + char *buf; + char *p; + int c; + if (*s != '\'') { + err_badcall(); + return NULL; + } + s++; + len = strlen(s); + if (s[--len] != '\'') { + err_badcall(); + return NULL; + } + if (strchr(s, '\\') == NULL) + return newsizedstringobject(s, len); + v = newsizedstringobject((char *)NULL, len); + p = buf = getstringvalue(v); + while (*s != '\0' && *s != '\'') { + if (*s != '\\') { + *p++ = *s++; + continue; + } + s++; + switch (*s++) { + /* XXX This assumes ASCII! */ + case '\\': *p++ = '\\'; break; + case '\'': *p++ = '\''; break; + case 'b': *p++ = '\b'; break; + case 'f': *p++ = '\014'; break; /* FF */ + case 't': *p++ = '\t'; break; + case 'n': *p++ = '\n'; break; + case 'r': *p++ = '\r'; break; + case 'v': *p++ = '\013'; break; /* VT */ + case 'E': *p++ = '\033'; break; /* ESC, not C */ + case 'a': *p++ = '\007'; break; /* BEL, not classic C */ + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + c = s[-1] - '0'; + if ('0' <= *s && *s <= '7') { + c = (c<<3) + *s++ - '0'; + if ('0' <= *s && *s <= '7') + c = (c<<3) + *s++ - '0'; + } + *p++ = c; + break; + case 'x': + if (isxdigit(*s)) { + sscanf(s, "%x", &c); + *p++ = c; + do { + s++; + } while (isxdigit(*s)); + break; + } + /* FALLTHROUGH */ + default: *p++ = '\\'; *p++ = s[-1]; break; + } + } + resizestring(&v, (int)(p - buf)); + return v; +} + +static void +com_list_constructor(c, n) + struct compiling *c; + node *n; +{ + int len; + int i; + object *v, *w; + if (TYPE(n) != testlist) + REQ(n, exprlist); + /* exprlist: expr (',' expr)* [',']; likewise for testlist */ + len = (NCH(n) + 1) / 2; + for (i = 0; i < NCH(n); i += 2) + com_node(c, CHILD(n, i)); + com_addoparg(c, BUILD_LIST, len); +} + +static void +com_atom(c, n) + struct compiling *c; + node *n; +{ + node *ch; + object *v; + int i; + REQ(n, atom); + ch = CHILD(n, 0); + switch (TYPE(ch)) { + case LPAR: + if (TYPE(CHILD(n, 1)) == RPAR) + com_addoparg(c, BUILD_TUPLE, 0); + else + com_node(c, CHILD(n, 1)); + break; + case LSQB: + if (TYPE(CHILD(n, 1)) == RSQB) + com_addoparg(c, BUILD_LIST, 0); + else + com_list_constructor(c, CHILD(n, 1)); + break; + case LBRACE: + com_addoparg(c, BUILD_MAP, 0); + break; + case BACKQUOTE: + com_node(c, CHILD(n, 1)); + com_addbyte(c, UNARY_CONVERT); + break; + case NUMBER: + if ((v = parsenumber(STR(ch))) == NULL) { + c->c_errors++; + i = 255; + } + else { + i = com_addconst(c, v); + DECREF(v); + } + com_addoparg(c, LOAD_CONST, i); + break; + case STRING: + if ((v = parsestr(STR(ch))) == NULL) { + c->c_errors++; + i = 255; + } + else { + i = com_addconst(c, v); + DECREF(v); + } + com_addoparg(c, LOAD_CONST, i); + break; + case NAME: + com_addopname(c, LOAD_NAME, ch); + break; + default: + fprintf(stderr, "node type %d\n", TYPE(ch)); + err_setstr(SystemError, "com_atom: unexpected node type"); + c->c_errors++; + } +} + +static void +com_slice(c, n, op) + struct compiling *c; + node *n; + int op; +{ + if (NCH(n) == 1) { + com_addbyte(c, op); + } + else if (NCH(n) == 2) { + if (TYPE(CHILD(n, 0)) != COLON) { + com_node(c, CHILD(n, 0)); + com_addbyte(c, op+1); + } + else { + com_node(c, CHILD(n, 1)); + com_addbyte(c, op+2); + } + } + else { + com_node(c, CHILD(n, 0)); + com_node(c, CHILD(n, 2)); + com_addbyte(c, op+3); + } +} + +static void +com_apply_subscript(c, n) + struct compiling *c; + node *n; +{ + REQ(n, subscript); + if (NCH(n) == 1 && TYPE(CHILD(n, 0)) != COLON) { + /* It's a single subscript */ + com_node(c, CHILD(n, 0)); + com_addbyte(c, BINARY_SUBSCR); + } + else { + /* It's a slice: [expr] ':' [expr] */ + com_slice(c, n, SLICE); + } +} + +static void +com_call_function(c, n) + struct compiling *c; + node *n; /* EITHER testlist OR ')' */ +{ + if (TYPE(n) == RPAR) { + com_addbyte(c, UNARY_CALL); + } + else { + com_node(c, n); + com_addbyte(c, BINARY_CALL); + } +} + +static void +com_select_member(c, n) + struct compiling *c; + node *n; +{ + com_addopname(c, LOAD_ATTR, n); +} + +static void +com_apply_trailer(c, n) + struct compiling *c; + node *n; +{ + REQ(n, trailer); + switch (TYPE(CHILD(n, 0))) { + case LPAR: + com_call_function(c, CHILD(n, 1)); + break; + case DOT: + com_select_member(c, CHILD(n, 1)); + break; + case LSQB: + com_apply_subscript(c, CHILD(n, 1)); + break; + default: + err_setstr(SystemError, + "com_apply_trailer: unknown trailer type"); + c->c_errors++; + } +} + +static void +com_factor(c, n) + struct compiling *c; + node *n; +{ + int i; + REQ(n, factor); + if (TYPE(CHILD(n, 0)) == PLUS) { + com_factor(c, CHILD(n, 1)); + com_addbyte(c, UNARY_POSITIVE); + } + else if (TYPE(CHILD(n, 0)) == MINUS) { + com_factor(c, CHILD(n, 1)); + com_addbyte(c, UNARY_NEGATIVE); + } + else { + com_atom(c, CHILD(n, 0)); + for (i = 1; i < NCH(n); i++) + com_apply_trailer(c, CHILD(n, i)); + } +} + +static void +com_term(c, n) + struct compiling *c; + node *n; +{ + int i; + int op; + REQ(n, term); + com_factor(c, CHILD(n, 0)); + for (i = 2; i < NCH(n); i += 2) { + com_factor(c, CHILD(n, i)); + switch (TYPE(CHILD(n, i-1))) { + case STAR: + op = BINARY_MULTIPLY; + break; + case SLASH: + op = BINARY_DIVIDE; + break; + case PERCENT: + op = BINARY_MODULO; + break; + default: + err_setstr(SystemError, + "com_term: term operator not *, / or %"); + c->c_errors++; + op = 255; + } + com_addbyte(c, op); + } +} + +static void +com_expr(c, n) + struct compiling *c; + node *n; +{ + int i; + int op; + REQ(n, expr); + com_term(c, CHILD(n, 0)); + for (i = 2; i < NCH(n); i += 2) { + com_term(c, CHILD(n, i)); + switch (TYPE(CHILD(n, i-1))) { + case PLUS: + op = BINARY_ADD; + break; + case MINUS: + op = BINARY_SUBTRACT; + break; + default: + err_setstr(SystemError, + "com_expr: expr operator not + or -"); + c->c_errors++; + op = 255; + } + com_addbyte(c, op); + } +} + +static enum cmp_op +cmp_type(n) + node *n; +{ + REQ(n, comp_op); + /* comp_op: '<' | '>' | '=' | '>' '=' | '<' '=' | '<' '>' + | 'in' | 'not' 'in' | 'is' | 'is' not' */ + if (NCH(n) == 1) { + n = CHILD(n, 0); + switch (TYPE(n)) { + case LESS: return LT; + case GREATER: return GT; + case EQUAL: return EQ; + case NAME: if (strcmp(STR(n), "in") == 0) return IN; + if (strcmp(STR(n), "is") == 0) return IS; + } + } + else if (NCH(n) == 2) { + int t2 = TYPE(CHILD(n, 1)); + switch (TYPE(CHILD(n, 0))) { + case LESS: if (t2 == EQUAL) return LE; + if (t2 == GREATER) return NE; + break; + case GREATER: if (t2 == EQUAL) return GE; + break; + case NAME: if (strcmp(STR(CHILD(n, 1)), "in") == 0) + return NOT_IN; + if (strcmp(STR(CHILD(n, 0)), "is") == 0) + return IS_NOT; + } + } + return BAD; +} + +static void +com_comparison(c, n) + struct compiling *c; + node *n; +{ + int i; + enum cmp_op op; + int anchor; + REQ(n, comparison); /* comparison: expr (comp_op expr)* */ + com_expr(c, CHILD(n, 0)); + if (NCH(n) == 1) + return; + + /**************************************************************** + The following code is generated for all but the last + comparison in a chain: + + label: on stack: opcode: jump to: + + a + a, b DUP_TOP + a, b, b ROT_THREE + b, a, b COMPARE_OP + b, 0-or-1 JUMP_IF_FALSE L1 + b, 1 POP_TOP + b + + We are now ready to repeat this sequence for the next + comparison in the chain. + + For the last we generate: + + b + b, c COMPARE_OP + 0-or-1 + + If there were any jumps to L1 (i.e., there was more than one + comparison), we generate: + + 0-or-1 JUMP_FORWARD L2 + L1: b, 0 ROT_TWO + 0, b POP_TOP + 0 + L2: + ****************************************************************/ + + anchor = 0; + + for (i = 2; i < NCH(n); i += 2) { + com_expr(c, CHILD(n, i)); + if (i+2 < NCH(n)) { + com_addbyte(c, DUP_TOP); + com_addbyte(c, ROT_THREE); + } + op = cmp_type(CHILD(n, i-1)); + if (op == BAD) { + err_setstr(SystemError, + "com_comparison: unknown comparison op"); + c->c_errors++; + } + com_addoparg(c, COMPARE_OP, op); + if (i+2 < NCH(n)) { + com_addfwref(c, JUMP_IF_FALSE, &anchor); + com_addbyte(c, POP_TOP); + } + } + + if (anchor) { + int anchor2 = 0; + com_addfwref(c, JUMP_FORWARD, &anchor2); + com_backpatch(c, anchor); + com_addbyte(c, ROT_TWO); + com_addbyte(c, POP_TOP); + com_backpatch(c, anchor2); + } +} + +static void +com_not_test(c, n) + struct compiling *c; + node *n; +{ + REQ(n, not_test); /* 'not' not_test | comparison */ + if (NCH(n) == 1) { + com_comparison(c, CHILD(n, 0)); + } + else { + com_not_test(c, CHILD(n, 1)); + com_addbyte(c, UNARY_NOT); + } +} + +static void +com_and_test(c, n) + struct compiling *c; + node *n; +{ + int i; + int anchor; + REQ(n, and_test); /* not_test ('and' not_test)* */ + anchor = 0; + i = 0; + for (;;) { + com_not_test(c, CHILD(n, i)); + if ((i += 2) >= NCH(n)) + break; + com_addfwref(c, JUMP_IF_FALSE, &anchor); + com_addbyte(c, POP_TOP); + } + if (anchor) + com_backpatch(c, anchor); +} + +static void +com_test(c, n) + struct compiling *c; + node *n; +{ + int i; + int anchor; + REQ(n, test); /* and_test ('and' and_test)* */ + anchor = 0; + i = 0; + for (;;) { + com_and_test(c, CHILD(n, i)); + if ((i += 2) >= NCH(n)) + break; + com_addfwref(c, JUMP_IF_TRUE, &anchor); + com_addbyte(c, POP_TOP); + } + if (anchor) + com_backpatch(c, anchor); +} + +static void +com_list(c, n) + struct compiling *c; + node *n; +{ + /* exprlist: expr (',' expr)* [',']; likewise for testlist */ + if (NCH(n) == 1) { + com_node(c, CHILD(n, 0)); + } + else { + int i; + int len; + len = (NCH(n) + 1) / 2; + for (i = 0; i < NCH(n); i += 2) + com_node(c, CHILD(n, i)); + com_addoparg(c, BUILD_TUPLE, len); + } +} + + +/* Begin of assignment compilation */ + +static void com_assign_name PROTO((struct compiling *, node *, int)); +static void com_assign PROTO((struct compiling *, node *, int)); + +static void +com_assign_attr(c, n, assigning) + struct compiling *c; + node *n; + int assigning; +{ + com_addopname(c, assigning ? STORE_ATTR : DELETE_ATTR, n); +} + +static void +com_assign_slice(c, n, assigning) + struct compiling *c; + node *n; + int assigning; +{ + com_slice(c, n, assigning ? STORE_SLICE : DELETE_SLICE); +} + +static void +com_assign_subscript(c, n, assigning) + struct compiling *c; + node *n; + int assigning; +{ + com_node(c, n); + com_addbyte(c, assigning ? STORE_SUBSCR : DELETE_SUBSCR); +} + +static void +com_assign_trailer(c, n, assigning) + struct compiling *c; + node *n; + int assigning; +{ + char *name; + REQ(n, trailer); + switch (TYPE(CHILD(n, 0))) { + case LPAR: /* '(' [exprlist] ')' */ + err_setstr(TypeError, "can't assign to function call"); + c->c_errors++; + break; + case DOT: /* '.' NAME */ + com_assign_attr(c, CHILD(n, 1), assigning); + break; + case LSQB: /* '[' subscript ']' */ + n = CHILD(n, 1); + REQ(n, subscript); /* subscript: expr | [expr] ':' [expr] */ + if (NCH(n) > 1 || TYPE(CHILD(n, 0)) == COLON) + com_assign_slice(c, n, assigning); + else + com_assign_subscript(c, CHILD(n, 0), assigning); + break; + default: + err_setstr(TypeError, "unknown trailer type"); + c->c_errors++; + } +} + +static void +com_assign_tuple(c, n, assigning) + struct compiling *c; + node *n; + int assigning; +{ + int i; + if (TYPE(n) != testlist) + REQ(n, exprlist); + if (assigning) + com_addoparg(c, UNPACK_TUPLE, (NCH(n)+1)/2); + for (i = 0; i < NCH(n); i += 2) + com_assign(c, CHILD(n, i), assigning); +} + +static void +com_assign_list(c, n, assigning) + struct compiling *c; + node *n; + int assigning; +{ + int i; + if (assigning) + com_addoparg(c, UNPACK_LIST, (NCH(n)+1)/2); + for (i = 0; i < NCH(n); i += 2) + com_assign(c, CHILD(n, i), assigning); +} + +static void +com_assign_name(c, n, assigning) + struct compiling *c; + node *n; + int assigning; +{ + REQ(n, NAME); + com_addopname(c, assigning ? STORE_NAME : DELETE_NAME, n); +} + +static void +com_assign(c, n, assigning) + struct compiling *c; + node *n; + int assigning; +{ + /* Loop to avoid trivial recursion */ + for (;;) { + switch (TYPE(n)) { + + case exprlist: + case testlist: + if (NCH(n) > 1) { + com_assign_tuple(c, n, assigning); + return; + } + n = CHILD(n, 0); + break; + + case test: + case and_test: + case not_test: + if (NCH(n) > 1) { + err_setstr(TypeError, + "can't assign to operator"); + c->c_errors++; + return; + } + n = CHILD(n, 0); + break; + + case comparison: + if (NCH(n) > 1) { + err_setstr(TypeError, + "can't assign to operator"); + c->c_errors++; + return; + } + n = CHILD(n, 0); + break; + + case expr: + if (NCH(n) > 1) { + err_setstr(TypeError, + "can't assign to operator"); + c->c_errors++; + return; + } + n = CHILD(n, 0); + break; + + case term: + if (NCH(n) > 1) { + err_setstr(TypeError, + "can't assign to operator"); + c->c_errors++; + return; + } + n = CHILD(n, 0); + break; + + case factor: /* ('+'|'-') factor | atom trailer* */ + if (TYPE(CHILD(n, 0)) != atom) { /* '+' | '-' */ + err_setstr(TypeError, + "can't assign to operator"); + c->c_errors++; + return; + } + if (NCH(n) > 1) { /* trailer present */ + int i; + com_node(c, CHILD(n, 0)); + for (i = 1; i+1 < NCH(n); i++) { + com_apply_trailer(c, CHILD(n, i)); + } /* NB i is still alive */ + com_assign_trailer(c, + CHILD(n, i), assigning); + return; + } + n = CHILD(n, 0); + break; + + case atom: + switch (TYPE(CHILD(n, 0))) { + case LPAR: + n = CHILD(n, 1); + if (TYPE(n) == RPAR) { + /* XXX Should allow () = () ??? */ + err_setstr(TypeError, + "can't assign to ()"); + c->c_errors++; + return; + } + break; + case LSQB: + n = CHILD(n, 1); + if (TYPE(n) == RSQB) { + err_setstr(TypeError, + "can't assign to []"); + c->c_errors++; + return; + } + com_assign_list(c, n, assigning); + return; + case NAME: + com_assign_name(c, CHILD(n, 0), assigning); + return; + default: + err_setstr(TypeError, + "can't assign to constant"); + c->c_errors++; + return; + } + break; + + default: + fprintf(stderr, "node type %d\n", TYPE(n)); + err_setstr(SystemError, "com_assign: bad node"); + c->c_errors++; + return; + + } + } +} + +static void +com_expr_stmt(c, n) + struct compiling *c; + node *n; +{ + REQ(n, expr_stmt); /* exprlist ('=' exprlist)* NEWLINE */ + com_node(c, CHILD(n, NCH(n)-2)); + if (NCH(n) == 2) { + com_addbyte(c, PRINT_EXPR); + } + else { + int i; + for (i = 0; i < NCH(n)-3; i+=2) { + if (i+2 < NCH(n)-3) + com_addbyte(c, DUP_TOP); + com_assign(c, CHILD(n, i), 1/*assign*/); + } + } +} + +static void +com_print_stmt(c, n) + struct compiling *c; + node *n; +{ + int i; + REQ(n, print_stmt); /* 'print' (test ',')* [test] NEWLINE */ + for (i = 1; i+1 < NCH(n); i += 2) { + com_node(c, CHILD(n, i)); + com_addbyte(c, PRINT_ITEM); + } + if (TYPE(CHILD(n, NCH(n)-2)) != COMMA) + com_addbyte(c, PRINT_NEWLINE); + /* XXX Alternatively, LOAD_CONST '\n' and then PRINT_ITEM */ +} + +static void +com_return_stmt(c, n) + struct compiling *c; + node *n; +{ + REQ(n, return_stmt); /* 'return' [testlist] NEWLINE */ + if (!c->c_infunction) { + err_setstr(TypeError, "'return' outside function"); + c->c_errors++; + } + if (NCH(n) == 2) + com_addoparg(c, LOAD_CONST, com_addconst(c, None)); + else + com_node(c, CHILD(n, 1)); + com_addbyte(c, RETURN_VALUE); +} + +static void +com_raise_stmt(c, n) + struct compiling *c; + node *n; +{ + REQ(n, raise_stmt); /* 'raise' expr [',' expr] NEWLINE */ + com_node(c, CHILD(n, 1)); + if (NCH(n) > 3) + com_node(c, CHILD(n, 3)); + else + com_addoparg(c, LOAD_CONST, com_addconst(c, None)); + com_addbyte(c, RAISE_EXCEPTION); +} + +static void +com_import_stmt(c, n) + struct compiling *c; + node *n; +{ + int i; + REQ(n, import_stmt); + /* 'import' NAME (',' NAME)* NEWLINE | + 'from' NAME 'import' ('*' | NAME (',' NAME)*) NEWLINE */ + if (STR(CHILD(n, 0))[0] == 'f') { + /* 'from' NAME 'import' ... */ + REQ(CHILD(n, 1), NAME); + com_addopname(c, IMPORT_NAME, CHILD(n, 1)); + for (i = 3; i < NCH(n); i += 2) + com_addopname(c, IMPORT_FROM, CHILD(n, i)); + com_addbyte(c, POP_TOP); + } + else { + /* 'import' ... */ + for (i = 1; i < NCH(n); i += 2) { + com_addopname(c, IMPORT_NAME, CHILD(n, i)); + com_addopname(c, STORE_NAME, CHILD(n, i)); + } + } +} + +static void +com_if_stmt(c, n) + struct compiling *c; + node *n; +{ + int i; + int anchor = 0; + REQ(n, if_stmt); + /*'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite] */ + for (i = 0; i+3 < NCH(n); i+=4) { + int a = 0; + node *ch = CHILD(n, i+1); + if (i > 0) + com_addoparg(c, SET_LINENO, ch->n_lineno); + com_node(c, CHILD(n, i+1)); + com_addfwref(c, JUMP_IF_FALSE, &a); + com_addbyte(c, POP_TOP); + com_node(c, CHILD(n, i+3)); + com_addfwref(c, JUMP_FORWARD, &anchor); + com_backpatch(c, a); + com_addbyte(c, POP_TOP); + } + if (i+2 < NCH(n)) + com_node(c, CHILD(n, i+2)); + com_backpatch(c, anchor); +} + +static void +com_while_stmt(c, n) + struct compiling *c; + node *n; +{ + int break_anchor = 0; + int anchor = 0; + int begin; + REQ(n, while_stmt); /* 'while' test ':' suite ['else' ':' suite] */ + com_addfwref(c, SETUP_LOOP, &break_anchor); + begin = c->c_nexti; + com_addoparg(c, SET_LINENO, n->n_lineno); + com_node(c, CHILD(n, 1)); + com_addfwref(c, JUMP_IF_FALSE, &anchor); + com_addbyte(c, POP_TOP); + c->c_loops++; + com_node(c, CHILD(n, 3)); + c->c_loops--; + com_addoparg(c, JUMP_ABSOLUTE, begin); + com_backpatch(c, anchor); + com_addbyte(c, POP_TOP); + com_addbyte(c, POP_BLOCK); + if (NCH(n) > 4) + com_node(c, CHILD(n, 6)); + com_backpatch(c, break_anchor); +} + +static void +com_for_stmt(c, n) + struct compiling *c; + node *n; +{ + object *v; + int break_anchor = 0; + int anchor = 0; + int begin; + REQ(n, for_stmt); + /* 'for' exprlist 'in' exprlist ':' suite ['else' ':' suite] */ + com_addfwref(c, SETUP_LOOP, &break_anchor); + com_node(c, CHILD(n, 3)); + v = newintobject(0L); + if (v == NULL) + c->c_errors++; + com_addoparg(c, LOAD_CONST, com_addconst(c, v)); + XDECREF(v); + begin = c->c_nexti; + com_addoparg(c, SET_LINENO, n->n_lineno); + com_addfwref(c, FOR_LOOP, &anchor); + com_assign(c, CHILD(n, 1), 1/*assigning*/); + c->c_loops++; + com_node(c, CHILD(n, 5)); + c->c_loops--; + com_addoparg(c, JUMP_ABSOLUTE, begin); + com_backpatch(c, anchor); + com_addbyte(c, POP_BLOCK); + if (NCH(n) > 8) + com_node(c, CHILD(n, 8)); + com_backpatch(c, break_anchor); +} + +/* Although 'execpt' and 'finally' clauses can be combined + syntactically, they are compiled separately. In fact, + try: S + except E1: S1 + except E2: S2 + ... + finally: Sf + is equivalent to + try: + try: S + except E1: S1 + except E2: S2 + ... + finally: Sf + meaning that the 'finally' clause is entered even if things + go wrong again in an exception handler. Note that this is + not the case for exception handlers: at most one is entered. + + Code generated for "try: S finally: Sf" is as follows: + + SETUP_FINALLY L + + POP_BLOCK + LOAD_CONST + L: + END_FINALLY + + The special instructions use the block stack. Each block + stack entry contains the instruction that created it (here + SETUP_FINALLY), the level of the value stack at the time the + block stack entry was created, and a label (here L). + + SETUP_FINALLY: + Pushes the current value stack level and the label + onto the block stack. + POP_BLOCK: + Pops en entry from the block stack, and pops the value + stack until its level is the same as indicated on the + block stack. (The label is ignored.) + END_FINALLY: + Pops a variable number of entries from the *value* stack + and re-raises the exception they specify. The number of + entries popped depends on the (pseudo) exception type. + + The block stack is unwound when an exception is raised: + when a SETUP_FINALLY entry is found, the exception is pushed + onto the value stack (and the exception condition is cleared), + and the interpreter jumps to the label gotten from the block + stack. + + Code generated for "try: S except E1, V1: S1 except E2, V2: S2 ...": + (The contents of the value stack is shown in [], with the top + at the right; 'tb' is trace-back info, 'val' the exception's + associated value, and 'exc' the exception.) + + Value stack Label Instruction Argument + [] SETUP_EXCEPT L1 + [] + [] POP_BLOCK + [] JUMP_FORWARD L0 + + [tb, val, exc] L1: DUP ) + [tb, val, exc, exc] ) + [tb, val, exc, exc, E1] COMPARE_OP EXC_MATCH ) only if E1 + [tb, val, exc, 1-or-0] JUMP_IF_FALSE L2 ) + [tb, val, exc, 1] POP ) + [tb, val, exc] POP + [tb, val] (or POP if no V1) + [tb] POP + [] + JUMP_FORWARD L0 + + [tb, val, exc, 0] L2: POP + [tb, val, exc] DUP + .............................etc....................... + + [tb, val, exc, 0] Ln+1: POP + [tb, val, exc] END_FINALLY # re-raise exception + + [] L0: + + Of course, parts are not generated if Vi or Ei is not present. +*/ + +static void +com_try_stmt(c, n) + struct compiling *c; + node *n; +{ + int finally_anchor = 0; + int except_anchor = 0; + REQ(n, try_stmt); + /* 'try' ':' suite (except_clause ':' suite)* ['finally' ':' suite] */ + + if (NCH(n) > 3 && TYPE(CHILD(n, NCH(n)-3)) != except_clause) { + /* Have a 'finally' clause */ + com_addfwref(c, SETUP_FINALLY, &finally_anchor); + } + if (NCH(n) > 3 && TYPE(CHILD(n, 3)) == except_clause) { + /* Have an 'except' clause */ + com_addfwref(c, SETUP_EXCEPT, &except_anchor); + } + com_node(c, CHILD(n, 2)); + if (except_anchor) { + int end_anchor = 0; + int i; + node *ch; + com_addbyte(c, POP_BLOCK); + com_addfwref(c, JUMP_FORWARD, &end_anchor); + com_backpatch(c, except_anchor); + for (i = 3; + i < NCH(n) && TYPE(ch = CHILD(n, i)) == except_clause; + i += 3) { + /* except_clause: 'except' [expr [',' expr]] */ + if (except_anchor == 0) { + err_setstr(TypeError, + "default 'except:' must be last"); + c->c_errors++; + break; + } + except_anchor = 0; + com_addoparg(c, SET_LINENO, ch->n_lineno); + if (NCH(ch) > 1) { + com_addbyte(c, DUP_TOP); + com_node(c, CHILD(ch, 1)); + com_addoparg(c, COMPARE_OP, EXC_MATCH); + com_addfwref(c, JUMP_IF_FALSE, &except_anchor); + com_addbyte(c, POP_TOP); + } + com_addbyte(c, POP_TOP); + if (NCH(ch) > 3) + com_assign(c, CHILD(ch, 3), 1/*assigning*/); + else + com_addbyte(c, POP_TOP); + com_addbyte(c, POP_TOP); + com_node(c, CHILD(n, i+2)); + com_addfwref(c, JUMP_FORWARD, &end_anchor); + if (except_anchor) { + com_backpatch(c, except_anchor); + com_addbyte(c, POP_TOP); + } + } + com_addbyte(c, END_FINALLY); + com_backpatch(c, end_anchor); + } + if (finally_anchor) { + node *ch; + com_addbyte(c, POP_BLOCK); + com_addoparg(c, LOAD_CONST, com_addconst(c, None)); + com_backpatch(c, finally_anchor); + ch = CHILD(n, NCH(n)-1); + com_addoparg(c, SET_LINENO, ch->n_lineno); + com_node(c, ch); + com_addbyte(c, END_FINALLY); + } +} + +static void +com_suite(c, n) + struct compiling *c; + node *n; +{ + REQ(n, suite); + /* simple_stmt | NEWLINE INDENT NEWLINE* (stmt NEWLINE*)+ DEDENT */ + if (NCH(n) == 1) { + com_node(c, CHILD(n, 0)); + } + else { + int i; + for (i = 0; i < NCH(n); i++) { + node *ch = CHILD(n, i); + if (TYPE(ch) == stmt) + com_node(c, ch); + } + } +} + +static void +com_funcdef(c, n) + struct compiling *c; + node *n; +{ + object *v; + REQ(n, funcdef); /* funcdef: 'def' NAME parameters ':' suite */ + v = (object *)compile(n, c->c_filename); + if (v == NULL) + c->c_errors++; + else { + int i = com_addconst(c, v); + com_addoparg(c, LOAD_CONST, i); + com_addbyte(c, BUILD_FUNCTION); + com_addopname(c, STORE_NAME, CHILD(n, 1)); + DECREF(v); + } +} + +static void +com_bases(c, n) + struct compiling *c; + node *n; +{ + int i, nbases; + REQ(n, baselist); + /* + baselist: atom arguments (',' atom arguments)* + arguments: '(' [testlist] ')' + */ + for (i = 0; i < NCH(n); i += 3) + com_node(c, CHILD(n, i)); + com_addoparg(c, BUILD_TUPLE, (NCH(n)+1) / 3); +} + +static void +com_classdef(c, n) + struct compiling *c; + node *n; +{ + object *v; + REQ(n, classdef); + /* + classdef: 'class' NAME parameters ['=' baselist] ':' suite + baselist: atom arguments (',' atom arguments)* + arguments: '(' [testlist] ')' + */ + if (NCH(n) == 7) + com_bases(c, CHILD(n, 4)); + else + com_addoparg(c, LOAD_CONST, com_addconst(c, None)); + v = (object *)compile(n, c->c_filename); + if (v == NULL) + c->c_errors++; + else { + int i = com_addconst(c, v); + com_addoparg(c, LOAD_CONST, i); + com_addbyte(c, BUILD_FUNCTION); + com_addbyte(c, UNARY_CALL); + com_addbyte(c, BUILD_CLASS); + com_addopname(c, STORE_NAME, CHILD(n, 1)); + DECREF(v); + } +} + +static void +com_node(c, n) + struct compiling *c; + node *n; +{ + switch (TYPE(n)) { + + /* Definition nodes */ + + case funcdef: + com_funcdef(c, n); + break; + case classdef: + com_classdef(c, n); + break; + + /* Trivial parse tree nodes */ + + case stmt: + case flow_stmt: + com_node(c, CHILD(n, 0)); + break; + + case simple_stmt: + case compound_stmt: + com_addoparg(c, SET_LINENO, n->n_lineno); + com_node(c, CHILD(n, 0)); + break; + + /* Statement nodes */ + + case expr_stmt: + com_expr_stmt(c, n); + break; + case print_stmt: + com_print_stmt(c, n); + break; + case del_stmt: /* 'del' exprlist NEWLINE */ + com_assign(c, CHILD(n, 1), 0/*delete*/); + break; + case pass_stmt: + break; + case break_stmt: + if (c->c_loops == 0) { + err_setstr(TypeError, "'break' outside loop"); + c->c_errors++; + } + com_addbyte(c, BREAK_LOOP); + break; + case return_stmt: + com_return_stmt(c, n); + break; + case raise_stmt: + com_raise_stmt(c, n); + break; + case import_stmt: + com_import_stmt(c, n); + break; + case if_stmt: + com_if_stmt(c, n); + break; + case while_stmt: + com_while_stmt(c, n); + break; + case for_stmt: + com_for_stmt(c, n); + break; + case try_stmt: + com_try_stmt(c, n); + break; + case suite: + com_suite(c, n); + break; + + /* Expression nodes */ + + case testlist: + com_list(c, n); + break; + case test: + com_test(c, n); + break; + case and_test: + com_and_test(c, n); + break; + case not_test: + com_not_test(c, n); + break; + case comparison: + com_comparison(c, n); + break; + case exprlist: + com_list(c, n); + break; + case expr: + com_expr(c, n); + break; + case term: + com_term(c, n); + break; + case factor: + com_factor(c, n); + break; + case atom: + com_atom(c, n); + break; + + default: + fprintf(stderr, "node type %d\n", TYPE(n)); + err_setstr(SystemError, "com_node: unexpected node type"); + c->c_errors++; + } +} + +static void com_fplist PROTO((struct compiling *, node *)); + +static void +com_fpdef(c, n) + struct compiling *c; + node *n; +{ + REQ(n, fpdef); /* fpdef: NAME | '(' fplist ')' */ + if (TYPE(CHILD(n, 0)) == LPAR) + com_fplist(c, CHILD(n, 1)); + else + com_addopname(c, STORE_NAME, CHILD(n, 0)); +} + +static void +com_fplist(c, n) + struct compiling *c; + node *n; +{ + REQ(n, fplist); /* fplist: fpdef (',' fpdef)* */ + if (NCH(n) == 1) { + com_fpdef(c, CHILD(n, 0)); + } + else { + int i; + com_addoparg(c, UNPACK_TUPLE, (NCH(n)+1)/2); + for (i = 0; i < NCH(n); i += 2) + com_fpdef(c, CHILD(n, i)); + } +} + +static void +com_file_input(c, n) + struct compiling *c; + node *n; +{ + int i; + REQ(n, file_input); /* (NEWLINE | stmt)* ENDMARKER */ + for (i = 0; i < NCH(n); i++) { + node *ch = CHILD(n, i); + if (TYPE(ch) != ENDMARKER && TYPE(ch) != NEWLINE) + com_node(c, ch); + } +} + +/* Top-level compile-node interface */ + +static void +compile_funcdef(c, n) + struct compiling *c; + node *n; +{ + node *ch; + REQ(n, funcdef); /* funcdef: 'def' NAME parameters ':' suite */ + ch = CHILD(n, 2); /* parameters: '(' [fplist] ')' */ + ch = CHILD(ch, 1); /* ')' | fplist */ + if (TYPE(ch) == RPAR) + com_addbyte(c, REFUSE_ARGS); + else { + com_addbyte(c, REQUIRE_ARGS); + com_fplist(c, ch); + } + c->c_infunction = 1; + com_node(c, CHILD(n, 4)); + c->c_infunction = 0; + com_addoparg(c, LOAD_CONST, com_addconst(c, None)); + com_addbyte(c, RETURN_VALUE); +} + +static void +compile_node(c, n) + struct compiling *c; + node *n; +{ + com_addoparg(c, SET_LINENO, n->n_lineno); + + switch (TYPE(n)) { + + case single_input: /* One interactive command */ + /* NEWLINE | simple_stmt | compound_stmt NEWLINE */ + com_addbyte(c, REFUSE_ARGS); + n = CHILD(n, 0); + if (TYPE(n) != NEWLINE) + com_node(c, n); + com_addoparg(c, LOAD_CONST, com_addconst(c, None)); + com_addbyte(c, RETURN_VALUE); + break; + + case file_input: /* A whole file, or built-in function exec() */ + com_addbyte(c, REFUSE_ARGS); + com_file_input(c, n); + com_addoparg(c, LOAD_CONST, com_addconst(c, None)); + com_addbyte(c, RETURN_VALUE); + break; + + case expr_input: /* Built-in function eval() */ + com_addbyte(c, REFUSE_ARGS); + com_node(c, CHILD(n, 0)); + com_addbyte(c, RETURN_VALUE); + break; + + case eval_input: /* Built-in function input() */ + com_addbyte(c, REFUSE_ARGS); + com_node(c, CHILD(n, 0)); + com_addbyte(c, RETURN_VALUE); + break; + + case funcdef: /* A function definition */ + compile_funcdef(c, n); + break; + + case classdef: /* A class definition */ + /* 'class' NAME parameters ['=' baselist] ':' suite */ + com_addbyte(c, REFUSE_ARGS); + com_node(c, CHILD(n, NCH(n)-1)); + com_addbyte(c, LOAD_LOCALS); + com_addbyte(c, RETURN_VALUE); + break; + + default: + fprintf(stderr, "node type %d\n", TYPE(n)); + err_setstr(SystemError, "compile_node: unexpected node type"); + c->c_errors++; + } +} + +codeobject * +compile(n, filename) + node *n; + char *filename; +{ + struct compiling sc; + codeobject *co; + if (!com_init(&sc, filename)) + return NULL; + compile_node(&sc, n); + com_done(&sc); + if (sc.c_errors == 0) + co = newcodeobject(sc.c_code, sc.c_consts, sc.c_names, filename); + else + co = NULL; + com_free(&sc); + return co; +} diff --git a/src/compile.h b/src/compile.h new file mode 100644 index 0000000..fb66ea7 --- /dev/null +++ b/src/compile.h @@ -0,0 +1,47 @@ +/*********************************************************** +Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +Netherlands. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* Definitions for compiled intermediate code */ + + +/* An intermediate code fragment contains: + - a string that encodes the instructions, + - a list of the constants, + - and a list of the names used. */ + +typedef struct { + OB_HEAD + stringobject *co_code; /* instruction opcodes */ + object *co_consts; /* list of immutable constant objects */ + object *co_names; /* list of stringobjects */ + object *co_filename; /* string */ +} codeobject; + +extern typeobject Codetype; + +#define is_codeobject(op) ((op)->ob_type == &Codetype) + + +/* Public interface */ +codeobject *compile PROTO((struct _node *, char *)); diff --git a/src/config.c b/src/config.c new file mode 100644 index 0000000..9d153c1 --- /dev/null +++ b/src/config.c @@ -0,0 +1,180 @@ +/*********************************************************** +Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +Netherlands. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* Configurable Python configuration file */ + +#include + +#ifdef USE_STDWIN +#include + +static int use_stdwin; +#endif + +/*ARGSUSED*/ +void +initargs(p_argc, p_argv) + int *p_argc; + char ***p_argv; +{ +#ifdef USE_STDWIN + extern char *getenv(); + char *display; + + /* Ignore an initial argument of '-s', for backward compatibility */ + if (*p_argc > 1 && strcmp((*p_argv)[1], "-s") == 0) { + (*p_argv)[1] = (*p_argv)[0]; + (*p_argc)--, (*p_argv)++; + } + + /* Assume we have to initialize stdwin if either of the following + conditions holds: + - the environment variable $DISPLAY is set + - there is an argument "-display" somewhere + */ + + display = getenv("DISPLAY"); + if (display != 0) + use_stdwin = 1; + else { + int i; + /* Scan through the arguments looking for "-display" */ + for (i = 1; i < *p_argc; i++) { + if (strcmp((*p_argv)[i], "-display") == 0) { + use_stdwin = 1; + break; + } + } + } + + if (use_stdwin) + wargs(p_argc, p_argv); +#endif +} + +void +initcalls() +{ +} + +void +donecalls() +{ +#ifdef USE_STDWIN + if (use_stdwin) + wdone(); +#endif +#ifdef USE_AUDIO + asa_done(); +#endif +} + +#ifdef USE_STDWIN +static void +maybeinitstdwin() +{ + if (use_stdwin) + initstdwin(); + else + fprintf(stderr, + "No $DISPLAY nor -display arg -- stdwin not available\n"); +} +#endif + +#ifndef PYTHONPATH +#define PYTHONPATH ".:/usr/local/lib/python" +#endif + +extern char *getenv(); + +char * +getpythonpath() +{ + char *path = getenv("PYTHONPATH"); + if (path == 0) + path = PYTHONPATH; + return path; +} + + +/* Table of built-in modules. + These are initialized when first imported. */ + +/* Standard modules */ +extern void inittime(); +extern void initmath(); +extern void initregexp(); +extern void initposix(); +#ifdef USE_AUDIO +extern void initaudio(); +#endif +#ifdef USE_AMOEBA +extern void initamoeba(); +#endif +#ifdef USE_GL +extern void initgl(); +#ifdef USE_PANEL +extern void initpanel(); +#endif +#endif +#ifdef USE_STDWIN +extern void maybeinitstdwin(); +#endif + +struct { + char *name; + void (*initfunc)(); +} inittab[] = { + + /* Standard modules */ + + {"time", inittime}, + {"math", initmath}, + {"regexp", initregexp}, + {"posix", initposix}, + + + /* Optional modules */ + +#ifdef USE_AUDIO + {"audio", initaudio}, +#endif + +#ifdef USE_AMOEBA + {"amoeba", initamoeba}, +#endif + +#ifdef USE_GL + {"gl", initgl}, +#ifdef USE_PANEL + {"pnl", initpanel}, +#endif +#endif + +#ifdef USE_STDWIN + {"stdwin", maybeinitstdwin}, +#endif + + {0, 0} /* Sentinel */ +}; diff --git a/src/configmac.c b/src/configmac.c new file mode 100644 index 0000000..c73130a --- /dev/null +++ b/src/configmac.c @@ -0,0 +1,109 @@ +/*********************************************************** +Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +Netherlands. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* Configuration using STDWIN on the Mac (THINK_C or MPW) */ + +#ifdef THINK_C +#define USE_STDWIN +#endif + +#ifdef USE_STDWIN +#include "stdwin.h" +#endif + +void +initargs(p_argc, p_argv) + int *p_argc; + char ***p_argv; +{ +#ifdef USE_STDWIN + +#ifdef THINK_C_3_0 + wsetstdio(1); +#else + /* This printf() statement is really needed only + to initialize THINK C 4.0's stdio: */ + printf( +"Python 4.0, Copyright 1990 Stichting Mathematisch Centrum, Amsterdam\n"); +#endif + + wargs(p_argc, p_argv); +#endif +} + +void +initcalls() +{ +} + +void +donecalls() +{ +#ifdef USE_STDWIN + wdone(); +#endif +} + +#ifndef PYTHONPATH +/* On the Mac, the search path is a space-separated list of directories */ +#define PYTHONPATH ": :lib :lib:stdwin :lib:mac :lib:demo" +#endif + +char * +getpythonpath() +{ + return PYTHONPATH; +} + + +/* Table of built-in modules. + These are initialized when first imported. */ + +/* Standard modules */ +extern void inittime(); +extern void initmath(); +extern void initregexp(); + +/* Mac-specific modules */ +extern void initmac(); +#ifdef USE_STDWIN +extern void initstdwin(); +#endif + +struct { + char *name; + void (*initfunc)(); +} inittab[] = { + /* Standard modules */ + {"time", inittime}, + {"math", initmath}, + {"regexp", initregexp}, + + /* Mac-specific modules */ + {"mac", initmac}, +#ifdef USE_STDWIN + {"stdwin", initstdwin}, +#endif + {0, 0} /* Sentinel */ +}; diff --git a/src/cstubs b/src/cstubs new file mode 100644 index 0000000..3996572 --- /dev/null +++ b/src/cstubs @@ -0,0 +1,999 @@ +/* +Input used to generate the Python module "glmodule.c". +The stub generator is a Python script called "cgen". + +Each definition must be contained on one line: + + + + can be: void, short, long (XXX maybe others?) + + can be: char, string, short, float, long, or double + string indicates a null terminated string; + if is char and begins with a *, the * is stripped + and is changed into string + + has the form or [] + where can be + s: arg is sent + r: arg is received (arg is a pointer) + and can be (N and I are numbers): + N + argI + retval + N*argI + N*retval +*/ + +#include +#include + +#include "allobjects.h" +#include "import.h" +#include "modsupport.h" +#include "cgensupport.h" + +/* +Some stubs are too complicated for the stub generator. +We can include manually written versions of them here. +A line starting with '%' gives the name of the function so the stub +generator can include it in the table of functions. +*/ + +/* +varray -- an array of v.. calls. +The argument is an array (maybe list or tuple) of points. +Each point must be a tuple or list of coordinates (x, y, z). +The points may be 2- or 3-dimensional but must all have the +same dimension. Float and int values may be mixed however. +The points are always converted to 3D double precision points +by assuming z=0.0 if necessary (as indicated in the man page), +and for each point v3d() is called. +*/ + +% varray + +static object * +gl_varray(self, args) + object *self; + object *args; +{ + object *v, *w; + int i, n, width; + double vec[3]; + object * (*getitem) FPROTO((object *, int)); + + if (!getiobjectarg(args, 1, 0, &v)) + return NULL; + + if (is_listobject(v)) { + n = getlistsize(v); + getitem = getlistitem; + } + else if (is_tupleobject(v)) { + n = gettuplesize(v); + getitem = gettupleitem; + } + else { + err_badarg(); + return NULL; + } + + if (n == 0) { + INCREF(None); + return None; + } + if (n > 0) + w = (*getitem)(v, 0); + + width = 0; + if (w == NULL) { + } + else if (is_listobject(w)) { + width = getlistsize(w); + } + else if (is_tupleobject(w)) { + width = gettuplesize(w); + } + + switch (width) { + case 2: + vec[2] = 0.0; + /* Fall through */ + case 3: + break; + default: + err_badarg(); + return NULL; + } + + for (i = 0; i < n; i++) { + w = (*getitem)(v, i); + if (!getidoublearray(w, 1, 0, width, vec)) + return NULL; + v3d(vec); + } + + INCREF(None); + return None; +} + +/* +vnarray, nvarray -- an array of n3f and v3f calls. +The argument is an array (list or tuple) of pairs of points and normals. +Each pair is a tuple (NOT a list) of a point and a normal for that point. +Each point or normal must be a tuple (NOT a list) of coordinates (x, y, z). +Three coordinates must be given. Float and int values may be mixed. +For each pair, n3f() is called for the normal, and then v3f() is called +for the vector. + +vnarray and nvarray differ only in the order of the vector and normal in +the pair: vnarray expects (v, n) while nvarray expects (n, v). +*/ + +static object *gen_nvarray(); /* Forward */ + +% nvarray + +static object * +gl_nvarray(self, args) + object *self; + object *args; +{ + return gen_nvarray(args, 0); +} + +% vnarray + +static object * +gl_vnarray(self, args) + object *self; + object *args; +{ + return gen_nvarray(args, 1); +} + +/* Generic, internal version of {nv,nv}array: inorm indicates the + argument order, 0: normal first, 1: vector first. */ + +static object * +gen_nvarray(args, inorm) + object *args; + int inorm; +{ + object *v, *w, *wnorm, *wvec; + int i, n; + float norm[3], vec[3]; + object * (*getitem) FPROTO((object *, int)); + + if (!getiobjectarg(args, 1, 0, &v)) + return NULL; + + if (is_listobject(v)) { + n = getlistsize(v); + getitem = getlistitem; + } + else if (is_tupleobject(v)) { + n = gettuplesize(v); + getitem = gettupleitem; + } + else { + err_badarg(); + return NULL; + } + + for (i = 0; i < n; i++) { + w = (*getitem)(v, i); + if (!is_tupleobject(w) || gettuplesize(w) != 2) { + err_badarg(); + return NULL; + } + wnorm = gettupleitem(w, inorm); + wvec = gettupleitem(w, 1 - inorm); + if (!getifloatarray(wnorm, 1, 0, 3, norm) || + !getifloatarray(wvec, 1, 0, 3, vec)) + return NULL; + n3f(norm); + v3f(vec); + } + + INCREF(None); + return None; +} + +/* nurbssurface(s_knots[], t_knots[], ctl[][], s_order, t_order, type). + The dimensions of ctl[] are computed as follows: + [len(s_knots) - s_order], [len(t_knots) - t_order] +*/ + +% nurbssurface + +static object * +gl_nurbssurface(self, args) + object *self; + object *args; +{ + long arg1 ; + double * arg2 ; + long arg3 ; + double * arg4 ; + double *arg5 ; + long arg6 ; + long arg7 ; + long arg8 ; + long ncoords; + long s_byte_stride, t_byte_stride; + long s_nctl, t_nctl; + long s, t; + object *v, *w, *pt; + double *pnext; + if (!getilongarraysize(args, 6, 0, &arg1)) + return NULL; + if ((arg2 = NEW(double, arg1 )) == NULL) { + return err_nomem(); + } + if (!getidoublearray(args, 6, 0, arg1 , arg2)) + return NULL; + if (!getilongarraysize(args, 6, 1, &arg3)) + return NULL; + if ((arg4 = NEW(double, arg3 )) == NULL) { + return err_nomem(); + } + if (!getidoublearray(args, 6, 1, arg3 , arg4)) + return NULL; + if (!getilongarg(args, 6, 3, &arg6)) + return NULL; + if (!getilongarg(args, 6, 4, &arg7)) + return NULL; + if (!getilongarg(args, 6, 5, &arg8)) + return NULL; + if (arg8 == N_XYZ) + ncoords = 3; + else if (arg8 == N_XYZW) + ncoords = 4; + else { + err_badarg(); + return NULL; + } + s_nctl = arg1 - arg6; + t_nctl = arg3 - arg7; + if (!getiobjectarg(args, 6, 2, &v)) + return NULL; + if (!is_listobject(v) || getlistsize(v) != s_nctl) { + err_badarg(); + return NULL; + } + if ((arg5 = NEW(double, s_nctl*t_nctl*ncoords )) == NULL) { + return err_nomem(); + } + pnext = arg5; + for (s = 0; s < s_nctl; s++) { + w = getlistitem(v, s); + if (w == NULL || !is_listobject(w) || + getlistsize(w) != t_nctl) { + err_badarg(); + return NULL; + } + for (t = 0; t < t_nctl; t++) { + pt = getlistitem(w, t); + if (!getidoublearray(pt, 1, 0, ncoords, pnext)) + return NULL; + pnext += ncoords; + } + } + s_byte_stride = sizeof(double) * ncoords; + t_byte_stride = s_byte_stride * s_nctl; + nurbssurface( arg1 , arg2 , arg3 , arg4 , + s_byte_stride , t_byte_stride , arg5 , arg6 , arg7 , arg8 ); + DEL(arg2); + DEL(arg4); + DEL(arg5); + INCREF(None); + return None; +} + +/* nurbscurve(knots, ctlpoints, order, type). + The length of ctlpoints is len(knots)-order. */ + +%nurbscurve + +static object * +gl_nurbscurve(self, args) + object *self; + object *args; +{ + long arg1 ; + double * arg2 ; + long arg3 ; + double * arg4 ; + long arg5 ; + long arg6 ; + int ncoords, npoints; + int i; + object *v; + double *pnext; + if (!getilongarraysize(args, 4, 0, &arg1)) + return NULL; + if ((arg2 = NEW(double, arg1 )) == NULL) { + return err_nomem(); + } + if (!getidoublearray(args, 4, 0, arg1 , arg2)) + return NULL; + if (!getilongarg(args, 4, 2, &arg5)) + return NULL; + if (!getilongarg(args, 4, 3, &arg6)) + return NULL; + if (arg6 == N_ST) + ncoords = 2; + else if (arg6 == N_STW) + ncoords = 3; + else { + err_badarg(); + return NULL; + } + npoints = arg1 - arg5; + if (!getiobjectarg(args, 4, 1, &v)) + return NULL; + if (!is_listobject(v) || getlistsize(v) != npoints) { + err_badarg(); + return NULL; + } + if ((arg4 = NEW(double, npoints*ncoords )) == NULL) { + return err_nomem(); + } + pnext = arg4; + for (i = 0; i < npoints; i++) { + if (!getidoublearray(getlistitem(v, i), 1, 0, ncoords, pnext)) + return NULL; + pnext += ncoords; + } + arg3 = (sizeof(double)) * ncoords; + nurbscurve( arg1 , arg2 , arg3 , arg4 , arg5 , arg6 ); + DEL(arg2); + DEL(arg4); + INCREF(None); + return None; +} + +/* pwlcurve(points, type). + Points is a list of points. Type must be N_ST. */ + +%pwlcurve + +static object * +gl_pwlcurve(self, args) + object *self; + object *args; +{ + object *v; + long type; + double *data, *pnext; + long npoints, ncoords; + int i; + if (!getiobjectarg(args, 2, 0, &v)) + return NULL; + if (!getilongarg(args, 2, 1, &type)) + return NULL; + if (!is_listobject(v)) { + err_badarg(); + return NULL; + } + npoints = getlistsize(v); + if (type == N_ST) + ncoords = 2; + else { + err_badarg(); + return NULL; + } + if ((data = NEW(double, npoints*ncoords)) == NULL) { + return err_nomem(); + } + pnext = data; + for (i = 0; i < npoints; i++) { + if (!getidoublearray(getlistitem(v, i), 1, 0, ncoords, pnext)) + return NULL; + pnext += ncoords; + } + pwlcurve(npoints, data, sizeof(double)*ncoords, type); + DEL(data); + INCREF(None); + return None; +} + + +/* Picking and Selecting */ + +static short *pickbuffer = NULL; +static long pickbuffersize; + +static object * +pick_select(args, func) + object *args; + void (*func)(); +{ + if (!getilongarg(args, 1, 0, &pickbuffersize)) + return NULL; + if (pickbuffer != NULL) { + err_setstr(RuntimeError, + "pick/gselect: already picking/selecting"); + return NULL; + } + if ((pickbuffer = NEW(short, pickbuffersize)) == NULL) { + return err_nomem(); + } + (*func)(pickbuffer, pickbuffersize); + INCREF(None); + return None; +} + +static object * +endpick_select(args, func) + object *args; + long (*func)(); +{ + object *v, *w; + int i, nhits, n; + if (!getnoarg(args)) + return NULL; + if (pickbuffer == NULL) { + err_setstr(RuntimeError, + "endpick/endselect: not in pick/select mode"); + return NULL; + } + nhits = (*func)(pickbuffer); + if (nhits < 0) { + nhits = -nhits; /* How to report buffer overflow otherwise? */ + } + /* Scan the buffer to see how many integers */ + n = 0; + for (; nhits > 0; nhits--) { + n += 1 + pickbuffer[n]; + } + v = newlistobject(n); + if (v == NULL) + return NULL; + /* XXX Could do it nicer and interpret the data structure here, + returning a list of lists. But this can be done in Python... */ + for (i = 0; i < n; i++) { + w = newintobject((long)pickbuffer[i]); + if (w == NULL) { + DECREF(v); + return NULL; + } + setlistitem(v, i, w); + } + DEL(pickbuffer); + pickbuffer = NULL; + return v; +} + +extern void pick(), gselect(); +extern long endpick(), endselect(); + +%pick +static object *gl_pick(self, args) object *self, *args; { + return pick_select(args, pick); +} + +%endpick +static object *gl_endpick(self, args) object *self, *args; { + return endpick_select(args, endpick); +} + +%gselect +static object *gl_gselect(self, args) object *self, *args; { + return pick_select(args, gselect); +} + +%endselect +static object *gl_endselect(self, args) object *self, *args; { + return endpick_select(args, endselect); +} + + +/* XXX The generator botches this one. Here's a quick hack to fix it. */ + +% getmatrix float r[16] + +static object * +gl_getmatrix(self, args) + object *self; + object *args; +{ + float arg1 [ 16 ] ; + object *v, *w; + int i; + getmatrix( arg1 ); + v = newlistobject(16); + if (v == NULL) { + return err_nomem(); + } + for (i = 0; i < 16; i++) { + w = mknewfloatobject(arg1[i]); + if (w == NULL) { + DECREF(v); + return NULL; + } + setlistitem(v, i, w); + } + return v; +} + +/* End of manually written stubs */ + +%% + +long getshade +void devport short s long s +void rdr2i long s long s +void rectfs short s short s short s short s +void rects short s short s short s short s +void rmv2i long s long s +void noport +void popviewport +void clear +void clearhitcode +void closeobj +void cursoff +void curson +void doublebuffer +void finish +void gconfig +void ginit +void greset +void multimap +void onemap +void popattributes +void popmatrix +void pushattributes +void pushmatrix +void pushviewport +void qreset +void RGBmode +void singlebuffer +void swapbuffers +void gsync +void tpon +void tpoff +void clkon +void clkoff +void ringbell +#void callfunc +void gbegin +void textinit +void initnames +void pclos +void popname +void spclos +void zclear +void screenspace +void reshapeviewport +void winpush +void winpop +void foreground +void endfullscrn +void endpupmode +void fullscrn +void pupmode +void winconstraints +void pagecolor short s +void textcolor short s +void color short s +void curveit short s +void font short s +void linewidth short s +void setlinestyle short s +void setmap short s +void swapinterval short s +void writemask short s +void textwritemask short s +void qdevice short s +void unqdevice short s +void curvebasis short s +void curveprecision short s +void loadname short s +void passthrough short s +void pushname short s +void setmonitor short s +void setshade short s +void setpattern short s +void pagewritemask short s +# +void callobj long s +void delobj long s +void editobj long s +void makeobj long s +void maketag long s +void chunksize long s +void compactify long s +void deltag long s +void lsrepeat long s +void objinsert long s +void objreplace long s +void winclose long s +void blanktime long s +void freepup long s +# This is not in the library!? +###void pupcolor long s +# +void backbuffer long s +void frontbuffer long s +void lsbackup long s +void resetls long s +void lampon long s +void lampoff long s +void setbell long s +void blankscreen long s +void depthcue long s +void zbuffer long s +void backface long s +# +void cmov2i long s long s +void draw2i long s long s +void move2i long s long s +void pnt2i long s long s +void patchbasis long s long s +void patchprecision long s long s +void pdr2i long s long s +void pmv2i long s long s +void rpdr2i long s long s +void rpmv2i long s long s +void xfpt2i long s long s +void objdelete long s long s +void patchcurves long s long s +void minsize long s long s +void maxsize long s long s +void keepaspect long s long s +void prefsize long s long s +void stepunit long s long s +void fudge long s long s +void winmove long s long s +# +void attachcursor short s short s +void deflinestyle short s short s +void noise short s short s +void picksize short s short s +void qenter short s short s +void setdepth short s short s +void cmov2s short s short s +void draw2s short s short s +void move2s short s short s +void pdr2s short s short s +void pmv2s short s short s +void pnt2s short s short s +void rdr2s short s short s +void rmv2s short s short s +void rpdr2s short s short s +void rpmv2s short s short s +void xfpt2s short s short s +# +void cmov2 float s float s +void draw2 float s float s +void move2 float s float s +void pnt2 float s float s +void pdr2 float s float s +void pmv2 float s float s +void rdr2 float s float s +void rmv2 float s float s +void rpdr2 float s float s +void rpmv2 float s float s +void xfpt2 float s float s +# +void loadmatrix float s[16] +void multmatrix float s[16] +void crv float s[16] +void rcrv float s[16] +# +# Methods that have strings. +# +void addtopup long s char *s long s +void charstr char *s +void getport char *s +long strwidth char *s +long winopen char *s +void wintitle char *s +# +# Methods that have 1 long (# of elements) and an array +# +void polf long s float s[3*arg1] +void polf2 long s float s[2*arg1] +void poly long s float s[3*arg1] +void poly2 long s float s[2*arg1] +void crvn long s float s[3*arg1] +void rcrvn long s float s[4*arg1] +# +void polf2i long s long s[2*arg1] +void polfi long s long s[3*arg1] +void poly2i long s long s[2*arg1] +void polyi long s long s[3*arg1] +# +void polf2s long s short s[2*arg1] +void polfs long s short s[3*arg1] +void polys long s short s[3*arg1] +void poly2s long s short s[2*arg1] +# +void defcursor short s short s[16] +void writepixels short s short s[arg1] +void defbasis long s float s[16] +void gewrite short s short s[arg1] +# +void rotate short s char s +# This is not in the library!? +###void setbutton short s char s +void rot float s char s +# +void circfi long s long s long s +void circi long s long s long s +void cmovi long s long s long s +void drawi long s long s long s +void movei long s long s long s +void pnti long s long s long s +void newtag long s long s long s +void pdri long s long s long s +void pmvi long s long s long s +void rdri long s long s long s +void rmvi long s long s long s +void rpdri long s long s long s +void rpmvi long s long s long s +void xfpti long s long s long s +# +void circ float s float s float s +void circf float s float s float s +void cmov float s float s float s +void draw float s float s float s +void move float s float s float s +void pnt float s float s float s +void scale float s float s float s +void translate float s float s float s +void pdr float s float s float s +void pmv float s float s float s +void rdr float s float s float s +void rmv float s float s float s +void rpdr float s float s float s +void rpmv float s float s float s +void xfpt float s float s float s +# +void RGBcolor short s short s short s +void RGBwritemask short s short s short s +void setcursor short s short s short s +void tie short s short s short s +void circfs short s short s short s +void circs short s short s short s +void cmovs short s short s short s +void draws short s short s short s +void moves short s short s short s +void pdrs short s short s short s +void pmvs short s short s short s +void pnts short s short s short s +void rdrs short s short s short s +void rmvs short s short s short s +void rpdrs short s short s short s +void rpmvs short s short s short s +void xfpts short s short s short s +void curorigin short s short s short s +void cyclemap short s short s short s +# +void patch float s[16] float s[16] float s[16] +void splf long s float s[3*arg1] short s[arg1] +void splf2 long s float s[2*arg1] short s[arg1] +void splfi long s long s[3*arg1] short s[arg1] +void splf2i long s long s[2*arg1] short s[arg1] +void splfs long s short s[3*arg1] short s[arg1] +void splf2s long s short s[2*arg1] short s[arg1] +void defpattern short s short s short s[arg2*arg2/16] +# +void rpatch float s[16] float s[16] float s[16] float s[16] +# +# routines that send 4 floats +# +void ortho2 float s float s float s float s +void rect float s float s float s float s +void rectf float s float s float s float s +void xfpt4 float s float s float s float s +# +void textport short s short s short s short s +void mapcolor short s short s short s short s +void scrmask short s short s short s short s +void setvaluator short s short s short s short s +void viewport short s short s short s short s +void shaderange short s short s short s short s +void xfpt4s short s short s short s short s +void rectfi long s long s long s long s +void recti long s long s long s long s +void xfpt4i long s long s long s long s +void prefposition long s long s long s long s +# +void arc float s float s float s short s short s +void arcf float s float s float s short s short s +void arcfi long s long s long s short s short s +void arci long s long s long s short s short s +# +void bbox2 short s short s float s float s float s float s +void bbox2i short s short s long s long s long s long s +void bbox2s short s short s short s short s short s short s +void blink short s short s short s short s short s +void ortho float s float s float s float s float s float s +void window float s float s float s float s float s float s +void lookat float s float s float s float s float s float s short s +# +void perspective short s float s float s float s +void polarview float s short s short s short s +# XXX getichararray not supported +#void writeRGB short s char s[arg1] char s[arg1] char s[arg1] +# +void arcfs short s short s short s short s short s +void arcs short s short s short s short s short s +void rectcopy short s short s short s short s short s short s +void RGBcursor short s short s short s short s short s short s short s +# +long getbutton short s +long getcmmode +long getlsbackup +long getresetls +long getdcm +long getzbuffer +long ismex +long isobj long s +long isqueued short s +long istag long s +# +long genobj +long gentag +long getbuffer +long getcolor +long getdisplaymode +long getfont +long getheight +long gethitcode +long getlstyle +long getlwidth +long getmap +long getplanes +long getwritemask +long qtest +long getlsrepeat +long getmonitor +long getopenobj +long getpattern +long winget +long winattach +long getothermonitor +long newpup +# +long getvaluator short s +void winset long s +long dopup long s +void getdepth short r short r +void getcpos short r short r +void getsize long r long r +void getorigin long r long r +void getviewport short r short r short r short r +void gettp short r short r short r short r +void getgpos float r float r float r float r +void winposition long s long s long s long s +void gRGBcolor short r short r short r +void gRGBmask short r short r short r +void getscrmask short r short r short r short r +void gRGBcursor short r short r short r short r short r short r short r short r long * +void getmcolor short s short r short r short r +void mapw long s short s short s float r float r float r float r float r float r +void mapw2 long s short s short s float r float r +void defrasterfont short s short s short s Fontchar s[arg3] short s short s[4*arg5] +long qread short r +void getcursor short r short r short r long r +# +# For these we receive arrays of stuff +# +void getdev long s short s[arg1] short r[arg1] +#XXX not generated correctly yet +#void getmatrix float r[16] +long readpixels short s short r[retval] +long readRGB short s char r[retval] char r[retval] char r[retval] +long blkqread short s short r[arg1] +# +# New 4D routines +# +void cmode +void concave long s +void curstype long s +void drawmode long s +void gammaramp short s[256] short s[256] short s[256] +long getbackface +long getdescender +long getdrawmode +long getmmode +long getsm +long getvideo long s +void imakebackground +void lmbind short s short s +void lmdef long s long s long s float s[arg3] +void mmode long s +void normal float s[3] +void overlay long s +void RGBrange short s short s short s short s short s short s short s short s +void setvideo long s long s +void shademodel long s +void underlay long s +# +# New Personal Iris/GT Routines +# +void bgnclosedline +void bgnline +void bgnpoint +void bgnpolygon +void bgnsurface +void bgntmesh +void bgntrim +void endclosedline +void endline +void endpoint +void endpolygon +void endsurface +void endtmesh +void endtrim +void blendfunction long s long s +void c3f float s[3] +void c3i long s[3] +void c3s short s[3] +void c4f float s[4] +void c4i long s[4] +void c4s short s[4] +void colorf float s +void cpack long s +void czclear long s long s +void dglclose long s +long dglopen char *s long s +long getgdesc long s +void getnurbsproperty long s float r +void glcompat long s long s +void iconsize long s long s +void icontitle char *s +void lRGBrange short s short s short s short s short s short s long s long s +void linesmooth long s +void lmcolor long s +void logicop long s +long lrectread short s short s short s short s long r[retval] +void lrectwrite short s short s short s short s long s[(arg2-arg1+1)*(arg4-arg3+1)] +long rectread short s short s short s short s short r[retval] +void rectwrite short s short s short s short s short s[(arg2-arg1+1)*(arg4-arg3+1)] +void lsetdepth long s long s +void lshaderange short s short s long s long s +void n3f float s[3] +void noborder +void pntsmooth long s +void readsource long s +void rectzoom float s float s +void sbox float s float s float s float s +void sboxi long s long s long s long s +void sboxs short s short s short s short s +void sboxf float s float s float s float s +void sboxfi long s long s long s long s +void sboxfs short s short s short s short s +void setnurbsproperty long s float s +void setpup long s long s long s +void smoothline long s +void subpixel long s +void swaptmesh +long swinopen long s +void v2f float s[2] +void v2i long s[2] +void v2s short s[2] +void v3f float s[3] +void v3i long s[3] +void v3s short s[3] +void v4f float s[4] +void v4i long s[4] +void v4s short s[4] +void videocmd long s +long windepth long s +void wmpack long s +void zdraw long s +void zfunction long s +void zsource long s +void zwritemask long s +# +# uses doubles +# +void v2d double s[2] +void v3d double s[3] +void v4d double s[4] diff --git a/src/dictobject.c b/src/dictobject.c new file mode 100644 index 0000000..3bbd1d5 --- /dev/null +++ b/src/dictobject.c @@ -0,0 +1,605 @@ +/*********************************************************** +Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +Netherlands. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* Dictionary object implementation; using a hash table */ + +/* +XXX Note -- although this may look professional, I didn't think very hard +about the problem and it is possible that obvious improvements exist. +A similar module that I saw by Chris Torek: +- uses chaining instead of hashed linear probing +- remembers the hash value with the entry to speed up table resizing +- sets the table size to a power of 2 +- uses a different hash function: + h = 0; p = str; while (*p) h = (h<<5) - h + *p++; +*/ + +#include "allobjects.h" + + +/* +Table of primes suitable as keys, in ascending order. +The first line are the largest primes less than some powers of two, +the second line is the largest prime less than 6000, +and the third line is a selection from Knuth, Vol. 3, Sec. 6.1, Table 1. +The final value is a sentinel and should cause the memory allocation +of that many entries to fail (if none of the earlier values cause such +failure already). +*/ +static unsigned int primes[] = { + 3, 7, 13, 31, 61, 127, 251, 509, 1021, 2017, 4093, + 5987, + 9551, 15683, 19609, 31397, + 0xffffffff /* All bits set -- truncation OK */ +}; + +/* String used as dummy key to fill deleted entries */ +static stringobject *dummy; /* Initialized by first call to newdictobject() */ + +/* +Invariant for entries: when in use, de_value is not NULL and de_key is +not NULL and not dummy; when not in use, de_value is NULL and de_key +is either NULL or dummy. A dummy key value cannot be replaced by NULL, +since otherwise other keys may be lost. +*/ +typedef struct { + stringobject *de_key; + object *de_value; +} dictentry; + +/* +To ensure the lookup algorithm terminates, the table size must be a +prime number and there must be at least one NULL key in the table. +The value di_fill is the number of non-NULL keys; di_used is the number +of non-NULL, non-dummy keys. +To avoid slowing down lookups on a near-full table, we resize the table +when it is more than half filled. +*/ +typedef struct { + OB_HEAD + int di_fill; + int di_used; + int di_size; + dictentry *di_table; +} dictobject; + +object * +newdictobject() +{ + register dictobject *dp; + if (dummy == NULL) { /* Auto-initialize dummy */ + dummy = (stringobject *) newstringobject(""); + if (dummy == NULL) + return NULL; + } + dp = NEWOBJ(dictobject, &Dicttype); + if (dp == NULL) + return NULL; + dp->di_size = primes[0]; + dp->di_table = (dictentry *) calloc(sizeof(dictentry), dp->di_size); + if (dp->di_table == NULL) { + DEL(dp); + return err_nomem(); + } + dp->di_fill = 0; + dp->di_used = 0; + return (object *)dp; +} + +/* +The basic lookup function used by all operations. +This is essentially Algorithm D from Knuth Vol. 3, Sec. 6.4. +Open addressing is preferred over chaining since the link overhead for +chaining would be substantial (100% with typical malloc overhead). + +First a 32-bit hash value, 'sum', is computed from the key string. +The first character is added an extra time shifted by 8 to avoid hashing +single-character keys (often heavily used variables) too close together. +All arithmetic on sum should ignore overflow. + +The initial probe index is then computed as sum mod the table size. +Subsequent probe indices are incr apart (mod table size), where incr +is also derived from sum, with the additional requirement that it is +relative prime to the table size (i.e., 1 <= incr < size, since the size +is a prime number). My choice for incr is somewhat arbitrary. +*/ +static dictentry *lookdict PROTO((dictobject *, char *)); +static dictentry * +lookdict(dp, key) + register dictobject *dp; + char *key; +{ + register int i, incr; + register dictentry *freeslot = NULL; + register unsigned char *p = (unsigned char *) key; + register unsigned long sum = *p << 7; + while (*p != '\0') + sum = sum + sum + *p++; + i = sum % dp->di_size; + do { + sum = sum + sum + 1; + incr = sum % dp->di_size; + } while (incr == 0); + for (;;) { + register dictentry *ep = &dp->di_table[i]; + if (ep->de_key == NULL) { + if (freeslot != NULL) + return freeslot; + else + return ep; + } + if (ep->de_key == dummy) { + if (freeslot != NULL) + freeslot = ep; + } + else if (GETSTRINGVALUE(ep->de_key)[0] == key[0]) { + if (strcmp(GETSTRINGVALUE(ep->de_key), key) == 0) { + return ep; + } + } + i = (i + incr) % dp->di_size; + } +} + +/* +Internal routine to insert a new item into the table. +Used both by the internal resize routine and by the public insert routine. +Eats a reference to key and one to value. +*/ +static void insertdict PROTO((dictobject *, stringobject *, object *)); +static void +insertdict(dp, key, value) + register dictobject *dp; + stringobject *key; + object *value; +{ + register dictentry *ep; + ep = lookdict(dp, GETSTRINGVALUE(key)); + if (ep->de_value != NULL) { + DECREF(ep->de_value); + DECREF(key); + } + else { + if (ep->de_key == NULL) + dp->di_fill++; + else + DECREF(ep->de_key); + ep->de_key = key; + dp->di_used++; + } + ep->de_value = value; +} + +/* +Restructure the table by allocating a new table and reinserting all +items again. When entries have been deleted, the new table may +actually be smaller than the old one. +*/ +static int dictresize PROTO((dictobject *)); +static int +dictresize(dp) + dictobject *dp; +{ + register int oldsize = dp->di_size; + register int newsize; + register dictentry *oldtable = dp->di_table; + register dictentry *newtable; + register dictentry *ep; + register int i; + newsize = dp->di_size; + for (i = 0; ; i++) { + if (primes[i] > dp->di_used*2) { + newsize = primes[i]; + break; + } + } + newtable = (dictentry *) calloc(sizeof(dictentry), newsize); + if (newtable == NULL) { + err_nomem(); + return -1; + } + dp->di_size = newsize; + dp->di_table = newtable; + dp->di_fill = 0; + dp->di_used = 0; + for (i = 0, ep = oldtable; i < oldsize; i++, ep++) { + if (ep->de_value != NULL) + insertdict(dp, ep->de_key, ep->de_value); + else if (ep->de_key != NULL) + DECREF(ep->de_key); + } + DEL(oldtable); + return 0; +} + +object * +dictlookup(op, key) + object *op; + char *key; +{ + if (!is_dictobject(op)) + fatal("dictlookup on non-dictionary"); + return lookdict((dictobject *)op, key) -> de_value; +} + +#ifdef NOT_USED +static object * +dict2lookup(op, key) + register object *op; + register object *key; +{ + register object *res; + if (!is_dictobject(op)) { + err_badcall(); + return NULL; + } + if (!is_stringobject(key)) { + err_badarg(); + return NULL; + } + res = lookdict((dictobject *)op, ((stringobject *)key)->ob_sval) + -> de_value; + if (res == NULL) + err_setstr(KeyError, "key not in dictionary"); + return res; +} +#endif + +static int +dict2insert(op, key, value) + register object *op; + object *key; + object *value; +{ + register dictobject *dp; + register stringobject *keyobj; + if (!is_dictobject(op)) { + err_badcall(); + return -1; + } + dp = (dictobject *)op; + if (!is_stringobject(key)) { + err_badarg(); + return -1; + } + keyobj = (stringobject *)key; + /* if fill >= 2/3 size, resize */ + if (dp->di_fill*3 >= dp->di_size*2) { + if (dictresize(dp) != 0) { + if (dp->di_fill+1 > dp->di_size) + return -1; + } + } + INCREF(keyobj); + INCREF(value); + insertdict(dp, keyobj, value); + return 0; +} + +int +dictinsert(op, key, value) + object *op; + char *key; + object *value; +{ + register object *keyobj; + register int err; + keyobj = newstringobject(key); + if (keyobj == NULL) { + err_nomem(); + return -1; + } + err = dict2insert(op, keyobj, value); + DECREF(keyobj); + return err; +} + +int +dictremove(op, key) + object *op; + char *key; +{ + register dictobject *dp; + register dictentry *ep; + if (!is_dictobject(op)) { + err_badcall(); + return -1; + } + dp = (dictobject *)op; + ep = lookdict(dp, key); + if (ep->de_value == NULL) { + err_setstr(KeyError, "key not in dictionary"); + return -1; + } + DECREF(ep->de_key); + INCREF(dummy); + ep->de_key = dummy; + DECREF(ep->de_value); + ep->de_value = NULL; + dp->di_used--; + return 0; +} + +static int +dict2remove(op, key) + object *op; + register object *key; +{ + if (!is_stringobject(key)) { + err_badarg(); + return -1; + } + return dictremove(op, GETSTRINGVALUE((stringobject *)key)); +} + +int +getdictsize(op) + register object *op; +{ + if (!is_dictobject(op)) { + err_badcall(); + return -1; + } + return ((dictobject *)op) -> di_size; +} + +static object * +getdict2key(op, i) + object *op; + register int i; +{ + /* XXX This can't return errors since its callers assume + that NULL means there was no key at that point */ + register dictobject *dp; + if (!is_dictobject(op)) { + /* err_badcall(); */ + return NULL; + } + dp = (dictobject *)op; + if (i < 0 || i >= dp->di_size) { + /* err_badarg(); */ + return NULL; + } + if (dp->di_table[i].de_value == NULL) { + /* Not an error! */ + return NULL; + } + return (object *) dp->di_table[i].de_key; +} + +char * +getdictkey(op, i) + object *op; + int i; +{ + register object *keyobj = getdict2key(op, i); + if (keyobj == NULL) + return NULL; + return GETSTRINGVALUE((stringobject *)keyobj); +} + +/* Methods */ + +static void +dict_dealloc(dp) + register dictobject *dp; +{ + register int i; + register dictentry *ep; + for (i = 0, ep = dp->di_table; i < dp->di_size; i++, ep++) { + if (ep->de_key != NULL) + DECREF(ep->de_key); + if (ep->de_value != NULL) + DECREF(ep->de_value); + } + if (dp->di_table != NULL) + DEL(dp->di_table); + DEL(dp); +} + +static void +dict_print(dp, fp, flags) + register dictobject *dp; + register FILE *fp; + register int flags; +{ + register int i; + register int any; + register dictentry *ep; + fprintf(fp, "{"); + any = 0; + for (i = 0, ep = dp->di_table; i < dp->di_size && !StopPrint; + i++, ep++) { + if (ep->de_value != NULL) { + if (any++ > 0) + fprintf(fp, "; "); + printobject((object *)ep->de_key, fp, flags); + fprintf(fp, ": "); + printobject(ep->de_value, fp, flags); + } + } + fprintf(fp, "}"); +} + +static void +js(pv, w) + object **pv; + object *w; +{ + joinstring(pv, w); + if (w != NULL) + DECREF(w); +} + +static object * +dict_repr(dp) + dictobject *dp; +{ + auto object *v; + register object *w; + object *semi, *colon; + register int i; + register int any; + register dictentry *ep; + v = newstringobject("{"); + semi = newstringobject("; "); + colon = newstringobject(": "); + any = 0; + for (i = 0, ep = dp->di_table; i < dp->di_size && !StopPrint; + i++, ep++) { + if (ep->de_value != NULL) { + if (any++) + joinstring(&v, semi); + js(&v, w = reprobject((object *)ep->de_key)); + joinstring(&v, colon); + js(&v, w = reprobject(ep->de_value)); + } + } + js(&v, w = newstringobject("}")); + if (semi != NULL) + DECREF(semi); + if (colon != NULL) + DECREF(colon); + return v; +} + +static int +dict_length(dp) + dictobject *dp; +{ + return dp->di_used; +} + +static object * +dict_subscript(dp, v) + dictobject *dp; + register object *v; +{ + if (!is_stringobject(v)) { + err_badarg(); + return NULL; + } + v = lookdict(dp, GETSTRINGVALUE((stringobject *)v)) -> de_value; + if (v == NULL) + err_setstr(KeyError, "key not in dictionary"); + else + INCREF(v); + return v; +} + +static int +dict_ass_sub(dp, v, w) + dictobject *dp; + object *v, *w; +{ + if (w == NULL) + return dict2remove((object *)dp, v); + else + return dict2insert((object *)dp, v, w); +} + +static mapping_methods dict_as_mapping = { + dict_length, /*mp_length*/ + dict_subscript, /*mp_subscript*/ + dict_ass_sub, /*mp_ass_subscript*/ +}; + +static object * +dict_keys(dp, args) + register dictobject *dp; + object *args; +{ + register object *v; + register int i, j; + if (!getnoarg(args)) + return NULL; + v = newlistobject(dp->di_used); + if (v == NULL) + return NULL; + for (i = 0, j = 0; i < dp->di_size; i++) { + if (dp->di_table[i].de_value != NULL) { + stringobject *key = dp->di_table[i].de_key; + INCREF(key); + setlistitem(v, j, (object *)key); + j++; + } + } + return v; +} + +object * +getdictkeys(dp) + object *dp; +{ + if (dp == NULL || !is_dictobject(dp)) { + err_badcall(); + return NULL; + } + return dict_keys((dictobject *)dp, (object *)NULL); +} + +static object * +dict_has_key(dp, args) + register dictobject *dp; + object *args; +{ + object *key; + register long ok; + if (!getstrarg(args, &key)) + return NULL; + ok = lookdict(dp, GETSTRINGVALUE((stringobject *)key))->de_value + != NULL; + return newintobject(ok); +} + +static struct methodlist dict_methods[] = { + {"keys", dict_keys}, + {"has_key", dict_has_key}, + {NULL, NULL} /* sentinel */ +}; + +static object * +dict_getattr(dp, name) + dictobject *dp; + char *name; +{ + return findmethod(dict_methods, (object *)dp, name); +} + +typeobject Dicttype = { + OB_HEAD_INIT(&Typetype) + 0, + "dictionary", + sizeof(dictobject), + 0, + dict_dealloc, /*tp_dealloc*/ + dict_print, /*tp_print*/ + dict_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + dict_repr, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + &dict_as_mapping, /*tp_as_mapping*/ +}; diff --git a/src/dictobject.h b/src/dictobject.h new file mode 100644 index 0000000..d665aa5 --- /dev/null +++ b/src/dictobject.h @@ -0,0 +1,44 @@ +/*********************************************************** +Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +Netherlands. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* +Dictionary object type -- mapping from char * to object. +NB: the key is given as a char *, not as a stringobject. +These functions set errno for errors. Functions dictremove() and +dictinsert() return nonzero for errors, getdictsize() returns -1, +the others NULL. A successful call to dictinsert() calls INCREF() +for the inserted item. +*/ + +extern typeobject Dicttype; + +#define is_dictobject(op) ((op)->ob_type == &Dicttype) + +extern object *newdictobject PROTO((void)); +extern object *dictlookup PROTO((object *dp, char *key)); +extern int dictinsert PROTO((object *dp, char *key, object *item)); +extern int dictremove PROTO((object *dp, char *key)); +extern int getdictsize PROTO((object *dp)); +extern char *getdictkey PROTO((object *dp, int i)); +extern object *getdictkeys PROTO((object *dp)); diff --git a/src/errcode.h b/src/errcode.h new file mode 100644 index 0000000..3324489 --- /dev/null +++ b/src/errcode.h @@ -0,0 +1,36 @@ +/*********************************************************** +Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +Netherlands. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* Error codes passed around between file input, tokenizer, parser and + interpreter. This was necessary so we can turn them into Python + exceptions at a higher level. */ + +#define E_OK 10 /* No error */ +#define E_EOF 11 /* (Unexpected) EOF read */ +#define E_INTR 12 /* Interrupted */ +#define E_TOKEN 13 /* Bad token */ +#define E_SYNTAX 14 /* Syntax error */ +#define E_NOMEM 15 /* Ran out of memory */ +#define E_DONE 16 /* Parsing complete */ +#define E_ERROR 17 /* Execution error */ diff --git a/src/errors.c b/src/errors.c new file mode 100644 index 0000000..b3e6aa3 --- /dev/null +++ b/src/errors.c @@ -0,0 +1,196 @@ +/*********************************************************** +Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +Netherlands. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* Error handling -- see also run.c */ + +/* New error handling interface. + + The following problem exists (existed): methods of built-in modules + are called with 'self' and 'args' arguments, but without a context + argument, so they have no way to raise a specific exception. + The same is true for the object implementations: no context argument. + The old convention was to set 'errno' and to return NULL. + The caller (usually call_function() in eval.c) detects the NULL + return value and then calls puterrno(ctx) to turn the errno value + into a true exception. Problems with this approach are: + - it used standard errno values to indicate Python-specific errors, + but this means that when such an error code is reported by a system + call (e.g., in module posix), the user gets a confusing message + - errno is a global variable, which makes extensions to a multi- + threading environment difficult; e.g., in IRIX, multi-threaded + programs must use the function oserror() instead of looking in errno + - there is no portable way to add new error numbers for specic + situations -- the value space for errno is reserved to the OS, yet + the way to turn module-specific errors into a module-specific + exception requires module-specific values for errno + - there is no way to add a more situation-specific message to an + error. + + The new interface solves all these problems. To return an error, a + built-in function calls err_set(exception), err_setval(exception, + value) or err_setstr(exception, string), and returns NULL. These + functions save the value for later use by puterrno(). To adapt this + scheme to a multi-threaded environment, only the implementation of + err_setval() has to be changed. +*/ + +#include "allobjects.h" + +#include +#ifndef errno +extern int errno; +#endif + +#include "errcode.h" + +extern char *strerror PROTO((int)); + +/* Last exception stored by err_setval() */ + +static object *last_exception; +static object *last_exc_val; + +void +err_setval(exception, value) + object *exception; + object *value; +{ + XDECREF(last_exception); + XINCREF(exception); + last_exception = exception; + + XDECREF(last_exc_val); + XINCREF(value); + last_exc_val = value; +} + +void +err_set(exception) + object *exception; +{ + err_setval(exception, (object *)NULL); +} + +void +err_setstr(exception, string) + object *exception; + char *string; +{ + object *value = newstringobject(string); + err_setval(exception, value); + XDECREF(value); +} + +int +err_occurred() +{ + return last_exception != NULL; +} + +void +err_get(p_exc, p_val) + object **p_exc; + object **p_val; +{ + *p_exc = last_exception; + last_exception = NULL; + *p_val = last_exc_val; + last_exc_val = NULL; +} + +void +err_clear() +{ + XDECREF(last_exception); + last_exception = NULL; + XDECREF(last_exc_val); + last_exc_val = NULL; +} + +/* Convenience functions to set a type error exception and return 0 */ + +int +err_badarg() +{ + err_setstr(TypeError, "illegal argument type for built-in operation"); + return 0; +} + +object * +err_nomem() +{ + err_set(MemoryError); + return NULL; +} + +object * +err_errno(exc) + object *exc; +{ + object *v = newtupleobject(2); + if (v != NULL) { + settupleitem(v, 0, newintobject((long)errno)); + settupleitem(v, 1, newstringobject(strerror(errno))); + } + err_setval(exc, v); + XDECREF(v); + return NULL; +} + +void +err_badcall() +{ + err_setstr(SystemError, "bad argument to internal function"); +} + +/* Set the error appropriate to the given input error code (see errcode.h) */ + +void +err_input(err) + int err; +{ + switch (err) { + case E_DONE: + case E_OK: + break; + case E_SYNTAX: + err_setstr(RuntimeError, "syntax error"); + break; + case E_TOKEN: + err_setstr(RuntimeError, "illegal token"); + break; + case E_INTR: + err_set(KeyboardInterrupt); + break; + case E_NOMEM: + err_nomem(); + break; + case E_EOF: + err_set(EOFError); + break; + default: + err_setstr(RuntimeError, "unknown input error"); + break; + } +} diff --git a/src/errors.h b/src/errors.h new file mode 100644 index 0000000..4baa142 --- /dev/null +++ b/src/errors.h @@ -0,0 +1,58 @@ +/*********************************************************** +Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +Netherlands. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* Error handling definitions */ + +void err_set PROTO((object *)); +void err_setval PROTO((object *, object *)); +void err_setstr PROTO((object *, char *)); +int err_occurred PROTO((void)); +void err_get PROTO((object **, object **)); +void err_clear PROTO((void)); + +/* Predefined exceptions */ + +extern object *RuntimeError; +extern object *EOFError; +extern object *TypeError; +extern object *MemoryError; +extern object *NameError; +extern object *SystemError; +extern object *KeyboardInterrupt; + +/* Some more planned for the future */ + +#define IndexError RuntimeError +#define KeyError RuntimeError +#define ZeroDivisionError RuntimeError +#define OverflowError RuntimeError + +/* Convenience functions */ + +extern int err_badarg PROTO((void)); +extern object *err_nomem PROTO((void)); +extern object *err_errno PROTO((object *)); +extern void err_input PROTO((int)); + +extern void err_badcall PROTO((void)); diff --git a/src/fgetsintr.c b/src/fgetsintr.c new file mode 100644 index 0000000..bda1ed8 --- /dev/null +++ b/src/fgetsintr.c @@ -0,0 +1,94 @@ +/*********************************************************** +Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +Netherlands. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* Interruptable version of fgets(). + Return < 0 for interrupted, 1 for EOF, 0 for valid input. */ + +/* XXX This uses longjmp() from a signal out of fgets(). + Should use read() instead?! */ + +#include "pgenheaders.h" + +#include +#include + +#include "errcode.h" +#include "sigtype.h" +#include "fgetsintr.h" + +#ifndef AMOEBA +#define sig_block() /*empty*/ +#define sig_unblock() /*empty*/ +#endif + +static jmp_buf jback; + +static void catcher PROTO((int)); + +static void +catcher(sig) + int sig; +{ + longjmp(jback, 1); +} + +int +fgets_intr(buf, size, fp) + char *buf; + int size; + FILE *fp; +{ + int ret; + SIGTYPE (*sigsave)(); + + if (setjmp(jback)) { + clearerr(fp); + signal(SIGINT, sigsave); +#ifdef THINK_C_3_0 + Set_Echo(1); +#endif + return E_INTR; + } + + /* The casts to (SIGTYPE(*)()) are needed by THINK_C only */ + + sigsave = signal(SIGINT, (SIGTYPE(*)()) SIG_IGN); + if (sigsave != (SIGTYPE(*)()) SIG_IGN) + signal(SIGINT, (SIGTYPE(*)()) catcher); + +#ifndef THINK_C + if (intrcheck()) + ret = E_INTR; + else +#endif + { + sig_block(); + ret = (fgets(buf, size, fp) == NULL) ? E_EOF : E_OK; + sig_unblock(); + } + + if (sigsave != (SIGTYPE(*)()) SIG_IGN) + signal(SIGINT, (SIGTYPE(*)()) sigsave); + return ret; +} diff --git a/src/fgetsintr.h b/src/fgetsintr.h new file mode 100644 index 0000000..87f1d2a --- /dev/null +++ b/src/fgetsintr.h @@ -0,0 +1,25 @@ +/*********************************************************** +Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +Netherlands. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +extern int fgets_intr PROTO((char *, int, FILE *)); diff --git a/src/fileobject.c b/src/fileobject.c new file mode 100644 index 0000000..640e27b --- /dev/null +++ b/src/fileobject.c @@ -0,0 +1,293 @@ +/*********************************************************** +Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +Netherlands. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyrig