Initial revision
This commit is contained in:
parent
c636014c43
commit
85a5fbbdfe
|
@ -0,0 +1,71 @@
|
|||
# Grammar for Python, version 3
|
||||
|
||||
# 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.
|
||||
# TO DO:
|
||||
# replace 'dir' by something more general?
|
||||
|
||||
# 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 | dir_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
|
||||
dir_stmt: 'dir' [expr] 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: '(' [exprlist] ')' | '[' 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] ')'
|
|
@ -0,0 +1 @@
|
|||
#define assert(e) { if (!(e)) { printf("Assertion failed\n"); abort(); } }
|
|
@ -0,0 +1,22 @@
|
|||
/* 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)
|
|
@ -0,0 +1,15 @@
|
|||
/* 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));
|
|
@ -0,0 +1,20 @@
|
|||
/* 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((node *, object *, object *));
|
||||
extern object *newclassmemberobject PROTO((object *));
|
||||
extern object *newclassmethodobject PROTO((object *, object *));
|
||||
|
||||
extern object *classmethodgetfunc PROTO((object *));
|
||||
extern object *classmethodgetself PROTO((object *));
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
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));
|
||||
|
||||
/* New interface with (string)object * instead of char * arguments */
|
||||
extern object *dict2lookup PROTO((object *dp, object *key));
|
||||
extern int dict2insert PROTO((object *dp, object *key, object *item));
|
||||
extern int dict2remove PROTO((object *dp, object *key));
|
||||
extern object *getdict2key PROTO((object *dp, int i));
|
|
@ -0,0 +1,12 @@
|
|||
/* 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 */
|
|
@ -0,0 +1,17 @@
|
|||
/* 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 (in run.c) */
|
||||
object *RuntimeError; /* Raised by error() */
|
||||
object *EOFError; /* Raised by eof_error() */
|
||||
object *TypeError; /* Rased by type_error() */
|
||||
object *MemoryError; /* Raised by mem_error() */
|
||||
object *NameError; /* Raised by name_error() */
|
||||
object *SystemError; /* Raised by sys_error() */
|
||||
object *KeyboardInterrupt; /* Raised by intr_error() */
|
|
@ -0,0 +1,9 @@
|
|||
/* File object interface */
|
||||
|
||||
extern typeobject Filetype;
|
||||
|
||||
#define is_fileobject(op) ((op)->ob_type == &Filetype)
|
||||
|
||||
extern object *newfileobject PROTO((char *, char *));
|
||||
extern object *newopenfileobject PROTO((FILE *, char *, char *));
|
||||
extern FILE *getfilefile PROTO((object *));
|
|
@ -0,0 +1,20 @@
|
|||
/* Float object interface */
|
||||
|
||||
/*
|
||||
floatobject represents a (double precision) floating point number.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
OB_HEAD
|
||||
double ob_fval;
|
||||
} floatobject;
|
||||
|
||||
extern typeobject Floattype;
|
||||
|
||||
#define is_floatobject(op) ((op)->ob_type == &Floattype)
|
||||
|
||||
extern object *newfloatobject PROTO((double));
|
||||
extern double getfloatvalue PROTO((object *));
|
||||
|
||||
/* Macro, trading safety for speed */
|
||||
#define GETFLOATVALUE(op) ((op)->ob_fval)
|
|
@ -0,0 +1,9 @@
|
|||
/* Function object interface */
|
||||
|
||||
extern typeobject Functype;
|
||||
|
||||
#define is_funcobject(op) ((op)->ob_type == &Functype)
|
||||
|
||||
extern object *newfuncobject PROTO((node *, object *));
|
||||
extern node *getfuncnode PROTO((object *));
|
||||
extern object *getfuncglobals PROTO((object *));
|
|
@ -0,0 +1,43 @@
|
|||
#define single_input 256
|
||||
#define file_input 257
|
||||
#define expr_input 258
|
||||
#define eval_input 259
|
||||
#define funcdef 260
|
||||
#define parameters 261
|
||||
#define fplist 262
|
||||
#define fpdef 263
|
||||
#define stmt 264
|
||||
#define simple_stmt 265
|
||||
#define expr_stmt 266
|
||||
#define print_stmt 267
|
||||
#define del_stmt 268
|
||||
#define dir_stmt 269
|
||||
#define pass_stmt 270
|
||||
#define flow_stmt 271
|
||||
#define break_stmt 272
|
||||
#define return_stmt 273
|
||||
#define raise_stmt 274
|
||||
#define import_stmt 275
|
||||
#define compound_stmt 276
|
||||
#define if_stmt 277
|
||||
#define while_stmt 278
|
||||
#define for_stmt 279
|
||||
#define try_stmt 280
|
||||
#define except_clause 281
|
||||
#define suite 282
|
||||
#define test 283
|
||||
#define and_test 284
|
||||
#define not_test 285
|
||||
#define comparison 286
|
||||
#define comp_op 287
|
||||
#define expr 288
|
||||
#define term 289
|
||||
#define factor 290
|
||||
#define atom 291
|
||||
#define trailer 292
|
||||
#define subscript 293
|
||||
#define exprlist 294
|
||||
#define testlist 295
|
||||
#define classdef 296
|
||||
#define baselist 297
|
||||
#define arguments 298
|
|
@ -0,0 +1,78 @@
|
|||
/* Grammar interface */
|
||||
|
||||
#include "bitset.h" /* Sigh... */
|
||||
|
||||
/* A label of an arc */
|
||||
|
||||
typedef struct _label {
|
||||
int lb_type;
|
||||
char *lb_str;
|
||||
} label;
|
||||
|
||||
#define EMPTY 0 /* Label number 0 is by definition the empty label */
|
||||
|
||||
/* A list of labels */
|
||||
|
||||
typedef struct _labellist {
|
||||
int ll_nlabels;
|
||||
label *ll_label;
|
||||
} labellist;
|
||||
|
||||
/* An arc from one state to another */
|
||||
|
||||
typedef struct _arc {
|
||||
short a_lbl; /* Label of this arc */
|
||||
short a_arrow; /* State where this arc goes to */
|
||||
} arc;
|
||||
|
||||
/* A state in a DFA */
|
||||
|
||||
typedef struct _state {
|
||||
int s_narcs;
|
||||
arc *s_arc; /* Array of arcs */
|
||||
|
||||
/* Optional accelerators */
|
||||
int s_lower; /* Lowest label index */
|
||||
int s_upper; /* Highest label index */
|
||||
int *s_accel; /* Accelerator */
|
||||
int s_accept; /* Nonzero for accepting state */
|
||||
} state;
|
||||
|
||||
/* A DFA */
|
||||
|
||||
typedef struct _dfa {
|
||||
int d_type; /* Non-terminal this represents */
|
||||
char *d_name; /* For printing */
|
||||
int d_initial; /* Initial state */
|
||||
int d_nstates;
|
||||
state *d_state; /* Array of states */
|
||||
bitset d_first;
|
||||
} dfa;
|
||||
|
||||
/* A grammar */
|
||||
|
||||
typedef struct _grammar {
|
||||
int g_ndfas;
|
||||
dfa *g_dfa; /* Array of DFAs */
|
||||
labellist g_ll;
|
||||
int g_start; /* Start symbol of the grammar */
|
||||
int g_accel; /* Set if accelerators present */
|
||||
} grammar;
|
||||
|
||||
/* FUNCTIONS */
|
||||
|
||||
grammar *newgrammar PROTO((int start));
|
||||
dfa *adddfa PROTO((grammar *g, int type, char *name));
|
||||
int addstate PROTO((dfa *d));
|
||||
void addarc PROTO((dfa *d, int from, int to, int lbl));
|
||||
dfa *finddfa PROTO((grammar *g, int type));
|
||||
char *typename PROTO((grammar *g, int lbl));
|
||||
|
||||
int addlabel PROTO((labellist *ll, int type, char *str));
|
||||
int findlabel PROTO((labellist *ll, int type, char *str));
|
||||
char *labelrepr PROTO((label *lb));
|
||||
void translatelabels PROTO((grammar *g));
|
||||
|
||||
void addfirstsets PROTO((grammar *g));
|
||||
|
||||
void addaccellerators PROTO((grammar *g));
|
|
@ -0,0 +1,7 @@
|
|||
/* Module definition and import interface */
|
||||
|
||||
void init_modules PROTO(());
|
||||
void close_modules PROTO(());
|
||||
object *new_module PROTO((char *name));
|
||||
void define_module PROTO((struct _context *ctx, char *name));
|
||||
object *import_module PROTO((struct _context *ctx, char *name));
|
|
@ -0,0 +1,48 @@
|
|||
/* Integer object interface */
|
||||
|
||||
/*
|
||||
123456789-123456789-123456789-123456789-123456789-123456789-123456789-12
|
||||
|
||||
intobject represents a (long) integer. This is an immutable object;
|
||||
an integer cannot change its value after creation.
|
||||
|
||||
There are functions to create new integer objects, to test an object
|
||||
for integer-ness, and to get the integer value. The latter functions
|
||||
returns -1 and sets errno to EBADF if the object is not an intobject.
|
||||
None of the functions should be applied to nil objects.
|
||||
|
||||
The type intobject is (unfortunately) exposed bere so we can declare
|
||||
TrueObject and FalseObject below; don't use this.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
OB_HEAD
|
||||
long ob_ival;
|
||||
} intobject;
|
||||
|
||||
extern typeobject Inttype;
|
||||
|
||||
#define is_intobject(op) ((op)->ob_type == &Inttype)
|
||||
|
||||
extern object *newintobject PROTO((long));
|
||||
extern long getintvalue PROTO((object *));
|
||||
|
||||
|
||||
/*
|
||||
123456789-123456789-123456789-123456789-123456789-123456789-123456789-12
|
||||
|
||||
False and True are special intobjects used by Boolean expressions.
|
||||
All values of type Boolean must point to either of these; but in
|
||||
contexts where integers are required they are integers (valued 0 and 1).
|
||||
Hope these macros don't conflict with other people's.
|
||||
|
||||
Don't forget to apply INCREF() when returning True or False!!!
|
||||
*/
|
||||
|
||||
extern intobject FalseObject, TrueObject; /* Don't use these directly */
|
||||
|
||||
#define False ((object *) &FalseObject)
|
||||
#define True ((object *) &TrueObject)
|
||||
|
||||
/* Macro, trading safety for speed */
|
||||
#define GETINTVALUE(op) ((op)->ob_ival)
|
|
@ -0,0 +1,26 @@
|
|||
/* List object interface */
|
||||
|
||||
/*
|
||||
123456789-123456789-123456789-123456789-123456789-123456789-123456789-12
|
||||
|
||||
Another generally useful object type is an list of object pointers.
|
||||
This is a mutable type: the list items can be changed, and items can be
|
||||
added or removed. Out-of-range indices or non-list objects are ignored.
|
||||
|
||||
*** WARNING *** setlistitem does not increment the new item's reference
|
||||
count, but does decrement the reference count of the item it replaces,
|
||||
if not nil. It does *decrement* the reference count if it is *not*
|
||||
inserted in the list. Similarly, getlistitem does not increment the
|
||||
returned item's reference count.
|
||||
*/
|
||||
|
||||
extern typeobject Listtype;
|
||||
|
||||
#define is_listobject(op) ((op)->ob_type == &Listtype)
|
||||
|
||||
extern object *newlistobject PROTO((int size));
|
||||
extern int getlistsize PROTO((object *));
|
||||
extern object *getlistitem PROTO((object *, int));
|
||||
extern int setlistitem PROTO((object *, int, object *));
|
||||
extern int inslistitem PROTO((object *, int, object *));
|
||||
extern int addlistitem PROTO((object *, object *));
|
|
@ -0,0 +1,6 @@
|
|||
#define MSTART 256
|
||||
#define RULE 257
|
||||
#define RHS 258
|
||||
#define ALT 259
|
||||
#define ITEM 260
|
||||
#define ATOM 261
|
|
@ -0,0 +1,11 @@
|
|||
/* Method object interface */
|
||||
|
||||
extern typeobject Methodtype;
|
||||
|
||||
#define is_methodobject(op) ((op)->ob_type == &Methodtype)
|
||||
|
||||
typedef object *(*method) FPROTO((object *, object *));
|
||||
|
||||
extern object *newmethodobject PROTO((char *, method, object *));
|
||||
extern method getmethod PROTO((object *));
|
||||
extern object *getself PROTO((object *));
|
|
@ -0,0 +1,11 @@
|
|||
/* Module support interface */
|
||||
|
||||
struct methodlist {
|
||||
char *ml_name;
|
||||
method ml_meth;
|
||||
};
|
||||
|
||||
extern object *findmethod PROTO((struct methodlist *, object *, char *));
|
||||
extern object *initmodule PROTO((char *, struct methodlist *));
|
||||
extern int err_badargs PROTO((void));
|
||||
extern object *err_nomem PROTO((void));
|
|
@ -0,0 +1,9 @@
|
|||
/* Module object interface */
|
||||
|
||||
extern typeobject Moduletype;
|
||||
|
||||
#define is_moduleobject(op) ((op)->ob_type == &Moduletype)
|
||||
|
||||
extern object *newmoduleobject PROTO((char *));
|
||||
extern object *getmoduledict PROTO((object *));
|
||||
extern int setmoduledict PROTO((object *, object *));
|
|
@ -0,0 +1,29 @@
|
|||
/* Parse tree node interface */
|
||||
|
||||
typedef struct _node {
|
||||
int n_type;
|
||||
char *n_str;
|
||||
int n_nchildren;
|
||||
struct _node *n_child;
|
||||
} node;
|
||||
|
||||
extern node *newnode PROTO((int type));
|
||||
extern node *addchild PROTO((node *n, int type, char *str));
|
||||
|
||||
/* Node access functions */
|
||||
#define NCH(n) ((n)->n_nchildren)
|
||||
#define CHILD(n, i) (&(n)->n_child[i])
|
||||
#define TYPE(n) ((n)->n_type)
|
||||
#define STR(n) ((n)->n_str)
|
||||
|
||||
/* Assert that the type of a node is what we expect */
|
||||
#ifndef DEBUG
|
||||
#define REQ(n, type) { /*pass*/ ; }
|
||||
#else
|
||||
#define REQ(n, type) \
|
||||
{ if (TYPE(n) != (type)) { \
|
||||
fprintf(stderr, "FATAL: node type %d, required %d\n", \
|
||||
TYPE(n), type); \
|
||||
abort(); \
|
||||
} }
|
||||
#endif
|
|
@ -0,0 +1,310 @@
|
|||
/* Object and type object interface */
|
||||
|
||||
/*
|
||||
123456789-123456789-123456789-123456789-123456789-123456789-123456789-12
|
||||
|
||||
Objects are structures allocated on the heap. Special rules apply to
|
||||
the use of objects to ensure they are properly garbage-collected.
|
||||
Objects are never allocated statically or on the stack; they must be
|
||||
accessed through special macros and functions only. (Type objects are
|
||||
exceptions to the first rule; the standard types are represented by
|
||||
statically initialized type objects.)
|
||||
|
||||
An object has a 'reference count' that is increased or decreased when a
|
||||
pointer to the object is copied or deleted; when the reference count
|
||||
reaches zero there are no references to the object left and it can be
|
||||
removed from the heap.
|
||||
|
||||
An object has a 'type' that determines what it represents and what kind
|
||||
of data it contains. An object's type is fixed when it is created.
|
||||
Types themselves are represented as objects; an object contains a
|
||||
pointer to the corresponding type object. The type itself has a type
|
||||
pointer pointing to the object representing the type 'type', which
|
||||
contains a pointer to itself!).
|
||||
|
||||
Objects do not float around in memory; once allocated an object keeps
|
||||
the same size and address. Objects that must hold variable-size data
|
||||
can contain pointers to variable-size parts of the object. Not all
|
||||
objects of the same type have the same size; but the size cannot change
|
||||
after allocation. (These restrictions are made so a reference to an
|
||||
object can be simply a pointer -- moving an object would require
|
||||
updating all the pointers, and changing an object's size would require
|
||||
moving it if there was another object right next to it.)
|
||||
|
||||
Objects are always accessed through pointers of the type 'object *'.
|
||||
The type 'object' is a structure that only contains the reference count
|
||||
and the type pointer. The actual memory allocated for an object
|
||||
contains other data that can only be accessed after casting the pointer
|
||||
to a pointer to a longer structure type. This longer type must start
|
||||
with the reference count and type fields; the macro OB_HEAD should be
|
||||
used for this (to accomodate for future changes). The implementation
|
||||
of a particular object type can cast the object pointer to the proper
|
||||
type and back.
|
||||
|
||||
A standard interface exists for objects that contain an array of items
|
||||
whose size is determined when the object is allocated.
|
||||
|
||||
123456789-123456789-123456789-123456789-123456789-123456789-123456789-12
|
||||
*/
|
||||
|
||||
#ifdef THINK_C
|
||||
/* Debugging options for THINK_C (which has no -D compiler option): */
|
||||
/*#define TRACE_REFS*/
|
||||
/*#define REF_DEBUG*/
|
||||
#endif
|
||||
|
||||
#ifdef TRACE_REFS
|
||||
#define OB_HEAD \
|
||||
struct _object *_ob_next, *_ob_prev; \
|
||||
unsigned int ob_refcnt; \
|
||||
struct _typeobject *ob_type;
|
||||
#define OB_HEAD_INIT(type) 0, 0, 1, type,
|
||||
#else
|
||||
#define OB_HEAD \
|
||||
unsigned int ob_refcnt; \
|
||||
struct _typeobject *ob_type;
|
||||
#define OB_HEAD_INIT(type) 1, type,
|
||||
#endif
|
||||
|
||||
#define OB_VARHEAD \
|
||||
OB_HEAD \
|
||||
unsigned int ob_size; /* Number of items in variable part */
|
||||
|
||||
typedef struct _object {
|
||||
OB_HEAD
|
||||
} object;
|
||||
|
||||
typedef struct {
|
||||
OB_VARHEAD
|
||||
} varobject;
|
||||
|
||||
|
||||
/*
|
||||
123456789-123456789-123456789-123456789-123456789-123456789-123456789-12
|
||||
|
||||
Type objects contain a string containing the type name (to help somewhat
|
||||
in debugging), the allocation parameters (see newobj() and newvarobj()),
|
||||
and methods for accessing objects of the type. Methods are optional,a
|
||||
nil pointer meaning that particular kind of access is not available for
|
||||
this type. The DECREF() macro uses the tp_dealloc method without
|
||||
checking for a nil pointer; it should always be implemented except if
|
||||
the implementation can guarantee that the reference count will never
|
||||
reach zero (e.g., for type objects).
|
||||
|
||||
NB: the methods for certain type groups are now contained in separate
|
||||
method blocks.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
object *(*nb_add) FPROTO((object *, object *));
|
||||
object *(*nb_subtract) FPROTO((object *, object *));
|
||||
object *(*nb_multiply) FPROTO((object *, object *));
|
||||
object *(*nb_divide) FPROTO((object *, object *));
|
||||
object *(*nb_remainder) FPROTO((object *, object *));
|
||||
object *(*nb_power) FPROTO((object *, object *));
|
||||
object *(*nb_negative) FPROTO((object *));
|
||||
object *(*nb_positive) FPROTO((object *));
|
||||
} number_methods;
|
||||
|
||||
typedef struct {
|
||||
int (*sq_length) FPROTO((object *));
|
||||
object *(*sq_concat) FPROTO((object *, object *));
|
||||
object *(*sq_repeat) FPROTO((object *, int));
|
||||
object *(*sq_item) FPROTO((object *, int));
|
||||
object *(*sq_slice) FPROTO((object *, int, int));
|
||||
int (*sq_ass_item) FPROTO((object *, int, object *));
|
||||
int (*sq_ass_slice) FPROTO((object *, int, int, object *));
|
||||
} sequence_methods;
|
||||
|
||||
typedef struct {
|
||||
int (*mp_length) FPROTO((object *));
|
||||
object *(*mp_subscript) FPROTO((object *, object *));
|
||||
int (*mp_ass_subscript) FPROTO((object *, object *, object *));
|
||||
} mapping_methods;
|
||||
|
||||
typedef struct _typeobject {
|
||||
OB_VARHEAD
|
||||
char *tp_name; /* For printing */
|
||||
unsigned int tp_basicsize, tp_itemsize; /* For allocation */
|
||||
|
||||
/* Methods to implement standard operations */
|
||||
|
||||
void (*tp_dealloc) FPROTO((object *));
|
||||
void (*tp_print) FPROTO((object *, FILE *, int));
|
||||
object *(*tp_getattr) FPROTO((object *, char *));
|
||||
int (*tp_setattr) FPROTO((object *, char *, object *));
|
||||
int (*tp_compare) FPROTO((object *, object *));
|
||||
object *(*tp_repr) FPROTO((object *));
|
||||
|
||||
/* Method suites for standard classes */
|
||||
|
||||
number_methods *tp_as_number;
|
||||
sequence_methods *tp_as_sequence;
|
||||
mapping_methods *tp_as_mapping;
|
||||
} typeobject;
|
||||
|
||||
extern typeobject Typetype; /* The type of type objects */
|
||||
|
||||
#define is_typeobject(op) ((op)->ob_type == &Typetype)
|
||||
|
||||
extern void printobject PROTO((object *, FILE *, int));
|
||||
extern object * reprobject PROTO((object *));
|
||||
extern int cmpobject PROTO((object *, object *));
|
||||
|
||||
/* Flag bits for printing: */
|
||||
#define PRINT_RAW 1 /* No string quotes etc. */
|
||||
|
||||
/*
|
||||
123456789-123456789-123456789-123456789-123456789-123456789-123456789-12
|
||||
|
||||
The macros INCREF(op) and DECREF(op) are used to increment or decrement
|
||||
reference counts. DECREF calls the object's deallocator function; for
|
||||
objects that don't contain references to other objects or heap memory
|
||||
this can be the standard function free(). Both macros can be used
|
||||
whereever a void expression is allowed. The argument shouldn't be a
|
||||
NIL pointer. The macro NEWREF(op) is used only to initialize reference
|
||||
counts to 1; it is defined here for convenience.
|
||||
|
||||
We assume that the reference count field can never overflow; this can
|
||||
be proven when the size of the field is the same as the pointer size
|
||||
but even with a 16-bit reference count field it is pretty unlikely so
|
||||
we ignore the possibility. (If you are paranoid, make it a long.)
|
||||
|
||||
Type objects should never be deallocated; the type pointer in an object
|
||||
is not considered to be a reference to the type object, to save
|
||||
complications in the deallocation function. (This is actually a
|
||||
decision that's up to the implementer of each new type so if you want,
|
||||
you can count such references to the type object.)
|
||||
|
||||
*** WARNING*** The DECREF macro must have a side-effect-free argument
|
||||
since it may evaluate its argument multiple times. (The alternative
|
||||
would be to mace it a proper function or assign it to a global temporary
|
||||
variable first, both of which are slower; and in a multi-threaded
|
||||
environment the global variable trick is not safe.)
|
||||
*/
|
||||
|
||||
#ifdef TRACE_REFS
|
||||
#ifndef REF_DEBUG
|
||||
#define REF_DEBUG
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef TRACE_REFS
|
||||
#define DELREF(op) (*(op)->ob_type->tp_dealloc)((object *)(op))
|
||||
#endif
|
||||
|
||||
#ifdef REF_DEBUG
|
||||
extern long ref_total;
|
||||
#ifndef TRACE_REFS
|
||||
#define NEWREF(op) (ref_total++, (op)->ob_refcnt = 1)
|
||||
#endif
|
||||
#define INCREF(op) (ref_total++, (op)->ob_refcnt++)
|
||||
#define DECREF(op) \
|
||||
if (--ref_total, --(op)->ob_refcnt != 0) \
|
||||
; \
|
||||
else \
|
||||
DELREF(op)
|
||||
#else
|
||||
#define NEWREF(op) ((op)->ob_refcnt = 1)
|
||||
#define INCREF(op) ((op)->ob_refcnt++)
|
||||
#define DECREF(op) \
|
||||
if (--(op)->ob_refcnt != 0) \
|
||||
; \
|
||||
else \
|
||||
DELREF(op)
|
||||
#endif
|
||||
|
||||
|
||||
/* Definition of NULL, so you don't have to include <stdio.h> */
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
NoObject is an object of undefined type which can be used in contexts
|
||||
where NULL (nil) is not suitable (since NULL often means 'error').
|
||||
|
||||
Don't forget to apply INCREF() when returning this value!!!
|
||||
*/
|
||||
|
||||
extern object NoObject; /* Don't use this directly */
|
||||
|
||||
#define None (&NoObject)
|
||||
|
||||
|
||||
/*
|
||||
123456789-123456789-123456789-123456789-123456789-123456789-123456789-12
|
||||
|
||||
More conventions
|
||||
================
|
||||
|
||||
Argument Checking
|
||||
-----------------
|
||||
|
||||
Functions that take objects as arguments normally don't check for nil
|
||||
arguments, but they do check the type of the argument, and return an
|
||||
error if the function doesn't apply to the type.
|
||||
|
||||
Failure Modes
|
||||
-------------
|
||||
|
||||
Functions may fail for a variety of reasons, including running out of
|
||||
memory. This is communicated to the caller in two ways: 'errno' is set
|
||||
to indicate the error, and the function result differs: functions that
|
||||
normally return a pointer return nil for failure, functions returning
|
||||
an integer return -1 (which can be a legal return value too!), and
|
||||
other functions return 0 for success and the error number for failure.
|
||||
Callers should always check for errors before using the result. The
|
||||
following error codes are used:
|
||||
|
||||
EBADF bad object type (first argument only)
|
||||
EINVAL bad argument type (second and further arguments)
|
||||
ENOMEM no memory (malloc failed)
|
||||
ENOENT key not found in dictionary
|
||||
EDOM index out of range or division by zero
|
||||
ERANGE result not representable
|
||||
|
||||
XXX any others?
|
||||
|
||||
Reference Counts
|
||||
----------------
|
||||
|
||||
It takes a while to get used to the proper usage of reference counts.
|
||||
|
||||
Functions that create an object set the reference count to 1; such new
|
||||
objects must be stored somewhere or destroyed again with DECREF().
|
||||
Functions that 'store' objects such as settupleitem() and dictinsert()
|
||||
don't increment the reference count of the object, since the most
|
||||
frequent use is to store a fresh object. Functions that 'retrieve'
|
||||
objects such as gettupleitem() and dictlookup() also don't increment
|
||||
the reference count, since most frequently the object is only looked at
|
||||
quickly. Thus, to retrieve an object and store it again, the caller
|
||||
must call INCREF() explicitly.
|
||||
|
||||
NOTE: functions that 'consume' a reference count like dictinsert() even
|
||||
consume the reference if the object wasn't stored, to simplify error
|
||||
handling.
|
||||
|
||||
It seems attractive to make other functions that take an object as
|
||||
argument consume a reference count; however this may quickly get
|
||||
confusing (even the current practice is already confusing). Consider
|
||||
it carefully, it may safe lots of calls to INCREF() and DECREF() at
|
||||
times.
|
||||
|
||||
123456789-123456789-123456789-123456789-123456789-123456789-123456789-12
|
||||
*/
|
||||
|
||||
/* Error number interface */
|
||||
#include <errno.h>
|
||||
|
||||
#ifndef errno
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
#ifdef THINK_C
|
||||
/* Lightspeed C doesn't define these in <errno.h> */
|
||||
#define EDOM 33
|
||||
#define ERANGE 34
|
||||
#endif
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
123456789-123456789-123456789-123456789-123456789-123456789-123456789-12
|
||||
|
||||
Additional macros for modules that implement new object types.
|
||||
You must first include "object.h".
|
||||
|
||||
NEWOBJ(type, typeobj) allocates memory for a new object of the given
|
||||
type; here 'type' must be the C structure type used to represent the
|
||||
object and 'typeobj' the address of the corresponding type object.
|
||||
Reference count and type pointer are filled in; the rest of the bytes of
|
||||
the object are *undefined*! The resulting expression type is 'type *'.
|
||||
The size of the object is actually determined by the tp_basicsize field
|
||||
of the type object.
|
||||
|
||||
NEWVAROBJ(type, typeobj, n) is similar but allocates a variable-size
|
||||
object with n extra items. The size is computer as tp_basicsize plus
|
||||
n * tp_itemsize. This fills in the ob_size field as well.
|
||||
*/
|
||||
|
||||
extern object *newobject PROTO((typeobject *));
|
||||
extern varobject *newvarobject PROTO((typeobject *, unsigned int));
|
||||
|
||||
#define NEWOBJ(type, typeobj) ((type *) newobject(typeobj))
|
||||
#define NEWVAROBJ(type, typeobj, n) ((type *) newvarobject(typeobj, n))
|
||||
|
||||
extern int StopPrint; /* Set when printing is interrupted */
|
||||
|
||||
/* Malloc interface */
|
||||
#include "malloc.h"
|
||||
|
||||
extern char *strdup PROTO((char *));
|
|
@ -0,0 +1,9 @@
|
|||
/* Parser-tokenizer link interface */
|
||||
|
||||
#if 0
|
||||
extern int parsetok PROTO((struct tok_state *, grammar *, int start,
|
||||
node **n_ret));
|
||||
#endif
|
||||
extern int parsestring PROTO((char *, grammar *, int start, node **n_ret));
|
||||
extern int parsefile PROTO((FILE *, grammar *, int start,
|
||||
char *ps1, char *ps2, node **n_ret));
|
|
@ -0,0 +1,17 @@
|
|||
/* 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 (in run.c) */
|
||||
object *RuntimeError; /* Raised by error() */
|
||||
object *EOFError; /* Raised by eof_error() */
|
||||
object *TypeError; /* Rased by type_error() */
|
||||
object *MemoryError; /* Raised by mem_error() */
|
||||
object *NameError; /* Raised by name_error() */
|
||||
object *SystemError; /* Raised by sys_error() */
|
||||
object *KeyboardInterrupt; /* Raised by intr_error() */
|
|
@ -0,0 +1,39 @@
|
|||
/* String object interface */
|
||||
|
||||
/*
|
||||
123456789-123456789-123456789-123456789-123456789-123456789-123456789-12
|
||||
|
||||
Type stringobject represents a character string. An extra zero byte is
|
||||
reserved at the end to ensure it is zero-terminated, but a size is
|
||||
present so strings with null bytes in them can be represented. This
|
||||
is an immutable object type.
|
||||
|
||||
There are functions to create new string objects, to test
|
||||
an object for string-ness, and to get the
|
||||
string value. The latter function returns a null pointer
|
||||
if the object is not of the proper type.
|
||||
There is a variant that takes an explicit size as well as a
|
||||
variant that assumes a zero-terminated string. Note that none of the
|
||||
functions should be applied to nil objects.
|
||||
*/
|
||||
|
||||
/* NB The type is revealed here only because it is used in dictobject.c */
|
||||
|
||||
typedef struct {
|
||||
OB_VARHEAD
|
||||
char ob_sval[1];
|
||||
} stringobject;
|
||||
|
||||
extern typeobject Stringtype;
|
||||
|
||||
#define is_stringobject(op) ((op)->ob_type == &Stringtype)
|
||||
|
||||
extern object *newsizedstringobject PROTO((char *, int));
|
||||
extern object *newstringobject PROTO((char *));
|
||||
extern unsigned int getstringsize PROTO((object *));
|
||||
extern char *getstringvalue PROTO((object *));
|
||||
extern void joinstring PROTO((object **, object *));
|
||||
extern int resizestring PROTO((object **, int));
|
||||
|
||||
/* Macro, trading safety for speed */
|
||||
#define GETSTRINGVALUE(op) ((op)->ob_sval)
|
|
@ -0,0 +1,6 @@
|
|||
/* System module interface */
|
||||
|
||||
object *sysget PROTO((char *));
|
||||
int sysset PROTO((char *, object *));
|
||||
FILE *sysgetfile PROTO((char *, FILE *));
|
||||
void initsys PROTO((int, char **));
|
|
@ -0,0 +1,45 @@
|
|||
/* Token types */
|
||||
|
||||
#define ENDMARKER 0
|
||||
#define NAME 1
|
||||
#define NUMBER 2
|
||||
#define STRING 3
|
||||
#define NEWLINE 4
|
||||
#define INDENT 5
|
||||
#define DEDENT 6
|
||||
#define LPAR 7
|
||||
#define RPAR 8
|
||||
#define LSQB 9
|
||||
#define RSQB 10
|
||||
#define COLON 11
|
||||
#define COMMA 12
|
||||
#define SEMI 13
|
||||
#define PLUS 14
|
||||
#define MINUS 15
|
||||
#define STAR 16
|
||||
#define SLASH 17
|
||||
#define VBAR 18
|
||||
#define AMPER 19
|
||||
#define LESS 20
|
||||
#define GREATER 21
|
||||
#define EQUAL 22
|
||||
#define DOT 23
|
||||
#define PERCENT 24
|
||||
#define BACKQUOTE 25
|
||||
#define LBRACE 26
|
||||
#define RBRACE 27
|
||||
#define OP 28
|
||||
#define ERRORTOKEN 29
|
||||
#define N_TOKENS 30
|
||||
|
||||
/* Special definitions for cooperation with parser */
|
||||
|
||||
#define NT_OFFSET 256
|
||||
|
||||
#define ISTERMINAL(x) ((x) < NT_OFFSET)
|
||||
#define ISNONTERMINAL(x) ((x) >= NT_OFFSET)
|
||||
#define ISEOF(x) ((x) == ENDMARKER)
|
||||
|
||||
|
||||
extern char *tok_name[]; /* Token names */
|
||||
extern int tok_1char PROTO((int));
|
|
@ -0,0 +1,24 @@
|
|||
/* Tuple object interface */
|
||||
|
||||
/*
|
||||
123456789-123456789-123456789-123456789-123456789-123456789-123456789-12
|
||||
|
||||
Another generally useful object type is an tuple of object pointers.
|
||||
This is a mutable type: the tuple items can be changed (but not their
|
||||
number). Out-of-range indices or non-tuple objects are ignored.
|
||||
|
||||
*** WARNING *** settupleitem does not increment the new item's reference
|
||||
count, but does decrement the reference count of the item it replaces,
|
||||
if not nil. It does *decrement* the reference count if it is *not*
|
||||
inserted in the tuple. Similarly, gettupleitem does not increment the
|
||||
returned item's reference count.
|
||||
*/
|
||||
|
||||
extern typeobject Tupletype;
|
||||
|
||||
#define is_tupleobject(op) ((op)->ob_type == &Tupletype)
|
||||
|
||||
extern object *newtupleobject PROTO((int size));
|
||||
extern int gettuplesize PROTO((object *));
|
||||
extern object *gettupleitem PROTO((object *, int));
|
||||
extern int settupleitem PROTO((object *, int, object *));
|
|
@ -0,0 +1,458 @@
|
|||
# Python script to parse cstubs file for gl and generate C stubs.
|
||||
# usage: python cgen <cstubs >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[:1] in digits:
|
||||
n = n + s[:1]
|
||||
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 mknew<type>object(<arg>)
|
||||
#
|
||||
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 '%%'.
|
||||
# <part1> -- literally copied to stdout
|
||||
# <part2> -- 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 '}'
|
|
@ -0,0 +1,369 @@
|
|||
/* Functions used by cgen output */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#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();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
/* 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));
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,167 @@
|
|||
/* Math module -- standard C math library functions, pi and e */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "PROTO.h"
|
||||
#include "object.h"
|
||||
#include "intobject.h"
|
||||
#include "tupleobject.h"
|
||||
#include "floatobject.h"
|
||||
#include "dictobject.h"
|
||||
#include "methodobject.h"
|
||||
#include "moduleobject.h"
|
||||
#include "objimpl.h"
|
||||
#include "import.h"
|
||||
#include "modsupport.h"
|
||||
|
||||
static int
|
||||
getdoublearg(args, px)
|
||||
register object *args;
|
||||
double *px;
|
||||
{
|
||||
if (args == NULL)
|
||||
return err_badarg();
|
||||
if (is_floatobject(args)) {
|
||||
*px = getfloatvalue(args);
|
||||
return 1;
|
||||
}
|
||||
if (is_intobject(args)) {
|
||||
*px = getintvalue(args);
|
||||
return 1;
|
||||
}
|
||||
return err_badarg();
|
||||
}
|
||||
|
||||
static int
|
||||
get2doublearg(args, px, py)
|
||||
register object *args;
|
||||
double *px, *py;
|
||||
{
|
||||
if (args == NULL || !is_tupleobject(args) || gettuplesize(args) != 2)
|
||||
return err_badarg();
|
||||
return getdoublearg(gettupleitem(args, 0), px) &&
|
||||
getdoublearg(gettupleitem(args, 1), py);
|
||||
}
|
||||
|
||||
static object *
|
||||
math_1(args, func)
|
||||
object *args;
|
||||
double (*func) FPROTO((double));
|
||||
{
|
||||
double x;
|
||||
if (!getdoublearg(args, &x))
|
||||
return NULL;
|
||||
errno = 0;
|
||||
x = (*func)(x);
|
||||
if (errno != 0)
|
||||
return NULL;
|
||||
else
|
||||
return newfloatobject(x);
|
||||
}
|
||||
|
||||
static object *
|
||||
math_2(args, func)
|
||||
object *args;
|
||||
double (*func) FPROTO((double, double));
|
||||
{
|
||||
double x, y;
|
||||
if (!get2doublearg(args, &x, &y))
|
||||
return NULL;
|
||||
errno = 0;
|
||||
x = (*func)(x, y);
|
||||
if (errno != 0)
|
||||
return NULL;
|
||||
else
|
||||
return newfloatobject(x);
|
||||
}
|
||||
|
||||
#define FUNC1(stubname, func) \
|
||||
static object * stubname(self, args) object *self, *args; { \
|
||||
return math_1(args, func); \
|
||||
}
|
||||
|
||||
#define FUNC2(stubname, func) \
|
||||
static object * stubname(self, args) object *self, *args; { \
|
||||
return math_2(args, func); \
|
||||
}
|
||||
|
||||
FUNC1(math_acos, acos)
|
||||
FUNC1(math_asin, asin)
|
||||
FUNC1(math_atan, atan)
|
||||
FUNC2(math_atan2, atan2)
|
||||
FUNC1(math_ceil, ceil)
|
||||
FUNC1(math_cos, cos)
|
||||
FUNC1(math_cosh, cosh)
|
||||
FUNC1(math_exp, exp)
|
||||
FUNC1(math_fabs, fabs)
|
||||
FUNC1(math_floor, floor)
|
||||
#if 0
|
||||
/* XXX This one is not in the Amoeba library yet, so what the heck... */
|
||||
FUNC2(math_fmod, fmod)
|
||||
#endif
|
||||
FUNC1(math_log, log)
|
||||
FUNC1(math_log10, log10)
|
||||
FUNC2(math_pow, pow)
|
||||
FUNC1(math_sin, sin)
|
||||
FUNC1(math_sinh, sinh)
|
||||
FUNC1(math_sqrt, sqrt)
|
||||
FUNC1(math_tan, tan)
|
||||
FUNC1(math_tanh, tanh)
|
||||
|
||||
#if 0
|
||||
/* What about these? */
|
||||
double frexp(double x, int *i);
|
||||
double ldexp(double x, int n);
|
||||
double modf(double x, double *i);
|
||||
#endif
|
||||
|
||||
static struct methodlist math_methods[] = {
|
||||
{"acos", math_acos},
|
||||
{"asin", math_asin},
|
||||
{"atan", math_atan},
|
||||
{"atan2", math_atan2},
|
||||
{"ceil", math_ceil},
|
||||
{"cos", math_cos},
|
||||
{"cosh", math_cosh},
|
||||
{"exp", math_exp},
|
||||
{"fabs", math_fabs},
|
||||
{"floor", math_floor},
|
||||
#if 0
|
||||
{"fmod", math_fmod},
|
||||
{"frexp", math_freqp},
|
||||
{"ldexp", math_ldexp},
|
||||
#endif
|
||||
{"log", math_log},
|
||||
{"log10", math_log10},
|
||||
#if 0
|
||||
{"modf", math_modf},
|
||||
#endif
|
||||
{"pow", math_pow},
|
||||
{"sin", math_sin},
|
||||
{"sinh", math_sinh},
|
||||
{"sqrt", math_sqrt},
|
||||
{"tan", math_tan},
|
||||
{"tanh", math_tanh},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
void
|
||||
initmath()
|
||||
{
|
||||
object *m, *d, *v;
|
||||
struct methodlist *ml;
|
||||
if ((m = new_module("math")) == NULL)
|
||||
fatal("can't create math module");
|
||||
d = getmoduledict(m);
|
||||
for (ml = math_methods; ml->ml_name != NULL; ml++) {
|
||||
v = newmethodobject(ml->ml_name, ml->ml_meth, (object *)NULL);
|
||||
if (v == NULL || dictinsert(d, ml->ml_name, v) != 0) {
|
||||
fatal("can't initialize math module");
|
||||
}
|
||||
DECREF(v);
|
||||
}
|
||||
dictinsert(d, "pi", newfloatobject(atan(1.0) * 4.0));
|
||||
dictinsert(d, "e", newfloatobject(exp(1.0)));
|
||||
DECREF(m);
|
||||
}
|
|
@ -0,0 +1,444 @@
|
|||
/* POSIX module implementation */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <setjmp.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#ifdef SYSV
|
||||
#include <dirent.h>
|
||||
#define direct dirent
|
||||
#else
|
||||
#include <sys/dir.h>
|
||||
#endif
|
||||
|
||||
#include "PROTO.h"
|
||||
#include "object.h"
|
||||
#include "intobject.h"
|
||||
#include "stringobject.h"
|
||||
#include "tupleobject.h"
|
||||
#include "listobject.h"
|
||||
#include "dictobject.h"
|
||||
#include "methodobject.h"
|
||||
#include "moduleobject.h"
|
||||
#include "objimpl.h"
|
||||
#include "import.h"
|
||||
#include "sigtype.h"
|
||||
#include "modsupport.h"
|
||||
#include "errors.h"
|
||||
|
||||
extern char *strerror();
|
||||
|
||||
#ifdef AMOEBA
|
||||
#define NO_LSTAT
|
||||
#endif
|
||||
|
||||
|
||||
/* Return a dictionary corresponding to the POSIX environment table */
|
||||
|
||||
extern char **environ;
|
||||
|
||||
static object *
|
||||
convertenviron()
|
||||
{
|
||||
object *d;
|
||||
char **e;
|
||||
d = newdictobject();
|
||||
if (d == NULL)
|
||||
return NULL;
|
||||
if (environ == NULL)
|
||||
return d;
|
||||
/* XXX This part ignores errors */
|
||||
for (e = environ; *e != NULL; e++) {
|
||||
object *v;
|
||||
char *p = strchr(*e, '=');
|
||||
if (p == NULL)
|
||||
continue;
|
||||
v = newstringobject(p+1);
|
||||
if (v == NULL)
|
||||
continue;
|
||||
*p = '\0';
|
||||
(void) dictinsert(d, *e, v);
|
||||
*p = '=';
|
||||
DECREF(v);
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
static object *PosixError; /* Exception posix.error */
|
||||
|
||||
/* Set a POSIX-specific error from errno, and return NULL */
|
||||
|
||||
static object *
|
||||
posix_error()
|
||||
{
|
||||
object *v = newtupleobject(2);
|
||||
if (v != NULL) {
|
||||
settupleitem(v, 0, newintobject((long)errno));
|
||||
settupleitem(v, 1, newstringobject(strerror(errno)));
|
||||
}
|
||||
err_setval(PosixError, v);
|
||||
if (v != NULL)
|
||||
DECREF(v);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* POSIX generic methods */
|
||||
|
||||
static object *
|
||||
posix_1str(args, func)
|
||||
object *args;
|
||||
int (*func) FPROTO((const char *));
|
||||
{
|
||||
object *path1;
|
||||
if (!getstrarg(args, &path1))
|
||||
return NULL;
|
||||
if ((*func)(getstringvalue(path1)) < 0)
|
||||
return posix_error();
|
||||
INCREF(None);
|
||||
return None;
|
||||
}
|
||||
|
||||
static object *
|
||||
posix_2str(args, func)
|
||||
object *args;
|
||||
int (*func) FPROTO((const char *, const char *));
|
||||
{
|
||||
object *path1, *path2;
|
||||
if (!getstrstrarg(args, &path1, &path2))
|
||||
return NULL;
|
||||
if ((*func)(getstringvalue(path1), getstringvalue(path2)) < 0)
|
||||
return posix_error();
|
||||
INCREF(None);
|
||||
return None;
|
||||
}
|
||||
|
||||
static object *
|
||||
posix_strint(args, func)
|
||||
object *args;
|
||||
int (*func) FPROTO((const char *, int));
|
||||
{
|
||||
object *path1;
|
||||
int i;
|
||||
if (!getstrintarg(args, &path1, &i))
|
||||
return NULL;
|
||||
if ((*func)(getstringvalue(path1), i) < 0)
|
||||
return posix_error();
|
||||
INCREF(None);
|
||||
return None;
|
||||
}
|
||||
|
||||
static object *
|
||||
posix_do_stat(self, args, statfunc)
|
||||
object *self;
|
||||
object *args;
|
||||
int (*statfunc) FPROTO((const char *, struct stat *));
|
||||
{
|
||||
struct stat st;
|
||||
object *path;
|
||||
object *v;
|
||||
if (!getstrarg(args, &path))
|
||||
return NULL;
|
||||
if ((*statfunc)(getstringvalue(path), &st) != 0)
|
||||
return posix_error();
|
||||
v = newtupleobject(10);
|
||||
if (v == NULL)
|
||||
return NULL;
|
||||
errno = 0;
|
||||
#define SET(i, st_member) settupleitem(v, i, newintobject((long)st.st_member))
|
||||
SET(0, st_mode);
|
||||
SET(1, st_ino);
|
||||
SET(2, st_dev);
|
||||
SET(3, st_nlink);
|
||||
SET(4, st_uid);
|
||||
SET(5, st_gid);
|
||||
SET(6, st_size);
|
||||
SET(7, st_atime);
|
||||
SET(8, st_mtime);
|
||||
SET(9, st_ctime);
|
||||
#undef SET
|
||||
if (errno != 0) {
|
||||
DECREF(v);
|
||||
return err_nomem();
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
/* POSIX methods */
|
||||
|
||||
static object *
|
||||
posix_chdir(self, args)
|
||||
object *self;
|
||||
object *args;
|
||||
{
|
||||
extern int chdir PROTO((const char *));
|
||||
return posix_1str(args, chdir);
|
||||
}
|
||||
|
||||
static object *
|
||||
posix_chmod(self, args)
|
||||
object *self;
|
||||
object *args;
|
||||
{
|
||||
extern int chmod PROTO((const char *, mode_t));
|
||||
return posix_strint(args, chmod);
|
||||
}
|
||||
|
||||
static object *
|
||||
posix_getcwd(self, args)
|
||||
object *self;
|
||||
object *args;
|
||||
{
|
||||
char buf[1026];
|
||||
extern char *getcwd PROTO((char *, int));
|
||||
if (!getnoarg(args))
|
||||
return NULL;
|
||||
if (getcwd(buf, sizeof buf) == NULL)
|
||||
return posix_error();
|
||||
return newstringobject(buf);
|
||||
}
|
||||
|
||||
static object *
|
||||
posix_link(self, args)
|
||||
object *self;
|
||||
object *args;
|
||||
{
|
||||
extern int link PROTO((const char *, const char *));
|
||||
return posix_2str(args, link);
|
||||
}
|
||||
|
||||
static object *
|
||||
posix_listdir(self, args)
|
||||
object *self;
|
||||
object *args;
|
||||
{
|
||||
object *name, *d, *v;
|
||||
DIR *dirp;
|
||||
struct direct *ep;
|
||||
if (!getstrarg(args, &name))
|
||||
return NULL;
|
||||
if ((dirp = opendir(getstringvalue(name))) == NULL)
|
||||
return posix_error();
|
||||
if ((d = newlistobject(0)) == NULL) {
|
||||
closedir(dirp);
|
||||
return NULL;
|
||||
}
|
||||
while ((ep = readdir(dirp)) != NULL) {
|
||||
v = newstringobject(ep->d_name);
|
||||
if (v == NULL) {
|
||||
DECREF(d);
|
||||
d = NULL;
|
||||
break;
|
||||
}
|
||||
if (addlistitem(d, v) != 0) {
|
||||
DECREF(v);
|
||||
DECREF(d);
|
||||
d = NULL;
|
||||
break;
|
||||
}
|
||||
DECREF(v);
|
||||
}
|
||||
closedir(dirp);
|
||||
return d;
|
||||
}
|
||||
|
||||
static object *
|
||||
posix_mkdir(self, args)
|
||||
object *self;
|
||||
object *args;
|
||||
{
|
||||
extern int mkdir PROTO((const char *, mode_t));
|
||||
return posix_strint(args, mkdir);
|
||||
}
|
||||
|
||||
static object *
|
||||
posix_rename(self, args)
|
||||
object *self;
|
||||
object *args;
|
||||
{
|
||||
extern int rename PROTO((const char *, const char *));
|
||||
return posix_2str(args, rename);
|
||||
}
|
||||
|
||||
static object *
|
||||
posix_rmdir(self, args)
|
||||
object *self;
|
||||
object *args;
|
||||
{
|
||||
extern int rmdir PROTO((const char *));
|
||||
return posix_1str(args, rmdir);
|
||||
}
|
||||
|
||||
static object *
|
||||
posix_stat(self, args)
|
||||
object *self;
|
||||
object *args;
|
||||
{
|
||||
extern int stat PROTO((const char *, struct stat *));
|
||||
return posix_do_stat(self, args, stat);
|
||||
}
|
||||
|
||||
static object *
|
||||
posix_system(self, args)
|
||||
object *self;
|
||||
object *args;
|
||||
{
|
||||
object *command;
|
||||
int sts;
|
||||
if (!getstrarg(args, &command))
|
||||
return NULL;
|
||||
sts = system(getstringvalue(command));
|
||||
return newintobject((long)sts);
|
||||
}
|
||||
|
||||
static object *
|
||||
posix_umask(self, args)
|
||||
object *self;
|
||||
object *args;
|
||||
{
|
||||
int i;
|
||||
if (!getintarg(args, &i))
|
||||
return NULL;
|
||||
i = umask(i);
|
||||
if (i < 0)
|
||||
return posix_error();
|
||||
return newintobject((long)i);
|
||||
}
|
||||
|
||||
static object *
|
||||
posix_unlink(self, args)
|
||||
object *self;
|
||||
object *args;
|
||||
{
|
||||
extern int unlink PROTO((const char *));
|
||||
return posix_1str(args, unlink);
|
||||
}
|
||||
|
||||
static object *
|
||||
posix_utimes(self, args)
|
||||
object *self;
|
||||
object *args;
|
||||
{
|
||||
object *path;
|
||||
struct timeval tv[2];
|
||||
if (args == NULL || !is_tupleobject(args) || gettuplesize(args) != 2) {
|
||||
err_badarg();
|
||||
return NULL;
|
||||
}
|
||||
if (!getstrarg(gettupleitem(args, 0), &path) ||
|
||||
!getlonglongargs(gettupleitem(args, 1),
|
||||
&tv[0].tv_sec, &tv[1].tv_sec))
|
||||
return NULL;
|
||||
tv[0].tv_usec = tv[1].tv_usec = 0;
|
||||
if (utimes(getstringvalue(path), tv) < 0)
|
||||
return posix_error();
|
||||
INCREF(None);
|
||||
return None;
|
||||
}
|
||||
|
||||
#ifdef NO_GETCWD
|
||||
|
||||
/* Quick hack to get posix.getcwd() working for pure BSD 4.3 */
|
||||
/* XXX This assumes MAXPATHLEN = 1024 !!! */
|
||||
|
||||
static char *
|
||||
getcwd(buf, size)
|
||||
char *buf;
|
||||
int size;
|
||||
{
|
||||
extern char *getwd PROTO((char *));
|
||||
register char *ret = getwd(buf);
|
||||
if (ret == NULL)
|
||||
errno = EACCES; /* Most likely error */
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* NO_GETCWD */
|
||||
|
||||
|
||||
#ifndef NO_LSTAT
|
||||
|
||||
static object *
|
||||
posix_lstat(self, args)
|
||||
object *self;
|
||||
object *args;
|
||||
{
|
||||
extern int lstat PROTO((const char *, struct stat *));
|
||||
return posix_do_stat(self, args, lstat);
|
||||
}
|
||||
|
||||
static object *
|
||||
posix_readlink(self, args)
|
||||
object *self;
|
||||
object *args;
|
||||
{
|
||||
char buf[1024]; /* XXX Should use MAXPATHLEN */
|
||||
object *path;
|
||||
int n;
|
||||
if (!getstrarg(args, &path))
|
||||
return NULL;
|
||||
n = readlink(getstringvalue(path), buf, sizeof buf);
|
||||
if (n < 0)
|
||||
return posix_error();
|
||||
return newsizedstringobject(buf, n);
|
||||
}
|
||||
|
||||
static object *
|
||||
posix_symlink(self, args)
|
||||
object *self;
|
||||
object *args;
|
||||
{
|
||||
extern int symlink PROTO((const char *, const char *));
|
||||
return posix_2str(args, symlink);
|
||||
}
|
||||
|
||||
#endif /* NO_LSTAT */
|
||||
|
||||
|
||||
static struct methodlist posix_methods[] = {
|
||||
{"chdir", posix_chdir},
|
||||
{"chmod", posix_chmod},
|
||||
{"getcwd", posix_getcwd},
|
||||
{"link", posix_link},
|
||||
{"listdir", posix_listdir},
|
||||
{"mkdir", posix_mkdir},
|
||||
{"rename", posix_rename},
|
||||
{"rmdir", posix_rmdir},
|
||||
{"stat", posix_stat},
|
||||
{"system", posix_system},
|
||||
{"umask", posix_umask},
|
||||
{"unlink", posix_unlink},
|
||||
{"utimes", posix_utimes},
|
||||
#ifndef NO_LSTAT
|
||||
{"lstat", posix_lstat},
|
||||
{"readlink", posix_readlink},
|
||||
{"symlink", posix_symlink},
|
||||
#endif
|
||||
{NULL, NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
|
||||
void
|
||||
initposix()
|
||||
{
|
||||
object *m, *d, *v;
|
||||
|
||||
m = initmodule("posix", posix_methods);
|
||||
d = getmoduledict(m);
|
||||
|
||||
/* Initialize posix.environ dictionary */
|
||||
v = convertenviron();
|
||||
if (v == NULL || dictinsert(d, "environ", v) != 0)
|
||||
fatal("can't define posix.environ");
|
||||
DECREF(v);
|
||||
|
||||
/* Initialize posix.error exception */
|
||||
PosixError = newstringobject("posix.error");
|
||||
if (PosixError == NULL || dictinsert(d, "error", PosixError) != 0)
|
||||
fatal("can't define posix.error");
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,178 @@
|
|||
/* Time module */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#ifdef __STDC__
|
||||
#include <time.h>
|
||||
#else /* !__STDC__ */
|
||||
typedef unsigned long time_t;
|
||||
extern time_t time();
|
||||
#endif /* !__STDC__ */
|
||||
|
||||
#include "PROTO.h"
|
||||
#include "object.h"
|
||||
#include "intobject.h"
|
||||
#include "dictobject.h"
|
||||
#include "methodobject.h"
|
||||
#include "moduleobject.h"
|
||||
#include "objimpl.h"
|
||||
#include "import.h"
|
||||
#include "sigtype.h"
|
||||
#include "modsupport.h"
|
||||
#include "errors.h"
|
||||
|
||||
|
||||
/* Time methods */
|
||||
|
||||
static object *
|
||||
time_time(self, args)
|
||||
object *self;
|
||||
object *args;
|
||||
{
|
||||
long secs;
|
||||
if (!getnoarg(args))
|
||||
return NULL;
|
||||
secs = time((time_t *)NULL);
|
||||
return newintobject(secs);
|
||||
}
|
||||
|
||||
static jmp_buf sleep_intr;
|
||||
|
||||
static void
|
||||
sleep_catcher(sig)
|
||||
int sig;
|
||||
{
|
||||
longjmp(sleep_intr, 1);
|
||||
}
|
||||
|
||||
static object *
|
||||
time_sleep(self, args)
|
||||
object *self;
|
||||
object *args;
|
||||
{
|
||||
int secs;
|
||||
SIGTYPE (*sigsave)();
|
||||
if (!getintarg(args, &secs))
|
||||
return NULL;
|
||||
if (setjmp(sleep_intr)) {
|
||||
signal(SIGINT, sigsave);
|
||||
err_set(KeyboardInterrupt);
|
||||
return NULL;
|
||||
}
|
||||
sigsave = signal(SIGINT, SIG_IGN);
|
||||
if (sigsave != (SIGTYPE (*)()) SIG_IGN)
|
||||
signal(SIGINT, sleep_catcher);
|
||||
sleep(secs);
|
||||
signal(SIGINT, sigsave);
|
||||
INCREF(None);
|
||||
return None;
|
||||
}
|
||||
|
||||
#ifdef THINK_C
|
||||
#define DO_MILLI
|
||||
#endif /* THINK_C */
|
||||
|
||||
#ifdef AMOEBA
|
||||
#define DO_MILLI
|
||||
extern long sys_milli();
|
||||
#define millitimer sys_milli
|
||||
#endif /* AMOEBA */
|
||||
|
||||
#ifdef DO_MILLI
|
||||
|
||||
static object *
|
||||
time_millisleep(self, args)
|
||||
object *self;
|
||||
object *args;
|
||||
{
|
||||
long msecs;
|
||||
SIGTYPE (*sigsave)();
|
||||
if (!getlongarg(args, &msecs))
|
||||
return NULL;
|
||||
if (setjmp(sleep_intr)) {
|
||||
signal(SIGINT, sigsave);
|
||||
err_set(KeyboardInterrupt);
|
||||
return NULL;
|
||||
}
|
||||
sigsave = signal(SIGINT, SIG_IGN);
|
||||
if (sigsave != (SIGTYPE (*)()) SIG_IGN)
|
||||
signal(SIGINT, sleep_catcher);
|
||||
millisleep(msecs);
|
||||
signal(SIGINT, sigsave);
|
||||
INCREF(None);
|
||||
return None;
|
||||
}
|
||||
|
||||
static object *
|
||||
time_millitimer(self, args)
|
||||
object *self;
|
||||
object *args;
|
||||
{
|
||||
long msecs;
|
||||
extern long millitimer();
|
||||
if (!getnoarg(args))
|
||||
return NULL;
|
||||
msecs = millitimer();
|
||||
return newintobject(msecs);
|
||||
}
|
||||
|
||||
#endif /* DO_MILLI */
|
||||
|
||||
|
||||
static struct methodlist time_methods[] = {
|
||||
#ifdef DO_MILLI
|
||||
{"millisleep", time_millisleep},
|
||||
{"millitimer", time_millitimer},
|
||||
#endif /* DO_MILLI */
|
||||
{"sleep", time_sleep},
|
||||
{"time", time_time},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
|
||||
void
|
||||
inittime()
|
||||
{
|
||||
initmodule("time", time_methods);
|
||||
}
|
||||
|
||||
|
||||
#ifdef THINK_C
|
||||
|
||||
#define MacTicks (* (long *)0x16A)
|
||||
|
||||
static
|
||||
sleep(msecs)
|
||||
int msecs;
|
||||
{
|
||||
register long deadline;
|
||||
|
||||
deadline = MacTicks + msecs * 60;
|
||||
while (MacTicks < deadline) {
|
||||
if (intrcheck())
|
||||
sleep_catcher(SIGINT);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
millisleep(msecs)
|
||||
long msecs;
|
||||
{
|
||||
register long deadline;
|
||||
|
||||
deadline = MacTicks + msecs * 3 / 50; /* msecs * 60 / 1000 */
|
||||
while (MacTicks < deadline) {
|
||||
if (intrcheck())
|
||||
sleep_catcher(SIGINT);
|
||||
}
|
||||
}
|
||||
|
||||
static long
|
||||
millitimer()
|
||||
{
|
||||
return MacTicks * 50 / 3; /* MacTicks * 1000 / 60 */
|
||||
}
|
||||
|
||||
#endif /* THINK_C */
|
|
@ -0,0 +1,268 @@
|
|||
/* Class object implementation */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "PROTO.h"
|
||||
#include "node.h"
|
||||
#include "object.h"
|
||||
#include "stringobject.h"
|
||||
#include "tupleobject.h"
|
||||
#include "dictobject.h"
|
||||
#include "funcobject.h"
|
||||
#include "classobject.h"
|
||||
#include "objimpl.h"
|
||||
|
||||
typedef struct {
|
||||
OB_HEAD
|
||||
node *cl_tree; /* The entire classdef parse tree */
|
||||
object *cl_bases; /* A tuple */
|
||||
object *cl_methods; /* A dictionary */
|
||||
} classobject;
|
||||
|
||||
object *
|
||||
newclassobject(tree, bases, methods)
|
||||
node *tree;
|
||||
object *bases; /* NULL or tuple of classobjects! */
|
||||
object *methods;
|
||||
{
|
||||
classobject *op;
|
||||
op = NEWOBJ(classobject, &Classtype);
|
||||
if (op == NULL)
|
||||
return NULL;
|
||||
op->cl_tree = tree;
|
||||
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;
|
||||
}
|
||||
}
|
||||
errno = ESRCH;
|
||||
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)) {
|
||||
errno = EINVAL;
|
||||
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 errno */
|
||||
if (is_funcobject(v)) {
|
||||
object *w = newclassmethodobject(v, (object *)cm);
|
||||
DECREF(v);
|
||||
return w;
|
||||
}
|
||||
DECREF(v);
|
||||
errno = ESRCH;
|
||||
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)) {
|
||||
errno = EINVAL;
|
||||
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)) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
return ((classmethodobject *)cm)->cm_func;
|
||||
}
|
||||
|
||||
object *
|
||||
classmethodgetself(cm)
|
||||
register object *cm;
|
||||
{
|
||||
if (!is_classmethodobject(cm)) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
return ((classmethodobject *)cm)->cm_self;
|
||||
}
|
||||
|
||||
/* Class method methods */
|
||||
|
||||
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*/
|
||||
0, /*tp_getattr*/
|
||||
0, /*tp_setattr*/
|
||||
0, /*tp_compare*/
|
||||
0, /*tp_repr*/
|
||||
0, /*tp_as_number*/
|
||||
0, /*tp_as_sequence*/
|
||||
0, /*tp_as_mapping*/
|
||||
};
|
|
@ -0,0 +1,267 @@
|
|||
/* File object implementation */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "PROTO.h"
|
||||
#include "object.h"
|
||||
#include "stringobject.h"
|
||||
#include "intobject.h"
|
||||
#include "fileobject.h"
|
||||
#include "methodobject.h"
|
||||
#include "objimpl.h"
|
||||
|
||||
typedef struct {
|
||||
OB_HEAD
|
||||
FILE *f_fp;
|
||||
object *f_name;
|
||||
object *f_mode;
|
||||
/* XXX Should move the 'need space' on printing flag here */
|
||||
} fileobject;
|
||||
|
||||
FILE *
|
||||
getfilefile(f)
|
||||
object *f;
|
||||
{
|
||||
if (!is_fileobject(f)) {
|
||||
errno = EBADF;
|
||||
return NULL;
|
||||
}
|
||||
return ((fileobject *)f)->f_fp;
|
||||
}
|
||||
|
||||
object *
|
||||
newopenfileobject(fp, name, mode)
|
||||
FILE *fp;
|
||||
char *name;
|
||||
char *mode;
|
||||
{
|
||||
fileobject *f = NEWOBJ(fileobject, &Filetype);
|
||||
if (f == NULL)
|
||||
return NULL;
|
||||
f->f_fp = NULL;
|
||||
f->f_name = newstringobject(name);
|
||||
f->f_mode = newstringobject(mode);
|
||||
if (f->f_name == NULL || f->f_mode == NULL) {
|
||||
DECREF(f);
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
f->f_fp = fp;
|
||||
return (object *) f;
|
||||
}
|
||||
|
||||
object *
|
||||
newfileobject(name, mode)
|
||||
char *name, *mode;
|
||||
{
|
||||
fileobject *f;
|
||||
FILE *fp;
|
||||
f = (fileobject *) newopenfileobject((FILE *)NULL, name, mode);
|
||||
if (f == NULL)
|
||||
return NULL;
|
||||
if ((f->f_fp = fopen(name, mode)) == NULL) {
|
||||
DECREF(f);
|
||||
return NULL;
|
||||
}
|
||||
return (object *)f;
|
||||
}
|
||||
|
||||
/* Methods */
|
||||
|
||||
static void
|
||||
filedealloc(f)
|
||||
fileobject *f;
|
||||
{
|
||||
if (f->f_fp != NULL)
|
||||
fclose(f->f_fp);
|
||||
if (f->f_name != NULL)
|
||||
DECREF(f->f_name);
|
||||
if (f->f_mode != NULL)
|
||||
DECREF(f->f_mode);
|
||||
free((char *)f);
|
||||
}
|
||||
|
||||
static void
|
||||
fileprint(f, fp, flags)
|
||||
fileobject *f;
|
||||
FILE *fp;
|
||||
int flags;
|
||||
{
|
||||
fprintf(fp, "<%s file ", f->f_fp == NULL ? "closed" : "open");
|
||||
printobject(f->f_name, fp, flags);
|
||||
fprintf(fp, ", mode ");
|
||||
printobject(f->f_mode, fp, flags);
|
||||
fprintf(fp, ">");
|
||||
}
|
||||
|
||||
static object *
|
||||
filerepr(f)
|
||||
fileobject *f;
|
||||
{
|
||||
char buf[300];
|
||||
/* XXX This differs from fileprint if the filename contains
|
||||
quotes or other funny characters. */
|
||||
sprintf(buf, "<%s file '%.256s', mode '%.10s'>",
|
||||
f->f_fp == NULL ? "closed" : "open",
|
||||
getstringvalue(f->f_name),
|
||||
getstringvalue(f->f_mode));
|
||||
return newstringobject(buf);
|
||||
}
|
||||
|
||||
static object *
|
||||
fileclose(f, args)
|
||||
fileobject *f;
|
||||
object *args;
|
||||
{
|
||||
if (args != NULL) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
if (f->f_fp != NULL) {
|
||||
fclose(f->f_fp);
|
||||
f->f_fp = NULL;
|
||||
}
|
||||
INCREF(None);
|
||||
return None;
|
||||
}
|
||||
|
||||
static object *
|
||||
fileread(f, args)
|
||||
fileobject *f;
|
||||
object *args;
|
||||
{
|
||||
int n;
|
||||
object *v;
|
||||
if (f->f_fp == NULL) {
|
||||
errno = EBADF;
|
||||
return NULL;
|
||||
}
|
||||
if (args == NULL || !is_intobject(args)) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
n = getintvalue(args);
|
||||
if (n <= 0 /* || n > 0x7fff /*XXX*/ ) {
|
||||
errno = EDOM;
|
||||
return NULL;
|
||||
}
|
||||
v = newsizedstringobject((char *)NULL, n);
|
||||
if (v == NULL) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
n = fread(getstringvalue(v), 1, n, f->f_fp);
|
||||
/* EOF is reported as an empty string */
|
||||
/* XXX should detect real I/O errors? */
|
||||
resizestring(&v, n);
|
||||
return v;
|
||||
}
|
||||
|
||||
/* XXX Should this be unified with raw_input()? */
|
||||
|
||||
static object *
|
||||
filereadline(f, args)
|
||||
fileobject *f;
|
||||
object *args;
|
||||
{
|
||||
int n;
|
||||
object *v;
|
||||
if (f->f_fp == NULL) {
|
||||
errno = EBADF;
|
||||
return NULL;
|
||||
}
|
||||
if (args == NULL) {
|
||||
n = 10000; /* XXX should really be unlimited */
|
||||
}
|
||||
else if (is_intobject(args)) {
|
||||
n = getintvalue(args);
|
||||
if (n < 0 || n > 0x7fff /*XXX*/ ) {
|
||||
errno = EDOM;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
v = newsizedstringobject((char *)NULL, n);
|
||||
if (v == NULL) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
if (fgets(getstringvalue(v), n+1, f->f_fp) == NULL) {
|
||||
/* EOF is reported as an empty string */
|
||||
/* XXX should detect real I/O errors? */
|
||||
n = 0;
|
||||
}
|
||||
else {
|
||||
n = strlen(getstringvalue(v));
|
||||
}
|
||||
resizestring(&v, n);
|
||||
return v;
|
||||
}
|
||||
|
||||
static object *
|
||||
filewrite(f, args)
|
||||
fileobject *f;
|
||||
object *args;
|
||||
{
|
||||
int n, n2;
|
||||
if (f->f_fp == NULL) {
|
||||
errno = EBADF;
|
||||
return NULL;
|
||||
}
|
||||
if (args == NULL || !is_stringobject(args)) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
errno = 0;
|
||||
n2 = fwrite(getstringvalue(args), 1, n = getstringsize(args), f->f_fp);
|
||||
if (n2 != n) {
|
||||
if (errno == 0)
|
||||
errno = EIO;
|
||||
return NULL;
|
||||
}
|
||||
INCREF(None);
|
||||
return None;
|
||||
}
|
||||
|
||||
static struct methodlist {
|
||||
char *ml_name;
|
||||
method ml_meth;
|
||||
} filemethods[] = {
|
||||
{"write", filewrite},
|
||||
{"read", fileread},
|
||||
{"readline", filereadline},
|
||||
{"close", fileclose},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
static object *
|
||||
filegetattr(f, name)
|
||||
fileobject *f;
|
||||
char *name;
|
||||
{
|
||||
struct methodlist *ml = filemethods;
|
||||
for (; ml->ml_name != NULL; ml++) {
|
||||
if (strcmp(name, ml->ml_name) == 0)
|
||||
return newmethodobject(ml->ml_name, ml->ml_meth,
|
||||
(object *)f);
|
||||
}
|
||||
errno = ESRCH;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
typeobject Filetype = {
|
||||
OB_HEAD_INIT(&Typetype)
|
||||
0,
|
||||
"file",
|
||||
sizeof(fileobject),
|
||||
0,
|
||||
filedealloc, /*tp_dealloc*/
|
||||
fileprint, /*tp_print*/
|
||||
filegetattr, /*tp_getattr*/
|
||||
0, /*tp_setattr*/
|
||||
0, /*tp_compare*/
|
||||
filerepr, /*tp_repr*/
|
||||
};
|
|
@ -0,0 +1,240 @@
|
|||
/* Float object implementation */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "PROTO.h"
|
||||
#include "object.h"
|
||||
#include "floatobject.h"
|
||||
#include "stringobject.h"
|
||||
#include "objimpl.h"
|
||||
|
||||
object *
|
||||
newfloatobject(fval)
|
||||
double fval;
|
||||
{
|
||||
/* For efficiency, this code is copied from newobject() */
|
||||
register floatobject *op = (floatobject *) malloc(sizeof(floatobject));
|
||||
if (op == NULL) {
|
||||
errno = ENOMEM;
|
||||
}
|
||||
else {
|
||||
NEWREF(op);
|
||||
op->ob_type = &Floattype;
|
||||
op->ob_fval = fval;
|
||||
}
|
||||
return (object *) op;
|
||||
}
|
||||
|
||||
double
|
||||
getfloatvalue(op)
|
||||
object *op;
|
||||
{
|
||||
if (!is_floatobject(op)) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
return ((floatobject *)op) -> ob_fval;
|
||||
}
|
||||
|
||||
/* Methods */
|
||||
|
||||
static void
|
||||
float_buf_repr(buf, v)
|
||||
char *buf;
|
||||
floatobject *v;
|
||||
{
|
||||
register char *cp;
|
||||
/* Subroutine for float_repr and float_print.
|
||||
We want float numbers to be recognizable as such,
|
||||
i.e., they should contain a decimal point or an exponent.
|
||||
However, %g may print the number as an integer;
|
||||
in such cases, we append ".0" to the string. */
|
||||
sprintf(buf, "%.12g", v->ob_fval);
|
||||
cp = buf;
|
||||
if (*cp == '-')
|
||||
cp++;
|
||||
for (; *cp != '\0'; cp++) {
|
||||
/* Any non-digit means it's not an integer;
|
||||
this takes care of NAN and INF as well. */
|
||||
if (!isdigit(*cp))
|
||||
break;
|
||||
}
|
||||
if (*cp == '\0') {
|
||||
*cp++ = '.';
|
||||
*cp++ = '0';
|
||||
*cp++ = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
float_print(v, fp, flags)
|
||||
floatobject *v;
|
||||
FILE *fp;
|
||||
int flags;
|
||||
{
|
||||
char buf[100];
|
||||
float_buf_repr(buf, v);
|
||||
fputs(buf, fp);
|
||||
}
|
||||
|
||||
static object *
|
||||
float_repr(v)
|
||||
floatobject *v;
|
||||
{
|
||||
char buf[100];
|
||||
float_buf_repr(buf, v);
|
||||
return newstringobject(buf);
|
||||
}
|
||||
|
||||
static int
|
||||
float_compare(v, w)
|
||||
floatobject *v, *w;
|
||||
{
|
||||
double i = v->ob_fval;
|
||||
double j = w->ob_fval;
|
||||
return (i < j) ? -1 : (i > j) ? 1 : 0;
|
||||
}
|
||||
|
||||
static object *
|
||||
float_add(v, w)
|
||||
floatobject *v;
|
||||
object *w;
|
||||
{
|
||||
if (!is_floatobject(w)) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
return newfloatobject(v->ob_fval + ((floatobject *)w) -> ob_fval);
|
||||
}
|
||||
|
||||
static object *
|
||||
float_sub(v, w)
|
||||
floatobject *v;
|
||||
object *w;
|
||||
{
|
||||
if (!is_floatobject(w)) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
return newfloatobject(v->ob_fval - ((floatobject *)w) -> ob_fval);
|
||||
}
|
||||
|
||||
static object *
|
||||
float_mul(v, w)
|
||||
floatobject *v;
|
||||
object *w;
|
||||
{
|
||||
if (!is_floatobject(w)) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
return newfloatobject(v->ob_fval * ((floatobject *)w) -> ob_fval);
|
||||
}
|
||||
|
||||
static object *
|
||||
float_div(v, w)
|
||||
floatobject *v;
|
||||
object *w;
|
||||
{
|
||||
if (!is_floatobject(w)) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
if (((floatobject *)w) -> ob_fval == 0) {
|
||||
errno = EDOM;
|
||||
return NULL;
|
||||
}
|
||||
return newfloatobject(v->ob_fval / ((floatobject *)w) -> ob_fval);
|
||||
}
|
||||
|
||||
static object *
|
||||
float_rem(v, w)
|
||||
floatobject *v;
|
||||
object *w;
|
||||
{
|
||||
double wx;
|
||||
extern double fmod();
|
||||
if (!is_floatobject(w)) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
wx = ((floatobject *)w) -> ob_fval;
|
||||
if (wx == 0.0) {
|
||||
errno = EDOM;
|
||||
return NULL;
|
||||
}
|
||||
return newfloatobject(fmod(v->ob_fval, wx));
|
||||
}
|
||||
|
||||
static object *
|
||||
float_pow(v, w)
|
||||
floatobject *v;
|
||||
object *w;
|
||||
{
|
||||
double iv, iw, ix;
|
||||
extern double pow();
|
||||
if (!is_floatobject(w)) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
iv = v->ob_fval;
|
||||
iw = ((floatobject *)w)->ob_fval;
|
||||
errno = 0;
|
||||
ix = pow(iv, iw);
|
||||
if (errno != 0)
|
||||
return NULL;
|
||||
else
|
||||
return newfloatobject(ix);
|
||||
}
|
||||
|
||||
static object *
|
||||
float_neg(v)
|
||||
floatobject *v;
|
||||
{
|
||||
return newfloatobject(-v->ob_fval);
|
||||
}
|
||||
|
||||
static object *
|
||||
float_pos(v)
|
||||
floatobject *v;
|
||||
{
|
||||
return newfloatobject(v->ob_fval);
|
||||
}
|
||||
|
||||
static number_methods float_as_number = {
|
||||
float_add, /*tp_add*/
|
||||
float_sub, /*tp_subtract*/
|
||||
float_mul, /*tp_multiply*/
|
||||
float_div, /*tp_divide*/
|
||||
float_rem, /*tp_remainder*/
|
||||
float_pow, /*tp_power*/
|
||||
float_neg, /*tp_negate*/
|
||||
float_pos, /*tp_plus*/
|
||||
};
|
||||
|
||||
typeobject Floattype = {
|
||||
OB_HEAD_INIT(&Typetype)
|
||||
0,
|
||||
"float",
|
||||
sizeof(floatobject),
|
||||
0,
|
||||
free, /*tp_dealloc*/
|
||||
float_print, /*tp_print*/
|
||||
0, /*tp_getattr*/
|
||||
0, /*tp_setattr*/
|
||||
float_compare, /*tp_compare*/
|
||||
float_repr, /*tp_repr*/
|
||||
&float_as_number, /*tp_as_number*/
|
||||
0, /*tp_as_sequence*/
|
||||
0, /*tp_as_mapping*/
|
||||
};
|
||||
|
||||
/*
|
||||
XXX This is not enough. Need:
|
||||
- automatic casts for mixed arithmetic (3.1 * 4)
|
||||
- mixed comparisons (!)
|
||||
- look at other uses of ints that could be extended to floats
|
||||
*/
|
|
@ -0,0 +1,101 @@
|
|||
/* Function object implementation */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "PROTO.h"
|
||||
#include "object.h"
|
||||
#include "node.h"
|
||||
#include "stringobject.h"
|
||||
#include "funcobject.h"
|
||||
#include "objimpl.h"
|
||||
#include "token.h"
|
||||
|
||||
typedef struct {
|
||||
OB_HEAD
|
||||
node *func_node;
|
||||
object *func_globals;
|
||||
} funcobject;
|
||||
|
||||
object *
|
||||
newfuncobject(n, globals)
|
||||
node *n;
|
||||
object *globals;
|
||||
{
|
||||
funcobject *op = NEWOBJ(funcobject, &Functype);
|
||||
if (op != NULL) {
|
||||
op->func_node = n;
|
||||
if (globals != NULL)
|
||||
INCREF(globals);
|
||||
op->func_globals = globals;
|
||||
}
|
||||
return (object *)op;
|
||||
}
|
||||
|
||||
node *
|
||||
getfuncnode(op)
|
||||
object *op;
|
||||
{
|
||||
if (!is_funcobject(op)) {
|
||||
errno = EBADF;
|
||||
return NULL;
|
||||
}
|
||||
return ((funcobject *) op) -> func_node;
|
||||
}
|
||||
|
||||
object *
|
||||
getfuncglobals(op)
|
||||
object *op;
|
||||
{
|
||||
if (!is_funcobject(op)) {
|
||||
errno = EBADF;
|
||||
return NULL;
|
||||
}
|
||||
return ((funcobject *) op) -> func_globals;
|
||||
}
|
||||
|
||||
/* Methods */
|
||||
|
||||
static void
|
||||
funcdealloc(op)
|
||||
funcobject *op;
|
||||
{
|
||||
/* XXX free node? */
|
||||
DECREF(op->func_globals);
|
||||
free((char *)op);
|
||||
}
|
||||
|
||||
static void
|
||||
funcprint(op, fp, flags)
|
||||
funcobject *op;
|
||||
FILE *fp;
|
||||
int flags;
|
||||
{
|
||||
node *n = op->func_node;
|
||||
n = CHILD(n, 1);
|
||||
fprintf(fp, "<user function %s>", STR(n));
|
||||
}
|
||||
|
||||
static object *
|
||||
funcrepr(op)
|
||||
funcobject *op;
|
||||
{
|
||||
char buf[100];
|
||||
node *n = op->func_node;
|
||||
n = CHILD(n, 1);
|
||||
sprintf(buf, "<user function %.80s>", STR(n));
|
||||
return newstringobject(buf);
|
||||
}
|
||||
|
||||
typeobject Functype = {
|
||||
OB_HEAD_INIT(&Typetype)
|
||||
0,
|
||||
"function",
|
||||
sizeof(funcobject),
|
||||
0,
|
||||
funcdealloc, /*tp_dealloc*/
|
||||
funcprint, /*tp_print*/
|
||||
0, /*tp_getattr*/
|
||||
0, /*tp_setattr*/
|
||||
0, /*tp_compare*/
|
||||
funcrepr, /*tp_repr*/
|
||||
};
|
|
@ -0,0 +1,250 @@
|
|||
/* Integer object implementation */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "PROTO.h"
|
||||
#include "object.h"
|
||||
#include "intobject.h"
|
||||
#include "stringobject.h"
|
||||
#include "objimpl.h"
|
||||
|
||||
/* Standard Booleans */
|
||||
intobject FalseObject = {
|
||||
OB_HEAD_INIT(&Inttype)
|
||||
0
|
||||
};
|
||||
intobject TrueObject = {
|
||||
OB_HEAD_INIT(&Inttype)
|
||||
1
|
||||
};
|
||||
|
||||
object *
|
||||
newintobject(ival)
|
||||
long ival;
|
||||
{
|
||||
/* For efficiency, this code is copied from newobject() */
|
||||
register intobject *op = (intobject *) malloc(sizeof(intobject));
|
||||
if (op == NULL) {
|
||||
errno = ENOMEM;
|
||||
}
|
||||
else {
|
||||
NEWREF(op);
|
||||
op->ob_type = &Inttype;
|
||||
op->ob_ival = ival;
|
||||
}
|
||||
return (object *) op;
|
||||
}
|
||||
|
||||
long
|
||||
getintvalue(op)
|
||||
register object *op;
|
||||
{
|
||||
if (!is_intobject(op)) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
return ((intobject *)op) -> ob_ival;
|
||||
}
|
||||
|
||||
/* Methods */
|
||||
|
||||
static void
|
||||
intprint(v, fp, flags)
|
||||
intobject *v;
|
||||
FILE *fp;
|
||||
int flags;
|
||||
{
|
||||
fprintf(fp, "%ld", v->ob_ival);
|
||||
}
|
||||
|
||||
static object *
|
||||
intrepr(v)
|
||||
intobject *v;
|
||||
{
|
||||
char buf[20];
|
||||
sprintf(buf, "%ld", v->ob_ival);
|
||||
return newstringobject(buf);
|
||||
}
|
||||
|
||||
static int
|
||||
intcompare(v, w)
|
||||
intobject *v, *w;
|
||||
{
|
||||
register long i = v->ob_ival;
|
||||
register long j = w->ob_ival;
|
||||
return (i < j) ? -1 : (i > j) ? 1 : 0;
|
||||
}
|
||||
|
||||
static object *
|
||||
intadd(v, w)
|
||||
intobject *v;
|
||||
register object *w;
|
||||
{
|
||||
register long a, b, x;
|
||||
if (!is_intobject(w)) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
a = v->ob_ival;
|
||||
b = ((intobject *)w) -> ob_ival;
|
||||
x = a + b;
|
||||
if ((x^a) < 0 && (x^b) < 0) {
|
||||
errno = ERANGE;
|
||||
return NULL;
|
||||
}
|
||||
return newintobject(x);
|
||||
}
|
||||
|
||||
static object *
|
||||
intsub(v, w)
|
||||
intobject *v;
|
||||
register object *w;
|
||||
{
|
||||
register long a, b, x;
|
||||
if (!is_intobject(w)) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
a = v->ob_ival;
|
||||
b = ((intobject *)w) -> ob_ival;
|
||||
x = a - b;
|
||||
if ((x^a) < 0 && (x^~b) < 0) {
|
||||
errno = ERANGE;
|
||||
return NULL;
|
||||
}
|
||||
return newintobject(x);
|
||||
}
|
||||
|
||||
static object *
|
||||
intmul(v, w)
|
||||
intobject *v;
|
||||
register object *w;
|
||||
{
|
||||
register long a, b;
|
||||
double x;
|
||||
if (!is_intobject(w)) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
a = v->ob_ival;
|
||||
b = ((intobject *)w) -> ob_ival;
|
||||
x = (double)a * (double)b;
|
||||
if (x > 0x7fffffff || x < (double) (long) 0x80000000) {
|
||||
errno = ERANGE;
|
||||
return NULL;
|
||||
}
|
||||
return newintobject(a * b);
|
||||
}
|
||||
|
||||
static object *
|
||||
intdiv(v, w)
|
||||
intobject *v;
|
||||
register object *w;
|
||||
{
|
||||
if (!is_intobject(w)) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
if (((intobject *)w) -> ob_ival == 0) {
|
||||
errno = EDOM;
|
||||
return NULL;
|
||||
}
|
||||
return newintobject(v->ob_ival / ((intobject *)w) -> ob_ival);
|
||||
}
|
||||
|
||||
static object *
|
||||
intrem(v, w)
|
||||
intobject *v;
|
||||
register object *w;
|
||||
{
|
||||
if (!is_intobject(w)) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
if (((intobject *)w) -> ob_ival == 0) {
|
||||
errno = EDOM;
|
||||
return NULL;
|
||||
}
|
||||
return newintobject(v->ob_ival % ((intobject *)w) -> ob_ival);
|
||||
}
|
||||
|
||||
static object *
|
||||
intpow(v, w)
|
||||
intobject *v;
|
||||
register object *w;
|
||||
{
|
||||
register long iv, iw, ix;
|
||||
register int neg;
|
||||
if (!is_intobject(w)) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
iv = v->ob_ival;
|
||||
iw = ((intobject *)w)->ob_ival;
|
||||
neg = 0;
|
||||
if (iw < 0)
|
||||
neg = 1, iw = -iw;
|
||||
ix = 1;
|
||||
for (; iw > 0; iw--)
|
||||
ix = ix * iv;
|
||||
if (neg) {
|
||||
if (ix == 0) {
|
||||
errno = EDOM;
|
||||
return NULL;
|
||||
}
|
||||
ix = 1/ix;
|
||||
}
|
||||
/* XXX How to check for overflow? */
|
||||
return newintobject(ix);
|
||||
}
|
||||
|
||||
static object *
|
||||
intneg(v)
|
||||
intobject *v;
|
||||
{
|
||||
register long a, x;
|
||||
a = v->ob_ival;
|
||||
x = -a;
|
||||
if (a < 0 && x < 0) {
|
||||
errno = ERANGE;
|
||||
return NULL;
|
||||
}
|
||||
return newintobject(x);
|
||||
}
|
||||
|
||||
static object *
|
||||
intpos(v)
|
||||
intobject *v;
|
||||
{
|
||||
INCREF(v);
|
||||
return (object *)v;
|
||||
}
|
||||
|
||||
static number_methods int_as_number = {
|
||||
intadd, /*tp_add*/
|
||||
intsub, /*tp_subtract*/
|
||||
intmul, /*tp_multiply*/
|
||||
intdiv, /*tp_divide*/
|
||||
intrem, /*tp_remainder*/
|
||||
intpow, /*tp_power*/
|
||||
intneg, /*tp_negate*/
|
||||
intpos, /*tp_plus*/
|
||||
};
|
||||
|
||||
typeobject Inttype = {
|
||||
OB_HEAD_INIT(&Typetype)
|
||||
0,
|
||||
"int",
|
||||
sizeof(intobject),
|
||||
0,
|
||||
free, /*tp_dealloc*/
|
||||
intprint, /*tp_print*/
|
||||
0, /*tp_getattr*/
|
||||
0, /*tp_setattr*/
|
||||
intcompare, /*tp_compare*/
|
||||
intrepr, /*tp_repr*/
|
||||
&int_as_number, /*tp_as_number*/
|
||||
0, /*tp_as_sequence*/
|
||||
0, /*tp_as_mapping*/
|
||||
};
|
|
@ -0,0 +1,482 @@
|
|||
/* List object implementation */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "PROTO.h"
|
||||
#include "object.h"
|
||||
#include "intobject.h"
|
||||
#include "stringobject.h"
|
||||
#include "tupleobject.h"
|
||||
#include "methodobject.h"
|
||||
#include "listobject.h"
|
||||
#include "objimpl.h"
|
||||
#include "modsupport.h"
|
||||
|
||||
typedef struct {
|
||||
OB_VARHEAD
|
||||
object **ob_item;
|
||||
} listobject;
|
||||
|
||||
object *
|
||||
newlistobject(size)
|
||||
int size;
|
||||
{
|
||||
int i;
|
||||
listobject *op;
|
||||
if (size < 0) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
op = (listobject *) malloc(sizeof(listobject));
|
||||
if (op == NULL) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
if (size <= 0) {
|
||||
op->ob_item = NULL;
|
||||
}
|
||||
else {
|
||||
op->ob_item = (object **) malloc(size * sizeof(object *));
|
||||
if (op->ob_item == NULL) {
|
||||
free((ANY *)op);
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
NEWREF(op);
|
||||
op->ob_type = &Listtype;
|
||||
op->ob_size = size;
|
||||
for (i = 0; i < size; i++)
|
||||
op->ob_item[i] = NULL;
|
||||
return (object *) op;
|
||||
}
|
||||
|
||||
int
|
||||
getlistsize(op)
|
||||
object *op;
|
||||
{
|
||||
if (!is_listobject(op)) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
return ((listobject *)op) -> ob_size;
|
||||
}
|
||||
|
||||
object *
|
||||
getlistitem(op, i)
|
||||
object *op;
|
||||
int i;
|
||||
{
|
||||
if (!is_listobject(op)) {
|
||||
errno = EBADF;
|
||||
return NULL;
|
||||
}
|
||||
if (i < 0 || i >= ((listobject *)op) -> ob_size) {
|
||||
errno = EDOM;
|
||||
return NULL;
|
||||
}
|
||||
return ((listobject *)op) -> ob_item[i];
|
||||
}
|
||||
|
||||
int
|
||||
setlistitem(op, i, newitem)
|
||||
register object *op;
|
||||
register int i;
|
||||
register object *newitem;
|
||||
{
|
||||
register object *olditem;
|
||||
if (!is_listobject(op)) {
|
||||
if (newitem != NULL)
|
||||
DECREF(newitem);
|
||||
return errno = EBADF;
|
||||
}
|
||||
if (i < 0 || i >= ((listobject *)op) -> ob_size) {
|
||||
if (newitem != NULL)
|
||||
DECREF(newitem);
|
||||
return errno = EDOM;
|
||||
}
|
||||
olditem = ((listobject *)op) -> ob_item[i];
|
||||
((listobject *)op) -> ob_item[i] = newitem;
|
||||
if (olditem != NULL)
|
||||
DECREF(olditem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ins1(self, where, v)
|
||||
listobject *self;
|
||||
int where;
|
||||
object *v;
|
||||
{
|
||||
int i;
|
||||
object **items;
|
||||
if (v == NULL)
|
||||
return errno = EINVAL;
|
||||
items = self->ob_item;
|
||||
RESIZE(items, object *, self->ob_size+1);
|
||||
if (items == NULL)
|
||||
return errno = ENOMEM;
|
||||
if (where < 0)
|
||||
where = 0;
|
||||
if (where > self->ob_size)
|
||||
where = self->ob_size;
|
||||
for (i = self->ob_size; --i >= where; )
|
||||
items[i+1] = items[i];
|
||||
INCREF(v);
|
||||
items[where] = v;
|
||||
self->ob_item = items;
|
||||
self->ob_size++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
inslistitem(op, where, newitem)
|
||||
object *op;
|
||||
int where;
|
||||
object *newitem;
|
||||
{
|
||||
if (!is_listobject(op))
|
||||
return errno = EBADF;
|
||||
return ins1((listobject *)op, where, newitem);
|
||||
}
|
||||
|
||||
int
|
||||
addlistitem(op, newitem)
|
||||
object *op;
|
||||
object *newitem;
|
||||
{
|
||||
if (!is_listobject(op))
|
||||
return errno = EBADF;
|
||||
return ins1((listobject *)op,
|
||||
(int) ((listobject *)op)->ob_size, newitem);
|
||||
}
|
||||
|
||||
/* Methods */
|
||||
|
||||
static void
|
||||
list_dealloc(op)
|
||||
listobject *op;
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < op->ob_size; i++) {
|
||||
if (op->ob_item[i] != NULL)
|
||||
DECREF(op->ob_item[i]);
|
||||
}
|
||||
if (op->ob_item != NULL)
|
||||
free((ANY *)op->ob_item);
|
||||
free((ANY *)op);
|
||||
}
|
||||
|
||||
static void
|
||||
list_print(op, fp, flags)
|
||||
listobject *op;
|
||||
FILE *fp;
|
||||
int flags;
|
||||
{
|
||||
int i;
|
||||
fprintf(fp, "[");
|
||||
for (i = 0; i < op->ob_size && !StopPrint; i++) {
|
||||
if (i > 0) {
|
||||
fprintf(fp, ", ");
|
||||
}
|
||||
printobject(op->ob_item[i], fp, flags);
|
||||
}
|
||||
fprintf(fp, "]");
|
||||
}
|
||||
|
||||
object *
|
||||
list_repr(v)
|
||||
listobject *v;
|
||||
{
|
||||
object *s, *t, *comma;
|
||||
int i;
|
||||
s = newstringobject("[");
|
||||
comma = newstringobject(", ");
|
||||
for (i = 0; i < v->ob_size && s != NULL; i++) {
|
||||
if (i > 0)
|
||||
joinstring(&s, comma);
|
||||
t = reprobject(v->ob_item[i]);
|
||||
joinstring(&s, t);
|
||||
DECREF(t);
|
||||
}
|
||||
DECREF(comma);
|
||||
t = newstringobject("]");
|
||||
joinstring(&s, t);
|
||||
DECREF(t);
|
||||
return s;
|
||||
}
|
||||
|
||||
static int
|
||||
list_compare(v, w)
|
||||
listobject *v, *w;
|
||||
{
|
||||
int len = (v->ob_size < w->ob_size) ? v->ob_size : w->ob_size;
|
||||
int i;
|
||||
for (i = 0; i < len; i++) {
|
||||
int cmp = cmpobject(v->ob_item[i], w->ob_item[i]);
|
||||
if (cmp != 0)
|
||||
return cmp;
|
||||
}
|
||||
return v->ob_size - w->ob_size;
|
||||
}
|
||||
|
||||
static int
|
||||
list_length(a)
|
||||
listobject *a;
|
||||
{
|
||||
return a->ob_size;
|
||||
}
|
||||
|
||||
static object *
|
||||
list_item(a, i)
|
||||
listobject *a;
|
||||
int i;
|
||||
{
|
||||
if (i < 0 || i >= a->ob_size) {
|
||||
errno = EDOM;
|
||||
return NULL;
|
||||
}
|
||||
INCREF(a->ob_item[i]);
|
||||
return a->ob_item[i];
|
||||
}
|
||||
|
||||
static object *
|
||||
list_slice(a, ilow, ihigh)
|
||||
listobject *a;
|
||||
int ilow, ihigh;
|
||||
{
|
||||
listobject *np;
|
||||
int i;
|
||||
if (ilow < 0)
|
||||
ilow = 0;
|
||||
else if (ilow > a->ob_size)
|
||||
ilow = a->ob_size;
|
||||
if (ihigh < 0)
|
||||
ihigh = 0;
|
||||
if (ihigh < ilow)
|
||||
ihigh = ilow;
|
||||
else if (ihigh > a->ob_size)
|
||||
ihigh = a->ob_size;
|
||||
np = (listobject *) newlistobject(ihigh - ilow);
|
||||
if (np == NULL)
|
||||
return NULL;
|
||||
for (i = ilow; i < ihigh; i++) {
|
||||
object *v = a->ob_item[i];
|
||||
INCREF(v);
|
||||
np->ob_item[i - ilow] = v;
|
||||
}
|
||||
return (object *)np;
|
||||
}
|
||||
|
||||
static object *
|
||||
list_concat(a, bb)
|
||||
listobject *a;
|
||||
object *bb;
|
||||
{
|
||||
int size;
|
||||
int i;
|
||||
listobject *np;
|
||||
if (!is_listobject(bb)) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
#define b ((listobject *)bb)
|
||||
size = a->ob_size + b->ob_size;
|
||||
np = (listobject *) newlistobject(size);
|
||||
if (np == NULL) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
for (i = 0; i < a->ob_size; i++) {
|
||||
object *v = a->ob_item[i];
|
||||
INCREF(v);
|
||||
np->ob_item[i] = v;
|
||||
}
|
||||
for (i = 0; i < b->ob_size; i++) {
|
||||
object *v = b->ob_item[i];
|
||||
INCREF(v);
|
||||
np->ob_item[i + a->ob_size] = v;
|
||||
}
|
||||
return (object *)np;
|
||||
#undef b
|
||||
}
|
||||
|
||||
static int
|
||||
list_ass_item(a, i, v)
|
||||
listobject *a;
|
||||
int i;
|
||||
object *v;
|
||||
{
|
||||
if (i < 0 || i >= a->ob_size)
|
||||
return errno = EDOM;
|
||||
if (v == NULL)
|
||||
return list_ass_slice(a, i, i+1, v);
|
||||
INCREF(v);
|
||||
DECREF(a->ob_item[i]);
|
||||
a->ob_item[i] = v;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
list_ass_slice(a, ilow, ihigh, v)
|
||||
listobject *a;
|
||||
int ilow, ihigh;
|
||||
object *v;
|
||||
{
|
||||
object **item;
|
||||
int n; /* Size of replacement list */
|
||||
int d; /* Change in size */
|
||||
int k; /* Loop index */
|
||||
#define b ((listobject *)v)
|
||||
if (v == NULL)
|
||||
n = 0;
|
||||
else if (is_listobject(v))
|
||||
n = b->ob_size;
|
||||
else
|
||||
return errno = EINVAL;
|
||||
if (ilow < 0)
|
||||
ilow = 0;
|
||||
else if (ilow > a->ob_size)
|
||||
ilow = a->ob_size;
|
||||
if (ihigh < 0)
|
||||
ihigh = 0;
|
||||
if (ihigh < ilow)
|
||||
ihigh = ilow;
|
||||
else if (ihigh > a->ob_size)
|
||||
ihigh = a->ob_size;
|
||||
item = a->ob_item;
|
||||
d = n - (ihigh-ilow);
|
||||
if (d <= 0) { /* Delete -d items; DECREF ihigh-ilow items */
|
||||
for (k = ilow; k < ihigh; k++)
|
||||
DECREF(item[k]);
|
||||
if (d < 0) {
|
||||
for (/*k = ihigh*/; k < a->ob_size; k++)
|
||||
item[k+d] = item[k];
|
||||
a->ob_size += d;
|
||||
RESIZE(item, object *, a->ob_size); /* Can't fail */
|
||||
a->ob_item = item;
|
||||
}
|
||||
}
|
||||
else { /* Insert d items; DECREF ihigh-ilow items */
|
||||
RESIZE(item, object *, a->ob_size + d);
|
||||
if (item == NULL)
|
||||
return errno = ENOMEM;
|
||||
for (k = a->ob_size; --k >= ihigh; )
|
||||
item[k+d] = item[k];
|
||||
for (/*k = ihigh-1*/; k >= ilow; --k)
|
||||
DECREF(item[k]);
|
||||
a->ob_item = item;
|
||||
a->ob_size += d;
|
||||
}
|
||||
for (k = 0; k < n; k++, ilow++) {
|
||||
object *w = b->ob_item[k];
|
||||
INCREF(w);
|
||||
item[ilow] = w;
|
||||
}
|
||||
return 0;
|
||||
#undef b
|
||||
}
|
||||
|
||||
static object *
|
||||
ins(self, where, v)
|
||||
listobject *self;
|
||||
int where;
|
||||
object *v;
|
||||
{
|
||||
if (ins1(self, where, v) != 0)
|
||||
return NULL;
|
||||
INCREF(None);
|
||||
return None;
|
||||
}
|
||||
|
||||
static object *
|
||||
listinsert(self, args)
|
||||
listobject *self;
|
||||
object *args;
|
||||
{
|
||||
int i;
|
||||
if (args == NULL || !is_tupleobject(args) || gettuplesize(args) != 2) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
if (!getintarg(gettupleitem(args, 0), &i))
|
||||
return NULL;
|
||||
return ins(self, i, gettupleitem(args, 1));
|
||||
}
|
||||
|
||||
static object *
|
||||
listappend(self, args)
|
||||
listobject *self;
|
||||
object *args;
|
||||
{
|
||||
return ins(self, (int) self->ob_size, args);
|
||||
}
|
||||
|
||||
static int
|
||||
cmp(v, w)
|
||||
char *v, *w;
|
||||
{
|
||||
return cmpobject(* (object **) v, * (object **) w);
|
||||
}
|
||||
|
||||
static object *
|
||||
listsort(self, args)
|
||||
listobject *self;
|
||||
object *args;
|
||||
{
|
||||
if (args != NULL) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
errno = 0;
|
||||
if (self->ob_size > 1)
|
||||
qsort((char *)self->ob_item,
|
||||
(int) self->ob_size, sizeof(object *), cmp);
|
||||
if (errno != 0)
|
||||
return NULL;
|
||||
INCREF(None);
|
||||
return None;
|
||||
}
|
||||
|
||||
static struct methodlist list_methods[] = {
|
||||
{"append", listappend},
|
||||
{"insert", listinsert},
|
||||
{"sort", listsort},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
static object *
|
||||
list_getattr(f, name)
|
||||
listobject *f;
|
||||
char *name;
|
||||
{
|
||||
return findmethod(list_methods, (object *)f, name);
|
||||
}
|
||||
|
||||
static sequence_methods list_as_sequence = {
|
||||
list_length, /*sq_length*/
|
||||
list_concat, /*sq_concat*/
|
||||
0, /*sq_repeat*/
|
||||
list_item, /*sq_item*/
|
||||
list_slice, /*sq_slice*/
|
||||
list_ass_item, /*sq_ass_item*/
|
||||
list_ass_slice, /*sq_ass_slice*/
|
||||
};
|
||||
|
||||
typeobject Listtype = {
|
||||
OB_HEAD_INIT(&Typetype)
|
||||
0,
|
||||
"list",
|
||||
sizeof(listobject),
|
||||
0,
|
||||
list_dealloc, /*tp_dealloc*/
|
||||
list_print, /*tp_print*/
|
||||
list_getattr, /*tp_getattr*/
|
||||
0, /*tp_setattr*/
|
||||
list_compare, /*tp_compare*/
|
||||
list_repr, /*tp_repr*/
|
||||
0, /*tp_as_number*/
|
||||
&list_as_sequence, /*tp_as_sequence*/
|
||||
0, /*tp_as_mapping*/
|
||||
};
|
|
@ -0,0 +1,113 @@
|
|||
/* Method object implementation */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "PROTO.h"
|
||||
#include "object.h"
|
||||
#include "node.h"
|
||||
#include "stringobject.h"
|
||||
#include "methodobject.h"
|
||||
#include "objimpl.h"
|
||||
#include "token.h"
|
||||
|
||||
typedef struct {
|
||||
OB_HEAD
|
||||
char *m_name;
|
||||
method m_meth;
|
||||
object *m_self;
|
||||
} methodobject;
|
||||
|
||||
object *
|
||||
newmethodobject(name, meth, self)
|
||||
char *name; /* static string */
|
||||
method meth;
|
||||
object *self;
|
||||
{
|
||||
methodobject *op = NEWOBJ(methodobject, &Methodtype);
|
||||
if (op != NULL) {
|
||||
op->m_name = name;
|
||||
op->m_meth = meth;
|
||||
if (self != NULL)
|
||||
INCREF(self);
|
||||
op->m_self = self;
|
||||
}
|
||||
return (object *)op;
|
||||
}
|
||||
|
||||
method
|
||||
getmethod(op)
|
||||
object *op;
|
||||
{
|
||||
if (!is_methodobject(op)) {
|
||||
errno = EBADF;
|
||||
return NULL;
|
||||
}
|
||||
return ((methodobject *)op) -> m_meth;
|
||||
}
|
||||
|
||||
object *
|
||||
getself(op)
|
||||
object *op;
|
||||
{
|
||||
if (!is_methodobject(op)) {
|
||||
errno = EBADF;
|
||||
return NULL;
|
||||
}
|
||||
return ((methodobject *)op) -> m_self;
|
||||
}
|
||||
|
||||
/* Methods (the standard built-in methods, that is) */
|
||||
|
||||
static void
|
||||
meth_dealloc(m)
|
||||
methodobject *m;
|
||||
{
|
||||
if (m->m_self != NULL)
|
||||
DECREF(m->m_self);
|
||||
free((char *)m);
|
||||
}
|
||||
|
||||
static void
|
||||
meth_print(m, fp, flags)
|
||||
methodobject *m;
|
||||
FILE *fp;
|
||||
int flags;
|
||||
{
|
||||
if (m->m_self == NULL)
|
||||
fprintf(fp, "<%s method>", m->m_name);
|
||||
else
|
||||
fprintf(fp, "<%s method of %s object at %lx>",
|
||||
m->m_name, m->m_self->ob_type->tp_name,
|
||||
(long)m->m_self);
|
||||
}
|
||||
|
||||
static object *
|
||||
meth_repr(m)
|
||||
methodobject *m;
|
||||
{
|
||||
char buf[200];
|
||||
if (m->m_self == NULL)
|
||||
sprintf(buf, "<%.80s method>", m->m_name);
|
||||
else
|
||||
sprintf(buf, "<%.80s method of %.80s object at %lx>",
|
||||
m->m_name, m->m_self->ob_type->tp_name,
|
||||
(long)m->m_self);
|
||||
return newstringobject(buf);
|
||||
}
|
||||
|
||||
typeobject Methodtype = {
|
||||
OB_HEAD_INIT(&Typetype)
|
||||
0,
|
||||
"method",
|
||||
sizeof(methodobject),
|
||||
0,
|
||||
meth_dealloc, /*tp_dealloc*/
|
||||
meth_print, /*tp_print*/
|
||||
0, /*tp_getattr*/
|
||||
0, /*tp_setattr*/
|
||||
0, /*tp_compare*/
|
||||
meth_repr, /*tp_repr*/
|
||||
0, /*tp_as_number*/
|
||||
0, /*tp_as_sequence*/
|
||||
0, /*tp_as_mapping*/
|
||||
};
|
|
@ -0,0 +1,130 @@
|
|||
/* Module object implementation */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "PROTO.h"
|
||||
#include "object.h"
|
||||
#include "stringobject.h"
|
||||
#include "dictobject.h"
|
||||
#include "moduleobject.h"
|
||||
#include "objimpl.h"
|
||||
|
||||
typedef struct {
|
||||
OB_HEAD
|
||||
object *md_name;
|
||||
object *md_dict;
|
||||
} moduleobject;
|
||||
|
||||
object *
|
||||
newmoduleobject(name)
|
||||
char *name;
|
||||
{
|
||||
moduleobject *m = NEWOBJ(moduleobject, &Moduletype);
|
||||
if (m == NULL)
|
||||
return NULL;
|
||||
m->md_name = newstringobject(name);
|
||||
m->md_dict = newdictobject();
|
||||
if (m->md_name == NULL || m->md_dict == NULL) {
|
||||
DECREF(m);
|
||||
return NULL;
|
||||
}
|
||||
return (object *)m;
|
||||
}
|
||||
|
||||
object *
|
||||
getmoduledict(m)
|
||||
object *m;
|
||||
{
|
||||
if (!is_moduleobject(m)) {
|
||||
errno = EBADF;
|
||||
return NULL;
|
||||
}
|
||||
return ((moduleobject *)m) -> md_dict;
|
||||
}
|
||||
|
||||
int
|
||||
setmoduledict(m, v)
|
||||
object *m;
|
||||
object *v;
|
||||
{
|
||||
if (!is_moduleobject(m))
|
||||
return errno = EBADF;
|
||||
if (!is_dictobject(v))
|
||||
return errno = EINVAL;
|
||||
DECREF(((moduleobject *)m) -> md_dict);
|
||||
INCREF(v);
|
||||
((moduleobject *)m) -> md_dict = v;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Methods */
|
||||
|
||||
static void
|
||||
moduledealloc(m)
|
||||
moduleobject *m;
|
||||
{
|
||||
if (m->md_name != NULL)
|
||||
DECREF(m->md_name);
|
||||
if (m->md_dict != NULL)
|
||||
DECREF(m->md_dict);
|
||||
free((char *)m);
|
||||
}
|
||||
|
||||
static void
|
||||
moduleprint(m, fp, flags)
|
||||
moduleobject *m;
|
||||
FILE *fp;
|
||||
int flags;
|
||||
{
|
||||
fprintf(fp, "<module %s>", getstringvalue(m->md_name));
|
||||
}
|
||||
|
||||
static object *
|
||||
modulerepr(m)
|
||||
moduleobject *m;
|
||||
{
|
||||
char buf[100];
|
||||
sprintf(buf, "<module %.80s>", getstringvalue(m->md_name));
|
||||
return newstringobject(buf);
|
||||
}
|
||||
|
||||
static object *
|
||||
modulegetattr(m, name)
|
||||
moduleobject *m;
|
||||
char *name;
|
||||
{
|
||||
object *res = dictlookup(m->md_dict, name);
|
||||
if (res == NULL) {
|
||||
if (errno == ENOENT)
|
||||
errno = ESRCH;
|
||||
}
|
||||
else
|
||||
INCREF(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int
|
||||
modulesetattr(m, name, v)
|
||||
moduleobject *m;
|
||||
char *name;
|
||||
object *v;
|
||||
{
|
||||
if (v == NULL)
|
||||
return dictremove(m->md_dict, name);
|
||||
else
|
||||
return dictinsert(m->md_dict, name, v);
|
||||
}
|
||||
|
||||
typeobject Moduletype = {
|
||||
OB_HEAD_INIT(&Typetype)
|
||||
0, /*ob_size*/
|
||||
"module", /*tp_name*/
|
||||
sizeof(moduleobject), /*tp_size*/
|
||||
0, /*tp_itemsize*/
|
||||
moduledealloc, /*tp_dealloc*/
|
||||
moduleprint, /*tp_print*/
|
||||
modulegetattr, /*tp_getattr*/
|
||||
modulesetattr, /*tp_setattr*/
|
||||
0, /*tp_compare*/
|
||||
modulerepr, /*tp_repr*/
|
||||
};
|
|
@ -0,0 +1,195 @@
|
|||
/* Object implementation; and 'noobject' implementation */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "PROTO.h"
|
||||
#include "object.h"
|
||||
#include "stringobject.h"
|
||||
#include "objimpl.h"
|
||||
#include "errors.h"
|
||||
|
||||
extern object *err_nomem PROTO((void)); /* XXX from modsupport.c */
|
||||
|
||||
int StopPrint; /* Flag to indicate printing must be stopped */
|
||||
|
||||
/* Object allocation routines used by NEWOBJ and NEWVAROBJ macros */
|
||||
|
||||
object *
|
||||
newobject(tp)
|
||||
typeobject *tp;
|
||||
{
|
||||
object *op = (object *) malloc(tp->tp_basicsize);
|
||||
if (op == NULL)
|
||||
return err_nomem();
|
||||
NEWREF(op);
|
||||
op->ob_type = tp;
|
||||
return op;
|
||||
}
|
||||
|
||||
#if 0 /* unused */
|
||||
|
||||
varobject *
|
||||
newvarobject(tp, size)
|
||||
typeobject *tp;
|
||||
unsigned int size;
|
||||
{
|
||||
varobject *op = (varobject *)
|
||||
malloc(tp->tp_basicsize + size * tp->tp_itemsize);
|
||||
if (op == NULL)
|
||||
return err_nomem();
|
||||
NEWREF(op);
|
||||
op->ob_type = tp;
|
||||
op->ob_size = size;
|
||||
return op;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int prlevel;
|
||||
|
||||
void
|
||||
printobject(op, fp, flags)
|
||||
object *op;
|
||||
FILE *fp;
|
||||
int flags;
|
||||
{
|
||||
/* Hacks to make printing a long or recursive object interruptible */
|
||||
prlevel++;
|
||||
if (!StopPrint && intrcheck()) {
|
||||
fprintf(fp, "\n[print interrupted]\n");
|
||||
StopPrint = 1;
|
||||
}
|
||||
if (!StopPrint) {
|
||||
if (op == NULL) {
|
||||
fprintf(fp, "<nil>");
|
||||
}
|
||||
else if (op->ob_type->tp_print == NULL) {
|
||||
fprintf(fp, "<%s object at %lx>",
|
||||
op->ob_type->tp_name, (long)op);
|
||||
}
|
||||
else {
|
||||
(*op->ob_type->tp_print)(op, fp, flags);
|
||||
}
|
||||
}
|
||||
prlevel--;
|
||||
if (prlevel == 0)
|
||||
StopPrint = 0;
|
||||
}
|
||||
|
||||
object *
|
||||
reprobject(v)
|
||||
object *v;
|
||||
{
|
||||
object *w;
|
||||
/* Hacks to make converting a long or recursive object interruptible */
|
||||
prlevel++;
|
||||
if (!StopPrint && intrcheck()) {
|
||||
StopPrint = 1;
|
||||
w = NULL;
|
||||
err_set(KeyboardInterrupt);
|
||||
}
|
||||
if (!StopPrint) {
|
||||
if (v == NULL) {
|
||||
w = newstringobject("<nil>");
|
||||
}
|
||||
else if (v->ob_type->tp_repr == NULL) {
|
||||
char buf[100];
|
||||
sprintf(buf, "<%.80s object at %lx>",
|
||||
v->ob_type->tp_name, (long)v);
|
||||
w = newstringobject(buf);
|
||||
}
|
||||
else {
|
||||
w = (*v->ob_type->tp_repr)(v);
|
||||
}
|
||||
}
|
||||
prlevel--;
|
||||
if (prlevel == 0)
|
||||
StopPrint = 0;
|
||||
return w;
|
||||
}
|
||||
|
||||
int
|
||||
cmpobject(v, w)
|
||||
object *v, *w;
|
||||
{
|
||||
typeobject *tp;
|
||||
if (v == w)
|
||||
return 0;
|
||||
if (v == NULL)
|
||||
return -1;
|
||||
if (w == NULL)
|
||||
return 1;
|
||||
if ((tp = v->ob_type) != w->ob_type)
|
||||
return strcmp(tp->tp_name, w->ob_type->tp_name);
|
||||
if (tp->tp_compare == NULL)
|
||||
return (v < w) ? -1 : 1;
|
||||
return ((*tp->tp_compare)(v, w));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
NoObject is usable as a non-NULL undefined value, used by the macro None.
|
||||
There is (and should be!) no way to create other objects of this type,
|
||||
so there is exactly one.
|
||||
*/
|
||||
|
||||
static void
|
||||
noprint(op, fp, flags)
|
||||
object *op;
|
||||
FILE *fp;
|
||||
int flags;
|
||||
{
|
||||
fprintf(fp, "<no value>");
|
||||
}
|
||||
|
||||
static typeobject Notype = {
|
||||
OB_HEAD_INIT(&Typetype)
|
||||
0,
|
||||
"novalue",
|
||||
0,
|
||||
0,
|
||||
0, /*tp_dealloc*/ /*never called*/
|
||||
noprint, /*tp_print*/
|
||||
};
|
||||
|
||||
object NoObject = {
|
||||
OB_HEAD_INIT(&Notype)
|
||||
};
|
||||
|
||||
|
||||
#ifdef TRACE_REFS
|
||||
|
||||
static object refchain = {&refchain, &refchain};
|
||||
|
||||
NEWREF(op)
|
||||
object *op;
|
||||
{
|
||||
ref_total++;
|
||||
op->ob_refcnt = 1;
|
||||
op->_ob_next = refchain._ob_next;
|
||||
op->_ob_prev = &refchain;
|
||||
refchain._ob_next->_ob_prev = op;
|
||||
refchain._ob_next = op;
|
||||
}
|
||||
|
||||
DELREF(op)
|
||||
object *op;
|
||||
{
|
||||
op->_ob_next->_ob_prev = op->_ob_prev;
|
||||
op->_ob_prev->_ob_next = op->_ob_next;
|
||||
(*(op)->ob_type->tp_dealloc)(op);
|
||||
}
|
||||
|
||||
printrefs(fp)
|
||||
FILE *fp;
|
||||
{
|
||||
object *op;
|
||||
fprintf(fp, "Remaining objects:\n");
|
||||
for (op = refchain._ob_next; op != &refchain; op = op->_ob_next) {
|
||||
fprintf(fp, "[%d] ", op->ob_refcnt);
|
||||
printobject(op, fp, 0);
|
||||
putc('\n', fp);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,328 @@
|
|||
/* String object implementation */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "PROTO.h"
|
||||
#include "object.h"
|
||||
#include "stringobject.h"
|
||||
#include "intobject.h"
|
||||
#include "objimpl.h"
|
||||
|
||||
object *
|
||||
newsizedstringobject(str, size)
|
||||
char *str;
|
||||
int size;
|
||||
{
|
||||
register stringobject *op = (stringobject *)
|
||||
malloc(sizeof(stringobject) + size * sizeof(char));
|
||||
if (op == NULL) {
|
||||
errno = ENOMEM;
|
||||
}
|
||||
else {
|
||||
NEWREF(op);
|
||||
op->ob_type = &Stringtype;
|
||||
op->ob_size = size;
|
||||
if (str != NULL)
|
||||
memcpy(op->ob_sval, str, size);
|
||||
op->ob_sval[size] = '\0';
|
||||
}
|
||||
return (object *) op;
|
||||
}
|
||||
|
||||
object *
|
||||
newstringobject(str)
|
||||
char *str;
|
||||
{
|
||||
register unsigned int size = strlen(str);
|
||||
register stringobject *op = (stringobject *)
|
||||
malloc(sizeof(stringobject) + size * sizeof(char));
|
||||
if (op == NULL) {
|
||||
errno = ENOMEM;
|
||||
}
|
||||
else {
|
||||
NEWREF(op);
|
||||
op->ob_type = &Stringtype;
|
||||
op->ob_size = size;
|
||||
strcpy(op->ob_sval, str);
|
||||
}
|
||||
return (object *) op;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
getstringsize(op)
|
||||
register object *op;
|
||||
{
|
||||
if (!is_stringobject(op)) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
return ((stringobject *)op) -> ob_size;
|
||||
}
|
||||
|
||||
/*const*/ char *
|
||||
getstringvalue(op)
|
||||
register object *op;
|
||||
{
|
||||
if (!is_stringobject(op)) {
|
||||
errno = EBADF;
|
||||
return NULL;
|
||||
}
|
||||
return ((stringobject *)op) -> ob_sval;
|
||||
}
|
||||
|
||||
/* Methods */
|
||||
|
||||
static void
|
||||
stringprint(op, fp, flags)
|
||||
stringobject *op;
|
||||
FILE *fp;
|
||||
int flags;
|
||||
{
|
||||
int i;
|
||||
char c;
|
||||
if (flags & PRINT_RAW) {
|
||||
fwrite(op->ob_sval, 1, (int) op->ob_size, fp);
|
||||
return;
|
||||
}
|
||||
fprintf(fp, "'");
|
||||
for (i = 0; i < op->ob_size; i++) {
|
||||
c = op->ob_sval[i];
|
||||
if (c == '\'' || c == '\\')
|
||||
fprintf(fp, "\\%c", c);
|
||||
else if (c < ' ' || c >= 0177)
|
||||
fprintf(fp, "\\%03o", c&0377);
|
||||
else
|
||||
putc(c, fp);
|
||||
}
|
||||
fprintf(fp, "'");
|
||||
}
|
||||
|
||||
static object *
|
||||
stringrepr(op)
|
||||
register stringobject *op;
|
||||
{
|
||||
/* XXX overflow? */
|
||||
int newsize = 2 + 4 * op->ob_size * sizeof(char);
|
||||
object *v = newsizedstringobject((char *)NULL, newsize);
|
||||
if (v == NULL) {
|
||||
errno = ENOMEM;
|
||||
}
|
||||
else {
|
||||
register int i;
|
||||
register char c;
|
||||
register char *p;
|
||||
NEWREF(v);
|
||||
v->ob_type = &Stringtype;
|
||||
((stringobject *)v)->ob_size = newsize;
|
||||
p = ((stringobject *)v)->ob_sval;
|
||||
*p++ = '\'';
|
||||
for (i = 0; i < op->ob_size; i++) {
|
||||
c = op->ob_sval[i];
|
||||
if (c == '\'' || c == '\\')
|
||||
*p++ = '\\', *p++ = c;
|
||||
else if (c < ' ' || c >= 0177) {
|
||||
sprintf(p, "\\%03o", c&0377);
|
||||
while (*p != '\0')
|
||||
p++;
|
||||
|
||||
}
|
||||
else
|
||||
*p++ = c;
|
||||
}
|
||||
*p++ = '\'';
|
||||
*p = '\0';
|
||||
resizestring(&v, (int) (p - ((stringobject *)v)->ob_sval));
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
static int
|
||||
stringlength(a)
|
||||
stringobject *a;
|
||||
{
|
||||
return a->ob_size;
|
||||
}
|
||||
|
||||
static object *
|
||||
stringconcat(a, bb)
|
||||
register stringobject *a;
|
||||
register object *bb;
|
||||
{
|
||||
register unsigned int size;
|
||||
register stringobject *op;
|
||||
if (!is_stringobject(bb)) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
#define b ((stringobject *)bb)
|
||||
/* Optimize cases with empty left or right operand */
|
||||
if (a->ob_size == 0) {
|
||||
INCREF(bb);
|
||||
return bb;
|
||||
}
|
||||
if (b->ob_size == 0) {
|
||||
INCREF(a);
|
||||
return (object *)a;
|
||||
}
|
||||
size = a->ob_size + b->ob_size;
|
||||
op = (stringobject *)
|
||||
malloc(sizeof(stringobject) + size * sizeof(char));
|
||||
if (op == NULL) {
|
||||
errno = ENOMEM;
|
||||
}
|
||||
else {
|
||||
NEWREF(op);
|
||||
op->ob_type = &Stringtype;
|
||||
op->ob_size = size;
|
||||
memcpy(op->ob_sval, a->ob_sval, (int) a->ob_size);
|
||||
memcpy(op->ob_sval + a->ob_size, b->ob_sval, (int) b->ob_size);
|
||||
op->ob_sval[size] = '\0';
|
||||
}
|
||||
return (object *) op;
|
||||
#undef b
|
||||
}
|
||||
|
||||
static object *
|
||||
stringrepeat(a, n)
|
||||
register stringobject *a;
|
||||
register int n;
|
||||
{
|
||||
register int i;
|
||||
register unsigned int size;
|
||||
register stringobject *op;
|
||||
if (n < 0)
|
||||
n = 0;
|
||||
size = a->ob_size * n;
|
||||
if (size == a->ob_size) {
|
||||
INCREF(a);
|
||||
return (object *)a;
|
||||
}
|
||||
op = (stringobject *)
|
||||
malloc(sizeof(stringobject) + size * sizeof(char));
|
||||
if (op == NULL) {
|
||||
errno = ENOMEM;
|
||||
}
|
||||
else {
|
||||
NEWREF(op);
|
||||
op->ob_type = &Stringtype;
|
||||
op->ob_size = size;
|
||||
for (i = 0; i < size; i += a->ob_size)
|
||||
memcpy(op->ob_sval+i, a->ob_sval, (int) a->ob_size);
|
||||
op->ob_sval[size] = '\0';
|
||||
}
|
||||
return (object *) op;
|
||||
}
|
||||
|
||||
/* String slice a[i:j] consists of characters a[i] ... a[j-1] */
|
||||
|
||||
static object *
|
||||
stringslice(a, i, j)
|
||||
register stringobject *a;
|
||||
register int i, j; /* May be negative! */
|
||||
{
|
||||
if (i < 0)
|
||||
i = 0;
|
||||
if (j < 0)
|
||||
j = 0; /* Avoid signed/unsigned bug in next line */
|
||||
if (j > a->ob_size)
|
||||
j = a->ob_size;
|
||||
if (i == 0 && j == a->ob_size) { /* It's the same as a */
|
||||
INCREF(a);
|
||||
return (object *)a;
|
||||
}
|
||||
if (j < i)
|
||||
j = i;
|
||||
return newsizedstringobject(a->ob_sval + i, (int) (j-i));
|
||||
}
|
||||
|
||||
static object *
|
||||
stringitem(a, i)
|
||||
stringobject *a;
|
||||
register int i;
|
||||
{
|
||||
if (i < 0 || i >= a->ob_size) {
|
||||
errno = EDOM;
|
||||
return NULL;
|
||||
}
|
||||
return stringslice(a, i, i+1);
|
||||
}
|
||||
|
||||
static int
|
||||
stringcompare(a, b)
|
||||
stringobject *a, *b;
|
||||
{
|
||||
/* XXX should use memcmp on shortest size, then compare lengths */
|
||||
return strcmp(a->ob_sval, b->ob_sval);
|
||||
}
|
||||
|
||||
static sequence_methods string_as_sequence = {
|
||||
stringlength, /*tp_length*/
|
||||
stringconcat, /*tp_concat*/
|
||||
stringrepeat, /*tp_repeat*/
|
||||
stringitem, /*tp_item*/
|
||||
stringslice, /*tp_slice*/
|
||||
0, /*tp_ass_item*/
|
||||
0, /*tp_ass_slice*/
|
||||
};
|
||||
|
||||
typeobject Stringtype = {
|
||||
OB_HEAD_INIT(&Typetype)
|
||||
0,
|
||||
"string",
|
||||
sizeof(stringobject),
|
||||
sizeof(char),
|
||||
free, /*tp_dealloc*/
|
||||
stringprint, /*tp_print*/
|
||||
0, /*tp_getattr*/
|
||||
0, /*tp_setattr*/
|
||||
stringcompare, /*tp_compare*/
|
||||
stringrepr, /*tp_repr*/
|
||||
0, /*tp_as_number*/
|
||||
&string_as_sequence, /*tp_as_sequence*/
|
||||
0, /*tp_as_mapping*/
|
||||
};
|
||||
|
||||
void
|
||||
joinstring(pv, w)
|
||||
register object **pv;
|
||||
register object *w;
|
||||
{
|
||||
register object *v;
|
||||
if (*pv == NULL || w == NULL || !is_stringobject(*pv))
|
||||
return;
|
||||
v = stringconcat((stringobject *) *pv, w);
|
||||
DECREF(*pv);
|
||||
*pv = v;
|
||||
}
|
||||
|
||||
/* The following function breaks the notion that strings are immutable:
|
||||
it changes the size of a string. We get away with this only if there
|
||||
is only one module referencing the object. You can also think of it
|
||||
as creating a new string object and destroying the old one, only
|
||||
more efficiently. In any case, don't use this if the string may
|
||||
already be known to some other part of the code... */
|
||||
|
||||
int
|
||||
resizestring(pv, newsize)
|
||||
object **pv;
|
||||
int newsize;
|
||||
{
|
||||
register stringobject *v;
|
||||
v = (stringobject *) *pv;
|
||||
if (!is_stringobject(v) || v->ob_refcnt != 1) {
|
||||
*pv = 0;
|
||||
DECREF(v);
|
||||
return errno = EBADF;
|
||||
}
|
||||
*pv = (object *)
|
||||
realloc((char *)v,
|
||||
sizeof(stringobject) + newsize * sizeof(char));
|
||||
if (*pv == NULL) {
|
||||
DECREF(v);
|
||||
return errno = ENOMEM;
|
||||
}
|
||||
v = (stringobject *) *pv;
|
||||
v->ob_size = newsize;
|
||||
v->ob_sval[newsize] = '\0';
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,276 @@
|
|||
/* Tuple object implementation */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "PROTO.h"
|
||||
#include "object.h"
|
||||
#include "stringobject.h"
|
||||
#include "tupleobject.h"
|
||||
#include "intobject.h"
|
||||
#include "objimpl.h"
|
||||
|
||||
typedef struct {
|
||||
OB_VARHEAD
|
||||
object *ob_item[1];
|
||||
} tupleobject;
|
||||
|
||||
object *
|
||||
newtupleobject(size)
|
||||
register int size;
|
||||
{
|
||||
register int i;
|
||||
register tupleobject *op;
|
||||
if (size < 0) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
op = (tupleobject *)
|
||||
malloc(sizeof(tupleobject) + size * sizeof(object *));
|
||||
if (op == NULL) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
NEWREF(op);
|
||||
op->ob_type = &Tupletype;
|
||||
op->ob_size = size;
|
||||
for (i = 0; i < size; i++)
|
||||
op->ob_item[i] = NULL;
|
||||
return (object *) op;
|
||||
}
|
||||
|
||||
int
|
||||
gettuplesize(op)
|
||||
register object *op;
|
||||
{
|
||||
if (!is_tupleobject(op)) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
return ((tupleobject *)op)->ob_size;
|
||||
}
|
||||
|
||||
object *
|
||||
gettupleitem(op, i)
|
||||
register object *op;
|
||||
register int i;
|
||||
{
|
||||
if (!is_tupleobject(op)) {
|
||||
errno = EBADF;
|
||||
return NULL;
|
||||
}
|
||||
if (i < 0 || i >= ((tupleobject *)op) -> ob_size) {
|
||||
errno = EDOM;
|
||||
return NULL;
|
||||
}
|
||||
return ((tupleobject *)op) -> ob_item[i];
|
||||
}
|
||||
|
||||
int
|
||||
settupleitem(op, i, newitem)
|
||||
register object *op;
|
||||
register int i;
|
||||
register object *newitem;
|
||||
{
|
||||
register object *olditem;
|
||||
if (!is_tupleobject(op)) {
|
||||
if (newitem != NULL)
|
||||
DECREF(newitem);
|
||||
return errno = EBADF;
|
||||
}
|
||||
if (i < 0 || i >= ((tupleobject *)op) -> ob_size) {
|
||||
if (newitem != NULL)
|
||||
DECREF(newitem);
|
||||
return errno = EDOM;
|
||||
}
|
||||
olditem = ((tupleobject *)op) -> ob_item[i];
|
||||
((tupleobject *)op) -> ob_item[i] = newitem;
|
||||
if (olditem != NULL)
|
||||
DECREF(olditem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Methods */
|
||||
|
||||
static void
|
||||
tupledealloc(op)
|
||||
register tupleobject *op;
|
||||
{
|
||||
register int i;
|
||||
for (i = 0; i < op->ob_size; i++) {
|
||||
if (op->ob_item[i] != NULL)
|
||||
DECREF(op->ob_item[i]);
|
||||
}
|
||||
free((ANY *)op);
|
||||
}
|
||||
|
||||
static void
|
||||
tupleprint(op, fp, flags)
|
||||
tupleobject *op;
|
||||
FILE *fp;
|
||||
int flags;
|
||||
{
|
||||
int i;
|
||||
fprintf(fp, "(");
|
||||
for (i = 0; i < op->ob_size && !StopPrint; i++) {
|
||||
if (i > 0) {
|
||||
fprintf(fp, ", ");
|
||||
}
|
||||
printobject(op->ob_item[i], fp, flags);
|
||||
}
|
||||
if (op->ob_size == 1)
|
||||
fprintf(fp, ",");
|
||||
fprintf(fp, ")");
|
||||
}
|
||||
|
||||
object *
|
||||
tuplerepr(v)
|
||||
tupleobject *v;
|
||||
{
|
||||
object *s, *t, *comma;
|
||||
int i;
|
||||
s = newstringobject("(");
|
||||
comma = newstringobject(", ");
|
||||
for (i = 0; i < v->ob_size && s != NULL; i++) {
|
||||
if (i > 0)
|
||||
joinstring(&s, comma);
|
||||
t = reprobject(v->ob_item[i]);
|
||||
joinstring(&s, t);
|
||||
if (t != NULL)
|
||||
DECREF(t);
|
||||
}
|
||||
DECREF(comma);
|
||||
if (v->ob_size == 1) {
|
||||
t = newstringobject(",");
|
||||
joinstring(&s, t);
|
||||
DECREF(t);
|
||||
}
|
||||
t = newstringobject(")");
|
||||
joinstring(&s, t);
|
||||
DECREF(t);
|
||||
return s;
|
||||
}
|
||||
|
||||
static int
|
||||
tuplecompare(v, w)
|
||||
register tupleobject *v, *w;
|
||||
{
|
||||
register int len =
|
||||
(v->ob_size < w->ob_size) ? v->ob_size : w->ob_size;
|
||||
register int i;
|
||||
for (i = 0; i < len; i++) {
|
||||
int cmp = cmpobject(v->ob_item[i], w->ob_item[i]);
|
||||
if (cmp != 0)
|
||||
return cmp;
|
||||
}
|
||||
return v->ob_size - w->ob_size;
|
||||
}
|
||||
|
||||
static int
|
||||
tuplelength(a)
|
||||
tupleobject *a;
|
||||
{
|
||||
return a->ob_size;
|
||||
}
|
||||
|
||||
static object *
|
||||
tupleitem(a, i)
|
||||
register tupleobject *a;
|
||||
register int i;
|
||||
{
|
||||
if (i < 0 || i >= a->ob_size) {
|
||||
errno = EDOM;
|
||||
return NULL;
|
||||
}
|
||||
INCREF(a->ob_item[i]);
|
||||
return a->ob_item[i];
|
||||
}
|
||||
|
||||
static object *
|
||||
tupleslice(a, ilow, ihigh)
|
||||
register tupleobject *a;
|
||||
register int ilow, ihigh;
|
||||
{
|
||||
register tupleobject *np;
|
||||
register int i;
|
||||
if (ilow < 0)
|
||||
ilow = 0;
|
||||
if (ihigh > a->ob_size)
|
||||
ihigh = a->ob_size;
|
||||
if (ihigh < ilow)
|
||||
ihigh = ilow;
|
||||
if (ilow == 0 && ihigh == a->ob_size) {
|
||||
/* XXX can only do this if tuples are immutable! */
|
||||
INCREF(a);
|
||||
return (object *)a;
|
||||
}
|
||||
np = (tupleobject *)newtupleobject(ihigh - ilow);
|
||||
if (np == NULL)
|
||||
return NULL;
|
||||
for (i = ilow; i < ihigh; i++) {
|
||||
object *v = a->ob_item[i];
|
||||
INCREF(v);
|
||||
np->ob_item[i - ilow] = v;
|
||||
}
|
||||
return (object *)np;
|
||||
}
|
||||
|
||||
static object *
|
||||
tupleconcat(a, bb)
|
||||
register tupleobject *a;
|
||||
register object *bb;
|
||||
{
|
||||
register int size;
|
||||
register int i;
|
||||
tupleobject *np;
|
||||
if (!is_tupleobject(bb)) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
#define b ((tupleobject *)bb)
|
||||
size = a->ob_size + b->ob_size;
|
||||
np = (tupleobject *) newtupleobject(size);
|
||||
if (np == NULL) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
for (i = 0; i < a->ob_size; i++) {
|
||||
object *v = a->ob_item[i];
|
||||
INCREF(v);
|
||||
np->ob_item[i] = v;
|
||||
}
|
||||
for (i = 0; i < b->ob_size; i++) {
|
||||
object *v = b->ob_item[i];
|
||||
INCREF(v);
|
||||
np->ob_item[i + a->ob_size] = v;
|
||||
}
|
||||
return (object *)np;
|
||||
#undef b
|
||||
}
|
||||
|
||||
static sequence_methods tuple_as_sequence = {
|
||||
tuplelength, /*sq_length*/
|
||||
tupleconcat, /*sq_concat*/
|
||||
0, /*sq_repeat*/
|
||||
tupleitem, /*sq_item*/
|
||||
tupleslice, /*sq_slice*/
|
||||
0, /*sq_ass_item*/
|
||||
0, /*sq_ass_slice*/
|
||||
};
|
||||
|
||||
typeobject Tupletype = {
|
||||
OB_HEAD_INIT(&Typetype)
|
||||
0,
|
||||
"tuple",
|
||||
sizeof(tupleobject) - sizeof(object *),
|
||||
sizeof(object *),
|
||||
tupledealloc, /*tp_dealloc*/
|
||||
tupleprint, /*tp_print*/
|
||||
0, /*tp_getattr*/
|
||||
0, /*tp_setattr*/
|
||||
tuplecompare, /*tp_compare*/
|
||||
tuplerepr, /*tp_repr*/
|
||||
0, /*tp_as_number*/
|
||||
&tuple_as_sequence, /*tp_as_sequence*/
|
||||
0, /*tp_as_mapping*/
|
||||
};
|
|
@ -0,0 +1,47 @@
|
|||
/* Type object implementation */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "PROTO.h"
|
||||
#include "object.h"
|
||||
#include "stringobject.h"
|
||||
#include "objimpl.h"
|
||||
|
||||
/* Type object implementation */
|
||||
|
||||
static void
|
||||
typeprint(v, fp, flags)
|
||||
typeobject *v;
|
||||
FILE *fp;
|
||||
int flags;
|
||||
{
|
||||
fprintf(fp, "<type '%s'>", v->tp_name);
|
||||
}
|
||||
|
||||
static object *
|
||||
typerepr(v)
|
||||
typeobject *v;
|
||||
{
|
||||
char buf[100];
|
||||
sprintf(buf, "<type '%.80s'>", v->tp_name);
|
||||
return newstringobject(buf);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
OB_HEAD
|
||||
long ob_ival;
|
||||
} intobject;
|
||||
|
||||
typeobject Typetype = {
|
||||
OB_HEAD_INIT(&Typetype)
|
||||
0, /* Number of items for varobject */
|
||||
"type", /* Name of this type */
|
||||
sizeof(typeobject), /* Basic object size */
|
||||
0, /* Item size for varobject */
|
||||
0, /*tp_dealloc*/
|
||||
typeprint, /*tp_print*/
|
||||
0, /*tp_getattr*/
|
||||
0, /*tp_setattr*/
|
||||
0, /*tp_compare*/
|
||||
typerepr, /*tp_repr*/
|
||||
};
|
|
@ -0,0 +1,94 @@
|
|||
/* Xx objects */
|
||||
|
||||
typedef struct {
|
||||
OB_HEAD
|
||||
object *x_attr; /* Attributes dictionary */
|
||||
} xxobject;
|
||||
|
||||
extern typeobject Xxtype; /* Really static, forward */
|
||||
|
||||
static xxobject *
|
||||
newxxobject(arg)
|
||||
object *arg;
|
||||
{
|
||||
textobject *xp;
|
||||
xp = NEWOBJ(xxobject, &Xxtype);
|
||||
if (xp == NULL)
|
||||
return NULL;
|
||||
xp->x_attr = NULL;
|
||||
return xp;
|
||||
}
|
||||
|
||||
/* Xx methods */
|
||||
|
||||
static void
|
||||
xx_dealloc(xp)
|
||||
xxobject *xp;
|
||||
{
|
||||
if (xp->x_attr != NULL)
|
||||
DECREF(xp->x_attr);
|
||||
DEL(xp);
|
||||
}
|
||||
|
||||
static object *
|
||||
xx_demo(self, args)
|
||||
xxobject *self;
|
||||
object *args;
|
||||
{
|
||||
if (!getnoarg(args))
|
||||
return NULL;
|
||||
INCREF(None);
|
||||
return None;
|
||||
}
|
||||
|
||||
static struct methodlist xx_methods[] = {
|
||||
"demo", xx_demo,
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
static object *
|
||||
xx_getattr(xp, name)
|
||||
xxobject *xp;
|
||||
char *name;
|
||||
{
|
||||
if (xp->x_attr != NULL) {
|
||||
object *v = dictlookup(xp->x_attr, name);
|
||||
if (v != NULL) {
|
||||
INCREF(v);
|
||||
return v;
|
||||
}
|
||||
}
|
||||
return findmethod(xx_methods, (object *)xp, name);
|
||||
}
|
||||
|
||||
static int
|
||||
xx_setattr(xp, name, v)
|
||||
xxobject *xp;
|
||||
char *name;
|
||||
object *v;
|
||||
{
|
||||
if (xp->x_attr == NULL) {
|
||||
xp->x_attr = newdictobject();
|
||||
if (xp->x_attr == NULL)
|
||||
return errno;
|
||||
}
|
||||
if (v == NULL)
|
||||
return dictremove(xp->x_attr, name);
|
||||
else
|
||||
return dictinsert(xp->x_attr, name, v);
|
||||
}
|
||||
|
||||
static typeobject Xxtype = {
|
||||
OB_HEAD_INIT(&Typetype)
|
||||
0, /*ob_size*/
|
||||
"xx", /*tp_name*/
|
||||
sizeof(xxobject), /*tp_size*/
|
||||
0, /*tp_itemsize*/
|
||||
/* methods */
|
||||
xx_dealloc, /*tp_dealloc*/
|
||||
0, /*tp_print*/
|
||||
xx_getattr, /*tp_getattr*/
|
||||
xx_setattr, /*tp_setattr*/
|
||||
0, /*tp_compare*/
|
||||
0, /*tp_repr*/
|
||||
};
|
|
@ -0,0 +1,101 @@
|
|||
/* Parser accelerator module */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "PROTO.h"
|
||||
#include "grammar.h"
|
||||
#include "token.h"
|
||||
#include "malloc.h"
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
#define assert(e) { if (!(e)) { printf("Assertion failed\n"); abort(); } }
|
|
@ -0,0 +1,76 @@
|
|||
/* Bitset primitives */
|
||||
|
||||
#include "PROTO.h"
|
||||
#include "malloc.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++;
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
/* Computation of FIRST stets */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "PROTO.h"
|
||||
#include "malloc.h"
|
||||
#include "grammar.h"
|
||||
#include "token.h"
|
||||
|
||||
extern int debugging;
|
||||
|
||||
static void
|
||||
calcfirstset(g, d)
|
||||
grammar *g;
|
||||
dfa *d;
|
||||
{
|
||||
int i, j;
|
||||
state *s;
|
||||
arc *a;
|
||||
int nsyms;
|
||||
int *sym;
|
||||
int nbits;
|
||||
static bitset dummy;
|
||||
bitset result;
|
||||
int type;
|
||||
dfa *d1;
|
||||
label *l0;
|
||||
|
||||
if (debugging)
|
||||
printf("Calculate FIRST set for '%s'\n", d->d_name);
|
||||
|
||||
if (dummy == NULL)
|
||||
dummy = newbitset(1);
|
||||
if (d->d_first == dummy) {
|
||||
fprintf(stderr, "Left-recursion for '%s'\n", d->d_name);
|
||||
return;
|
||||
}
|
||||
if (d->d_first != NULL) {
|
||||
fprintf(stderr, "Re-calculating FIRST set for '%s' ???\n",
|
||||
d->d_name);
|
||||
}
|
||||
d->d_first = dummy;
|
||||
|
||||
l0 = g->g_ll.ll_label;
|
||||
nbits = g->g_ll.ll_nlabels;
|
||||
result = newbitset(nbits);
|
||||
|
||||
sym = NEW(int, 1);
|
||||
if (sym == NULL)
|
||||
fatal("no mem for new sym in calcfirstset");
|
||||
nsyms = 1;
|
||||
sym[0] = findlabel(&g->g_ll, d->d_type, (char *)NULL);
|
||||
|
||||
s = &d->d_state[d->d_initial];
|
||||
for (i = 0; i < s->s_narcs; i++) {
|
||||
a = &s->s_arc[i];
|
||||
for (j = 0; j < nsyms; j++) {
|
||||
if (sym[j] == a->a_lbl)
|
||||
break;
|
||||
}
|
||||
if (j >= nsyms) { /* New label */
|
||||
RESIZE(sym, int, nsyms + 1);
|
||||
if (sym == NULL)
|
||||
fatal("no mem to resize sym in calcfirstset");
|
||||
sym[nsyms++] = a->a_lbl;
|
||||
type = l0[a->a_lbl].lb_type;
|
||||
if (ISNONTERMINAL(type)) {
|
||||
d1 = finddfa(g, type);
|
||||
if (d1->d_first == dummy) {
|
||||
fprintf(stderr,
|
||||
"Left-recursion below '%s'\n",
|
||||
d->d_name);
|
||||
}
|
||||
else {
|
||||
if (d1->d_first == NULL)
|
||||
calcfirstset(g, d1);
|
||||
mergebitset(result, d1->d_first, nbits);
|
||||
}
|
||||
}
|
||||
else if (ISTERMINAL(type)) {
|
||||
addbit(result, a->a_lbl);
|
||||
}
|
||||
}
|
||||
}
|
||||
d->d_first = result;
|
||||
if (debugging) {
|
||||
printf("FIRST set for '%s': {", d->d_name);
|
||||
for (i = 0; i < nbits; i++) {
|
||||
if (testbit(result, i))
|
||||
printf(" %s", labelrepr(&l0[i]));
|
||||
}
|
||||
printf(" }\n");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
addfirstsets(g)
|
||||
grammar *g;
|
||||
{
|
||||
int i;
|
||||
dfa *d;
|
||||
|
||||
printf("Adding FIRST sets ...\n");
|
||||
for (i = 0; i < g->g_ndfas; i++) {
|
||||
d = &g->g_dfa[i];
|
||||
if (d->d_first == NULL)
|
||||
calcfirstset(g, d);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,207 @@
|
|||
/* Grammar implementation */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "PROTO.h"
|
||||
#include "malloc.h"
|
||||
#include "assert.h"
|
||||
#include "token.h"
|
||||
#include "grammar.h"
|
||||
|
||||
extern int debugging;
|
||||
|
||||
grammar *
|
||||
newgrammar(start)
|
||||
int start;
|
||||
{
|
||||
grammar *g;
|
||||
|
||||
g = NEW(grammar, 1);
|
||||
if (g == NULL)
|
||||
fatal("no mem for new grammar");
|
||||
g->g_ndfas = 0;
|
||||
g->g_dfa = NULL;
|
||||
g->g_start = start;
|
||||
g->g_ll.ll_nlabels = 0;
|
||||
g->g_ll.ll_label = NULL;
|
||||
return g;
|
||||
}
|
||||
|
||||
dfa *
|
||||
adddfa(g, type, name)
|
||||
grammar *g;
|
||||
int type;
|
||||
char *name;
|
||||
{
|
||||
dfa *d;
|
||||
|
||||
RESIZE(g->g_dfa, dfa, g->g_ndfas + 1);
|
||||
if (g->g_dfa == NULL)
|
||||
fatal("no mem to resize dfa in adddfa");
|
||||
d = &g->g_dfa[g->g_ndfas++];
|
||||
d->d_type = type;
|
||||
d->d_name = name;
|
||||
d->d_nstates = 0;
|
||||
d->d_state = NULL;
|
||||
d->d_initial = -1;
|
||||
d->d_first = NULL;
|
||||
return d; /* Only use while fresh! */
|
||||
}
|
||||
|
||||
int
|
||||
addstate(d)
|
||||
dfa *d;
|
||||
{
|
||||
state *s;
|
||||
|
||||
RESIZE(d->d_state, state, d->d_nstates + 1);
|
||||
if (d->d_state == NULL)
|
||||
fatal("no mem to resize state in addstate");
|
||||
s = &d->d_state[d->d_nstates++];
|
||||
s->s_narcs = 0;
|
||||
s->s_arc = NULL;
|
||||
return s - d->d_state;
|
||||
}
|
||||
|
||||
void
|
||||
addarc(d, from, to, lbl)
|
||||
dfa *d;
|
||||
int lbl;
|
||||
{
|
||||
state *s;
|
||||
arc *a;
|
||||
|
||||
assert(0 <= from && from < d->d_nstates);
|
||||
assert(0 <= to && to < d->d_nstates);
|
||||
|
||||
s = &d->d_state[from];
|
||||
RESIZE(s->s_arc, arc, s->s_narcs + 1);
|
||||
if (s->s_arc == NULL)
|
||||
fatal("no mem to resize arc list in addarc");
|
||||
a = &s->s_arc[s->s_narcs++];
|
||||
a->a_lbl = lbl;
|
||||
a->a_arrow = to;
|
||||
}
|
||||
|
||||
int
|
||||
addlabel(ll, type, str)
|
||||
labellist *ll;
|
||||
int type;
|
||||
char *str;
|
||||
{
|
||||
int i;
|
||||
label *lb;
|
||||
|
||||
for (i = 0; i < ll->ll_nlabels; i++) {
|
||||
if (ll->ll_label[i].lb_type == type &&
|
||||
strcmp(ll->ll_label[i].lb_str, str) == 0)
|
||||
return i;
|
||||
}
|
||||
RESIZE(ll->ll_label, label, ll->ll_nlabels + 1);
|
||||
if (ll->ll_label == NULL)
|
||||
fatal("no mem to resize labellist in addlabel");
|
||||
lb = &ll->ll_label[ll->ll_nlabels++];
|
||||
lb->lb_type = type;
|
||||
lb->lb_str = str; /* XXX strdup(str) ??? */
|
||||
return lb - ll->ll_label;
|
||||
}
|
||||
|
||||
/* Same, but rather dies than adds */
|
||||
|
||||
int
|
||||
findlabel(ll, type, str)
|
||||
labellist *ll;
|
||||
int type;
|
||||
char *str;
|
||||
{
|
||||
int i;
|
||||
label *lb;
|
||||
|
||||
for (i = 0; i < ll->ll_nlabels; i++) {
|
||||
if (ll->ll_label[i].lb_type == type /*&&
|
||||
strcmp(ll->ll_label[i].lb_str, str) == 0*/)
|
||||
return i;
|
||||
}
|
||||
fprintf(stderr, "Label %d/'%s' not found\n", type, str);
|
||||
abort();
|
||||
}
|
||||
|
||||
static void
|
||||
translabel(g, lb)
|
||||
grammar *g;
|
||||
label *lb;
|
||||
{
|
||||
int i;
|
||||
|
||||
if (debugging)
|
||||
printf("Translating label %s ...\n", labelrepr(lb));
|
||||
|
||||
if (lb->lb_type == NAME) {
|
||||
for (i = 0; i < g->g_ndfas; i++) {
|
||||
if (strcmp(lb->lb_str, g->g_dfa[i].d_name) == 0) {
|
||||
if (debugging)
|
||||
printf("Label %s is non-terminal %d.\n",
|
||||
lb->lb_str,
|
||||
g->g_dfa[i].d_type);
|
||||
lb->lb_type = g->g_dfa[i].d_type;
|
||||
lb->lb_str = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < (int)N_TOKENS; i++) {
|
||||
if (strcmp(lb->lb_str, tok_name[i]) == 0) {
|
||||
if (debugging)
|
||||
printf("Label %s is terminal %d.\n",
|
||||
lb->lb_str, i);
|
||||
lb->lb_type = i;
|
||||
lb->lb_str = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
printf("Can't translate NAME label '%s'\n", lb->lb_str);
|
||||
return;
|
||||
}
|
||||
|
||||
if (lb->lb_type == STRING) {
|
||||
if (isalpha(lb->lb_str[1])) {
|
||||
char *p, *strchr();
|
||||
if (debugging)
|
||||
printf("Label %s is a keyword\n", lb->lb_str);
|
||||
lb->lb_type = NAME;
|
||||
lb->lb_str++;
|
||||
p = strchr(lb->lb_str, '\'');
|
||||
if (p)
|
||||
*p = '\0';
|
||||
}
|
||||
else {
|
||||
if (lb->lb_str[2] == lb->lb_str[0]) {
|
||||
int type = (int) tok_1char(lb->lb_str[1]);
|
||||
if (type != OP) {
|
||||
lb->lb_type = type;
|
||||
lb->lb_str = NULL;
|
||||
}
|
||||
else
|
||||
printf("Unknown OP label %s\n",
|
||||
lb->lb_str);
|
||||
}
|
||||
else
|
||||
printf("Can't translate STRING label %s\n",
|
||||
lb->lb_str);
|
||||
}
|
||||
}
|
||||
else
|
||||
printf("Can't translate label '%s'\n", labelrepr(lb));
|
||||
}
|
||||
|
||||
void
|
||||
translatelabels(g)
|
||||
grammar *g;
|
||||
{
|
||||
int i;
|
||||
|
||||
printf("Translating labels ...\n");
|
||||
/* Don't translate EMPTY */
|
||||
for (i = EMPTY+1; i < g->g_ll.ll_nlabels; i++)
|
||||
translabel(g, &g->g_ll.ll_label[i]);
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/* Grammar subroutines needed by parser */
|
||||
|
||||
#include "PROTO.h"
|
||||
#define NULL 0
|
||||
#include "assert.h"
|
||||
#include "grammar.h"
|
||||
#include "token.h"
|
||||
|
||||
/* Return the DFA for the given type */
|
||||
|
||||
dfa *
|
||||
finddfa(g, type)
|
||||
grammar *g;
|
||||
register int type;
|
||||
{
|
||||
register int i;
|
||||
register dfa *d;
|
||||
|
||||
for (i = g->g_ndfas, d = g->g_dfa; --i >= 0; d++) {
|
||||
if (d->d_type == type)
|
||||
return d;
|
||||
}
|
||||
assert(0);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
char *
|
||||
labelrepr(lb)
|
||||
label *lb;
|
||||
{
|
||||
static char buf[100];
|
||||
|
||||
if (lb->lb_type == ENDMARKER)
|
||||
return "EMPTY";
|
||||
else if (ISNONTERMINAL(lb->lb_type)) {
|
||||
if (lb->lb_str == NULL) {
|
||||
sprintf(buf, "NT%d", lb->lb_type);
|
||||
return buf;
|
||||
}
|
||||
else
|
||||
return lb->lb_str;
|
||||
}
|
||||
else {
|
||||
if (lb->lb_str == NULL)
|
||||
return tok_name[lb->lb_type];
|
||||
else {
|
||||
sprintf(buf, "%.32s(%.32s)",
|
||||
tok_name[lb->lb_type], lb->lb_str);
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
/* Check for interrupts */
|
||||
|
||||
#ifdef MSDOS
|
||||
|
||||
/* This might work for MS-DOS: */
|
||||
|
||||
void
|
||||
initintr()
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
intrcheck()
|
||||
{
|
||||
int interrupted = 0;
|
||||
while (kbhit()) {
|
||||
if (getch() == '\003')
|
||||
interrupted = 1;
|
||||
}
|
||||
return interrupted;
|
||||
}
|
||||
|
||||
#define OK
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef THINK_C
|
||||
|
||||
#include <MacHeaders>
|
||||
|
||||
void
|
||||
initintr()
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
intrcheck()
|
||||
{
|
||||
/* Static to make it faster(?) only */
|
||||
static EventRecord e;
|
||||
|
||||
/* XXX This fails if the user first types ahead and then
|
||||
decides to interrupt -- repeating Command-. until the
|
||||
event queue overflows may work though. */
|
||||
if (EventAvail(keyDownMask|autoKeyMask, &e) &&
|
||||
(e.modifiers & cmdKey) &&
|
||||
(e.message & charCodeMask) == '.') {
|
||||
(void) GetNextEvent(keyDownMask|autoKeyMask, &e);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define OK
|
||||
|
||||
#endif /* THINK_C */
|
||||
|
||||
|
||||
#ifndef OK
|
||||
|
||||
/* Default version -- should work for Unix and Standard C */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "sigtype.h"
|
||||
|
||||
static int interrupted;
|
||||
|
||||
static SIGTYPE
|
||||
intcatcher(sig)
|
||||
int sig;
|
||||
{
|
||||
interrupted = 1;
|
||||
signal(SIGINT, intcatcher);
|
||||
}
|
||||
|
||||
void
|
||||
initintr()
|
||||
{
|
||||
if (signal(SIGINT, SIG_IGN) != SIG_IGN)
|
||||
signal(SIGINT, intcatcher);
|
||||
}
|
||||
|
||||
int
|
||||
intrcheck()
|
||||
{
|
||||
if (!interrupted)
|
||||
return 0;
|
||||
interrupted = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* !OK */
|
|
@ -0,0 +1,68 @@
|
|||
/* List a node on a file */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "PROTO.h"
|
||||
#include "token.h"
|
||||
#include "node.h"
|
||||
|
||||
static int level, atbol;
|
||||
|
||||
static void
|
||||
list1node(fp, n)
|
||||
FILE *fp;
|
||||
node *n;
|
||||
{
|
||||
if (n == 0)
|
||||
return;
|
||||
if (ISNONTERMINAL(TYPE(n))) {
|
||||
int i;
|
||||
for (i = 0; i < NCH(n); i++)
|
||||
list1node(fp, CHILD(n, i));
|
||||
}
|
||||
else if (ISTERMINAL(TYPE(n))) {
|
||||
switch (TYPE(n)) {
|
||||
case INDENT:
|
||||
++level;
|
||||
break;
|
||||
case DEDENT:
|
||||
--level;
|
||||
break;
|
||||
default:
|
||||
if (atbol) {
|
||||
int i;
|
||||
for (i = 0; i < level; ++i)
|
||||
fprintf(fp, "\t");
|
||||
atbol = 0;
|
||||
}
|
||||
if (TYPE(n) == NEWLINE) {
|
||||
if (STR(n) != NULL)
|
||||
fprintf(fp, "%s", STR(n));
|
||||
fprintf(fp, "\n");
|
||||
atbol = 1;
|
||||
}
|
||||
else
|
||||
fprintf(fp, "%s ", STR(n));
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
fprintf(fp, "? ");
|
||||
}
|
||||
|
||||
void
|
||||
listnode(fp, n)
|
||||
FILE *fp;
|
||||
node *n;
|
||||
{
|
||||
level = 0;
|
||||
atbol = 1;
|
||||
list1node(fp, n);
|
||||
}
|
||||
|
||||
void
|
||||
listtree(n)
|
||||
node *n;
|
||||
{
|
||||
listnode(stdout, n);
|
||||
}
|
|
@ -0,0 +1,151 @@
|
|||
#include "PROTO.h"
|
||||
#include "metagrammar.h"
|
||||
#include "grammar.h"
|
||||
static arc arcs_0_0[3] = {
|
||||
{2, 0},
|
||||
{3, 0},
|
||||
{4, 1},
|
||||
};
|
||||
static arc arcs_0_1[1] = {
|
||||
{0, 1},
|
||||
};
|
||||
static state states_0[2] = {
|
||||
{3, arcs_0_0},
|
||||
{1, arcs_0_1},
|
||||
};
|
||||
static arc arcs_1_0[1] = {
|
||||
{5, 1},
|
||||
};
|
||||
static arc arcs_1_1[1] = {
|
||||
{6, 2},
|
||||
};
|
||||
static arc arcs_1_2[1] = {
|
||||
{7, 3},
|
||||
};
|
||||
static arc arcs_1_3[1] = {
|
||||
{3, 4},
|
||||
};
|
||||
static arc arcs_1_4[1] = {
|
||||
{0, 4},
|
||||
};
|
||||
static state states_1[5] = {
|
||||
{1, arcs_1_0},
|
||||
{1, arcs_1_1},
|
||||
{1, arcs_1_2},
|
||||
{1, arcs_1_3},
|
||||
{1, arcs_1_4},
|
||||
};
|
||||
static arc arcs_2_0[1] = {
|
||||
{8, 1},
|
||||
};
|
||||
static arc arcs_2_1[2] = {
|
||||
{9, 0},
|
||||
{0, 1},
|
||||
};
|
||||
static state states_2[2] = {
|
||||
{1, arcs_2_0},
|
||||
{2, arcs_2_1},
|
||||
};
|
||||
static arc arcs_3_0[1] = {
|
||||
{10, 1},
|
||||
};
|
||||
static arc arcs_3_1[2] = {
|
||||
{10, 1},
|
||||
{0, 1},
|
||||
};
|
||||
static state states_3[2] = {
|
||||
{1, arcs_3_0},
|
||||
{2, arcs_3_1},
|
||||
};
|
||||
static arc arcs_4_0[2] = {
|
||||
{11, 1},
|
||||
{13, 2},
|
||||
};
|
||||
static arc arcs_4_1[1] = {
|
||||
{7, 3},
|
||||
};
|
||||
static arc arcs_4_2[3] = {
|
||||
{14, 4},
|
||||
{15, 4},
|
||||
{0, 2},
|
||||
};
|
||||
static arc arcs_4_3[1] = {
|
||||
{12, 4},
|
||||
};
|
||||
static arc arcs_4_4[1] = {
|
||||
{0, 4},
|
||||
};
|
||||
static state states_4[5] = {
|
||||
{2, arcs_4_0},
|
||||
{1, arcs_4_1},
|
||||
{3, arcs_4_2},
|
||||
{1, arcs_4_3},
|
||||
{1, arcs_4_4},
|
||||
};
|
||||
static arc arcs_5_0[3] = {
|
||||
{5, 1},
|
||||
{16, 1},
|
||||
{17, 2},
|
||||
};
|
||||
static arc arcs_5_1[1] = {
|
||||
{0, 1},
|
||||
};
|
||||
static arc arcs_5_2[1] = {
|
||||
{7, 3},
|
||||
};
|
||||
static arc arcs_5_3[1] = {
|
||||
{18, 1},
|
||||
};
|
||||
static state states_5[4] = {
|
||||
{3, arcs_5_0},
|
||||
{1, arcs_5_1},
|
||||
{1, arcs_5_2},
|
||||
{1, arcs_5_3},
|
||||
};
|
||||
static dfa dfas[6] = {
|
||||
{256, "MSTART", 0, 2, states_0,
|
||||
"\070\000\000"},
|
||||
{257, "RULE", 0, 5, states_1,
|
||||
"\040\000\000"},
|
||||
{258, "RHS", 0, 2, states_2,
|
||||
"\040\010\003"},
|
||||
{259, "ALT", 0, 2, states_3,
|
||||
"\040\010\003"},
|
||||
{260, "ITEM", 0, 5, states_4,
|
||||
"\040\010\003"},
|
||||
{261, "ATOM", 0, 4, states_5,
|
||||
"\040\000\003"},
|
||||
};
|
||||
static label labels[19] = {
|
||||
{0, "EMPTY"},
|
||||
{256, 0},
|
||||
{257, 0},
|
||||
{4, 0},
|
||||
{0, 0},
|
||||
{1, 0},
|
||||
{11, 0},
|
||||
{258, 0},
|
||||
{259, 0},
|
||||
{18, 0},
|
||||
{260, 0},
|
||||
{9, 0},
|
||||
{10, 0},
|
||||
{261, 0},
|
||||
{16, 0},
|
||||
{14, 0},
|
||||
{3, 0},
|
||||
{7, 0},
|
||||
{8, 0},
|
||||
};
|
||||
static grammar gram = {
|
||||
6,
|
||||
dfas,
|
||||
{19, labels},
|
||||
256
|
||||
};
|
||||
|
||||
grammar *
|
||||
meta_grammar()
|
||||
{
|
||||
return &gram;
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/* Parse tree node implementation */
|
||||
|
||||
#include "PROTO.h"
|
||||
#include "malloc.h"
|
||||
#include "node.h"
|
||||
|
||||
node *
|
||||
newnode(type)
|
||||
int type;
|
||||
{
|
||||
node *n = NEW(node, 1);
|
||||
if (n == NULL)
|
||||
return NULL;
|
||||
n->n_type = type;
|
||||
n->n_str = NULL;
|
||||
n->n_nchildren = 0;
|
||||
n->n_child = NULL;
|
||||
return n;
|
||||
}
|
||||
|
||||
#define XXX 3 /* Node alignment factor to speed up realloc */
|
||||
#define XXXROUNDUP(n) ((n) == 1 ? 1 : ((n) + XXX - 1) / XXX * XXX)
|
||||
|
||||
node *
|
||||
addchild(n1, type, str)
|
||||
register node *n1;
|
||||
int type;
|
||||
char *str;
|
||||
{
|
||||
register int nch = n1->n_nchildren;
|
||||
register int nch1 = nch+1;
|
||||
register node *n;
|
||||
if (XXXROUNDUP(nch) < nch1) {
|
||||
n = n1->n_child;
|
||||
nch1 = XXXROUNDUP(nch1);
|
||||
RESIZE(n, node, nch1);
|
||||
if (n == NULL)
|
||||
return NULL;
|
||||
n1->n_child = n;
|
||||
}
|
||||
n = &n1->n_child[n1->n_nchildren++];
|
||||
n->n_type = type;
|
||||
n->n_str = str;
|
||||
n->n_nchildren = 0;
|
||||
n->n_child = NULL;
|
||||
return n;
|
||||
}
|
|
@ -0,0 +1,396 @@
|
|||
/* Parser implementation */
|
||||
|
||||
/* For a description, see the comments at end of this file */
|
||||
|
||||
/* XXX To do: error recovery */
|
||||
|
||||
#include <stdio.h>
|
||||
#include "assert.h"
|
||||
|
||||
#include "PROTO.h"
|
||||
#include "malloc.h"
|
||||
#include "token.h"
|
||||
#include "grammar.h"
|
||||
#include "node.h"
|
||||
#include "parser.h"
|
||||
#include "errcode.h"
|
||||
|
||||
extern int debugging;
|
||||
|
||||
#ifdef DEBUG
|
||||
#define D(x) if (!debugging); else x
|
||||
#else
|
||||
#define D(x)
|
||||
#endif
|
||||
|
||||
|
||||
/* STACK DATA TYPE */
|
||||
|
||||
static void s_reset PROTO((stack *));
|
||||
|
||||
static void
|
||||
s_reset(s)
|
||||
stack *s;
|
||||
{
|
||||
s->s_top = &s->s_base[MAXSTACK];
|
||||
}
|
||||
|
||||
#define s_empty(s) ((s)->s_top == &(s)->s_base[MAXSTACK])
|
||||
|
||||
static int s_push PROTO((stack *, dfa *, node *));
|
||||
|
||||
static int
|
||||
s_push(s, d, parent)
|
||||
register stack *s;
|
||||
dfa *d;
|
||||
node *parent;
|
||||
{
|
||||
register stackentry *top;
|
||||
if (s->s_top == s->s_base) {
|
||||
fprintf(stderr, "s_push: parser stack overflow\n");
|
||||
return -1;
|
||||
}
|
||||
top = --s->s_top;
|
||||
top->s_dfa = d;
|
||||
top->s_parent = parent;
|
||||
top->s_state = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
static void s_pop PROTO((stack *));
|
||||
|
||||
static void
|
||||
s_pop(s)
|
||||
register stack *s;
|
||||
{
|
||||
if (s_empty(s)) {
|
||||
fprintf(stderr, "s_pop: parser stack underflow -- FATAL\n");
|
||||
abort();
|
||||
}
|
||||
s->s_top++;
|
||||
}
|
||||
|
||||
#else /* !DEBUG */
|
||||
|
||||
#define s_pop(s) (s)->s_top++
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* PARSER CREATION */
|
||||
|
||||
parser_state *
|
||||
newparser(g, start)
|
||||
grammar *g;
|
||||
int start;
|
||||
{
|
||||
parser_state *ps;
|
||||
|
||||
if (!g->g_accel)
|
||||
addaccelerators(g);
|
||||
ps = NEW(parser_state, 1);
|
||||
if (ps == NULL)
|
||||
return NULL;
|
||||
ps->p_grammar = g;
|
||||
ps->p_tree = newnode(start);
|
||||
if (ps->p_tree == NULL) {
|
||||
if (ps->p_tree != NULL)
|
||||
DEL(ps->p_tree); /* XXX freeing a node!?! */
|
||||
DEL(ps);
|
||||
return NULL;
|
||||
}
|
||||
s_reset(&ps->p_stack);
|
||||
(void) s_push(&ps->p_stack, finddfa(g, start), ps->p_tree);
|
||||
return ps;
|
||||
}
|
||||
|
||||
void
|
||||
delparser(ps)
|
||||
parser_state *ps;
|
||||
{
|
||||
DEL(ps);
|
||||
}
|
||||
|
||||
|
||||
/* PARSER STACK OPERATIONS */
|
||||
|
||||
static int shift PROTO((stack *, int, char *, int));
|
||||
|
||||
static int
|
||||
shift(s, type, str, newstate)
|
||||
register stack *s;
|
||||
int type;
|
||||
char *str;
|
||||
int newstate;
|
||||
{
|
||||
assert(!s_empty(s));
|
||||
if (addchild(s->s_top->s_parent, type, str) == NULL) {
|
||||
fprintf(stderr, "shift: no mem in addchild\n");
|
||||
return -1;
|
||||
}
|
||||
s->s_top->s_state = newstate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int push PROTO((stack *, int, dfa *, int));
|
||||
|
||||
static int
|
||||
push(s, type, d, newstate)
|
||||
register stack *s;
|
||||
int type;
|
||||
dfa *d;
|
||||
int newstate;
|
||||
{
|
||||
register node *n;
|
||||
n = s->s_top->s_parent;
|
||||
assert(!s_empty(s));
|
||||
if (addchild(n, type, (char *)NULL) == NULL) {
|
||||
fprintf(stderr, "push: no mem in addchild\n");
|
||||
return -1;
|
||||
}
|
||||
s->s_top->s_state = newstate;
|
||||
return s_push(s, d, CHILD(n, NCH(n)-1));
|
||||
}
|
||||
|
||||
|
||||
/* PARSER PROPER */
|
||||
|
||||
static int classify PROTO((grammar *, int, char *));
|
||||
|
||||
static int
|
||||
classify(g, type, str)
|
||||
grammar *g;
|
||||
register int type;
|
||||
char *str;
|
||||
{
|
||||
register int n = g->g_ll.ll_nlabels;
|
||||
|
||||
if (type == NAME) {
|
||||
register char *s = str;
|
||||
register label *l = g->g_ll.ll_label;
|
||||
register int i;
|
||||
for (i = n; i > 0; i--, l++) {
|
||||
if (l->lb_type == NAME && l->lb_str != NULL &&
|
||||
l->lb_str[0] == s[0] &&
|
||||
strcmp(l->lb_str, s) == 0) {
|
||||
D(printf("It's a keyword\n"));
|
||||
return n - i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
register label *l = g->g_ll.ll_label;
|
||||
register int i;
|
||||
for (i = n; i > 0; i--, l++) {
|
||||
if (l->lb_type == type && l->lb_str == NULL) {
|
||||
D(printf("It's a token we know\n"));
|
||||
return n - i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
D(printf("Illegal token\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
addtoken(ps, type, str)
|
||||
register parser_state *ps;
|
||||
register int type;
|
||||
char *str;
|
||||
{
|
||||
register int ilabel;
|
||||
|
||||
D(printf("Token %s/'%s' ... ", tok_name[type], str));
|
||||
|
||||
/* Find out which label this token is */
|
||||
ilabel = classify(ps->p_grammar, type, str);
|
||||
if (ilabel < 0)
|
||||
return E_SYNTAX;
|
||||
|
||||
/* Loop until the token is shifted or an error occurred */
|
||||
for (;;) {
|
||||
/* Fetch the current dfa and state */
|
||||
register dfa *d = ps->p_stack.s_top->s_dfa;
|
||||
register state *s = &d->d_state[ps->p_stack.s_top->s_state];
|
||||
|
||||
D(printf(" DFA '%s', state %d:",
|
||||
d->d_name, ps->p_stack.s_top->s_state));
|
||||
|
||||
/* Check accelerator */
|
||||
if (s->s_lower <= ilabel && ilabel < s->s_upper) {
|
||||
register int x = s->s_accel[ilabel - s->s_lower];
|
||||
if (x != -1) {
|
||||
if (x & (1<<7)) {
|
||||
/* Push non-terminal */
|
||||
int nt = (x >> 8) + NT_OFFSET;
|
||||
int arrow = x & ((1<<7)-1);
|
||||
dfa *d1 = finddfa(ps->p_grammar, nt);
|
||||
if (push(&ps->p_stack, nt, d1, arrow) < 0) {
|
||||
D(printf(" MemError: push.\n"));
|
||||
return E_NOMEM;
|
||||
}
|
||||
D(printf(" Push ...\n"));
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Shift the token */
|
||||
if (shift(&ps->p_stack, type, str, x) < 0) {
|
||||
D(printf(" MemError: shift.\n"));
|
||||
return E_NOMEM;
|
||||
}
|
||||
D(printf(" Shift.\n"));
|
||||
/* Pop while we are in an accept-only state */
|
||||
while (s = &d->d_state
|
||||
[ps->p_stack.s_top->s_state],
|
||||
s->s_accept && s->s_narcs == 1) {
|
||||
D(printf(" Direct pop.\n"));
|
||||
s_pop(&ps->p_stack);
|
||||
if (s_empty(&ps->p_stack)) {
|
||||
D(printf(" ACCEPT.\n"));
|
||||
return E_DONE;
|
||||
}
|
||||
d = ps->p_stack.s_top->s_dfa;
|
||||
}
|
||||
return E_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if (s->s_accept) {
|
||||
/* Pop this dfa and try again */
|
||||
s_pop(&ps->p_stack);
|
||||
D(printf(" Pop ...\n"));
|
||||
if (s_empty(&ps->p_stack)) {
|
||||
D(printf(" Error: bottom of stack.\n"));
|
||||
return E_SYNTAX;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Stuck, report syntax error */
|
||||
D(printf(" Error.\n"));
|
||||
return E_SYNTAX;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
/* DEBUG OUTPUT */
|
||||
|
||||
void
|
||||
dumptree(g, n)
|
||||
grammar *g;
|
||||
node *n;
|
||||
{
|
||||
int i;
|
||||
|
||||
if (n == NULL)
|
||||
printf("NIL");
|
||||
else {
|
||||
label l;
|
||||
l.lb_type = TYPE(n);
|
||||
l.lb_str = TYPE(str);
|
||||
printf("%s", labelrepr(&l));
|
||||
if (ISNONTERMINAL(TYPE(n))) {
|
||||
printf("(");
|
||||
for (i = 0; i < NCH(n); i++) {
|
||||
if (i > 0)
|
||||
printf(",");
|
||||
dumptree(g, CHILD(n, i));
|
||||
}
|
||||
printf(")");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
showtree(g, n)
|
||||
grammar *g;
|
||||
node *n;
|
||||
{
|
||||
int i;
|
||||
|
||||
if (n == NULL)
|
||||
return;
|
||||
if (ISNONTERMINAL(TYPE(n))) {
|
||||
for (i = 0; i < NCH(n); i++)
|
||||
showtree(g, CHILD(n, i));
|
||||
}
|
||||
else if (ISTERMINAL(TYPE(n))) {
|
||||
printf("%s", tok_name[TYPE(n)]);
|
||||
if (TYPE(n) == NUMBER || TYPE(n) == NAME)
|
||||
printf("(%s)", STR(n));
|
||||
printf(" ");
|
||||
}
|
||||
else
|
||||
printf("? ");
|
||||
}
|
||||
|
||||
void
|
||||
printtree(ps)
|
||||
parser_state *ps;
|
||||
{
|
||||
if (debugging) {
|
||||
printf("Parse tree:\n");
|
||||
dumptree(ps->p_grammar, ps->p_tree);
|
||||
printf("\n");
|
||||
printf("Tokens:\n");
|
||||
showtree(ps->p_grammar, ps->p_tree);
|
||||
printf("\n");
|
||||
}
|
||||
printf("Listing:\n");
|
||||
listtree(ps->p_tree);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
#endif /* DEBUG */
|
||||
|
||||
/*
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The parser's interface is different than usual: the function addtoken()
|
||||
must be called for each token in the input. This makes it possible to
|
||||
turn it into an incremental parsing system later. The parsing system
|
||||
constructs a parse tree as it goes.
|
||||
|
||||
A parsing rule is represented as a Deterministic Finite-state Automaton
|
||||
(DFA). A node in a DFA represents a state of the parser; an arc represents
|
||||
a transition. Transitions are either labeled with terminal symbols or
|
||||
with non-terminals. When the parser decides to follow an arc labeled
|
||||
with a non-terminal, it is invoked recursively with the DFA representing
|
||||
the parsing rule for that as its initial state; when that DFA accepts,
|
||||
the parser that invoked it continues. The parse tree constructed by the
|
||||
recursively called parser is inserted as a child in the current parse tree.
|
||||
|
||||
The DFA's can be constructed automatically from a more conventional
|
||||
language description. An extended LL(1) grammar (ELL(1)) is suitable.
|
||||
Certain restrictions make the parser's life easier: rules that can produce
|
||||
the empty string should be outlawed (there are other ways to put loops
|
||||
or optional parts in the language). To avoid the need to construct
|
||||
FIRST sets, we can require that all but the last alternative of a rule
|
||||
(really: arc going out of a DFA's state) must begin with a terminal
|
||||
symbol.
|
||||
|
||||
As an example, consider this grammar:
|
||||
|
||||
expr: term (OP term)*
|
||||
term: CONSTANT | '(' expr ')'
|
||||
|
||||
The DFA corresponding to the rule for expr is:
|
||||
|
||||
------->.---term-->.------->
|
||||
^ |
|
||||
| |
|
||||
\----OP----/
|
||||
|
||||
The parse tree generated for the input a+b is:
|
||||
|
||||
(expr: (term: (NAME: a)), (OP: +), (term: (NAME: b)))
|
||||
|
||||
*/
|
|
@ -0,0 +1,25 @@
|
|||
/* Parser interface */
|
||||
|
||||
#define MAXSTACK 100
|
||||
|
||||
typedef struct _stackentry {
|
||||
int s_state; /* State in current DFA */
|
||||
dfa *s_dfa; /* Current DFA */
|
||||
node *s_parent; /* Where to add next node */
|
||||
} stackentry;
|
||||
|
||||
typedef struct _stack {
|
||||
stackentry *s_top; /* Top entry */
|
||||
stackentry s_base[MAXSTACK];/* Array of stack entries */
|
||||
/* NB The stack grows down */
|
||||
} stack;
|
||||
|
||||
typedef struct {
|
||||
struct _stack p_stack; /* Stack of parser states */
|
||||
struct _grammar *p_grammar; /* Grammar to use */
|
||||
struct _node *p_tree; /* Top of parse tree */
|
||||
} parser_state;
|
||||
|
||||
parser_state *newparser PROTO((struct _grammar *g, int start));
|
||||
void delparser PROTO((parser_state *ps));
|
||||
int addtoken PROTO((parser_state *ps, int type, char *str));
|
|
@ -0,0 +1,131 @@
|
|||
/* Parser-tokenizer link implementation */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "PROTO.h"
|
||||
#include "malloc.h"
|
||||
#include "tokenizer.h"
|
||||
#include "node.h"
|
||||
#include "grammar.h"
|
||||
#include "parser.h"
|
||||
#include "errcode.h"
|
||||
|
||||
extern int debugging;
|
||||
|
||||
|
||||
/* Parse input coming from the given tokenizer structure.
|
||||
Return error code. */
|
||||
|
||||
static int
|
||||
parsetok(tok, g, start, n_ret)
|
||||
struct tok_state *tok;
|
||||
grammar *g;
|
||||
int start;
|
||||
node **n_ret;
|
||||
{
|
||||
parser_state *ps;
|
||||
int ret;
|
||||
|
||||
if ((ps = newparser(g, start)) == NULL) {
|
||||
fprintf(stderr, "no mem for new parser\n");
|
||||
return E_NOMEM;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
char *a, *b;
|
||||
int type;
|
||||
int len;
|
||||
char *str;
|
||||
|
||||
type = tok_get(tok, &a, &b);
|
||||
if (type == ERRORTOKEN) {
|
||||
ret = tok->done;
|
||||
break;
|
||||
}
|
||||
len = b - a;
|
||||
str = NEW(char, len + 1);
|
||||
if (str == NULL) {
|
||||
fprintf(stderr, "no mem for next token\n");
|
||||
ret = E_NOMEM;
|
||||
break;
|
||||
}
|
||||
strncpy(str, a, len);
|
||||
str[len] = '\0';
|
||||
ret = addtoken(ps, (int)type, str);
|
||||
if (ret != E_OK) {
|
||||
if (ret == E_DONE)
|
||||
*n_ret = ps->p_tree;
|
||||
else if (tok->lineno <= 1 && tok->done == E_EOF)
|
||||
ret = E_EOF;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
delparser(ps);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* Parse input coming from a string. Return error code. */
|
||||
|
||||
int
|
||||
parsestring(s, g, start, n_ret)
|
||||
char *s;
|
||||
grammar *g;
|
||||
int start;
|
||||
node **n_ret;
|
||||
{
|
||||
struct tok_state *tok = tok_setups(s);
|
||||
int ret;
|
||||
|
||||
if (tok == NULL) {
|
||||
fprintf(stderr, "no mem for tok_setups\n");
|
||||
return E_NOMEM;
|
||||
}
|
||||
ret = parsetok(tok, g, start, n_ret);
|
||||
if (ret == E_TOKEN || ret == E_SYNTAX) {
|
||||
fprintf(stderr, "String parsing error at line %d\n",
|
||||
tok->lineno);
|
||||
}
|
||||
tok_free(tok);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* Parse input coming from a file. Return error code. */
|
||||
|
||||
int
|
||||
parsefile(fp, g, start, ps1, ps2, n_ret)
|
||||
FILE *fp;
|
||||
grammar *g;
|
||||
int start;
|
||||
char *ps1, *ps2;
|
||||
node **n_ret;
|
||||
{
|
||||
struct tok_state *tok = tok_setupf(fp, ps1, ps2);
|
||||
int ret;
|
||||
|
||||
if (tok == NULL) {
|
||||
fprintf(stderr, "no mem for tok_setupf\n");
|
||||
return E_NOMEM;
|
||||
}
|
||||
ret = parsetok(tok, g, start, n_ret);
|
||||
if (ret == E_TOKEN || ret == E_SYNTAX) {
|
||||
char *p;
|
||||
fprintf(stderr, "Parsing error at line %d:\n",
|
||||
tok->lineno);
|
||||
*tok->inp = '\0';
|
||||
if (tok->inp > tok->buf && tok->inp[-1] == '\n')
|
||||
tok->inp[-1] = '\0';
|
||||
fprintf(stderr, "%s\n", tok->buf);
|
||||
for (p = tok->buf; p < tok->cur; p++) {
|
||||
if (*p == '\t')
|
||||
putc('\t', stderr);
|
||||
else
|
||||
putc(' ', stderr);
|
||||
}
|
||||
fprintf(stderr, "^\n");
|
||||
}
|
||||
tok_free(tok);
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,729 @@
|
|||
/* Parser generator */
|
||||
|
||||
/* For a description, see the comments at end of this file */
|
||||
|
||||
#include <stdio.h>
|
||||
#include "assert.h"
|
||||
|
||||
#include "PROTO.h"
|
||||
#include "malloc.h"
|
||||
#include "token.h"
|
||||
#include "node.h"
|
||||
#include "grammar.h"
|
||||
#include "metagrammar.h"
|
||||
#include "pgen.h"
|
||||
|
||||
extern int debugging;
|
||||
|
||||
|
||||
/* PART ONE -- CONSTRUCT NFA -- Cf. Algorithm 3.2 from [Aho&Ullman 77] */
|
||||
|
||||
typedef struct _nfaarc {
|
||||
int ar_label;
|
||||
int ar_arrow;
|
||||
} nfaarc;
|
||||
|
||||
typedef struct _nfastate {
|
||||
int st_narcs;
|
||||
nfaarc *st_arc;
|
||||
} nfastate;
|
||||
|
||||
typedef struct _nfa {
|
||||
int nf_type;
|
||||
char *nf_name;
|
||||
int nf_nstates;
|
||||
nfastate *nf_state;
|
||||
int nf_start, nf_finish;
|
||||
} nfa;
|
||||
|
||||
static int
|
||||
addnfastate(nf)
|
||||
nfa *nf;
|
||||
{
|
||||
nfastate *st;
|
||||
|
||||
RESIZE(nf->nf_state, nfastate, nf->nf_nstates + 1);
|
||||
if (nf->nf_state == NULL)
|
||||
fatal("out of mem");
|
||||
st = &nf->nf_state[nf->nf_nstates++];
|
||||
st->st_narcs = 0;
|
||||
st->st_arc = NULL;
|
||||
return st - nf->nf_state;
|
||||
}
|
||||
|
||||
static void
|
||||
addnfaarc(nf, from, to, lbl)
|
||||
nfa *nf;
|
||||
int from, to, lbl;
|
||||
{
|
||||
nfastate *st;
|
||||
nfaarc *ar;
|
||||
|
||||
st = &nf->nf_state[from];
|
||||
RESIZE(st->st_arc, nfaarc, st->st_narcs + 1);
|
||||
if (st->st_arc == NULL)
|
||||
fatal("out of mem");
|
||||
ar = &st->st_arc[st->st_narcs++];
|
||||
ar->ar_label = lbl;
|
||||
ar->ar_arrow = to;
|
||||
}
|
||||
|
||||
static nfa *
|
||||
newnfa(name)
|
||||
char *name;
|
||||
{
|
||||
nfa *nf;
|
||||
static type = NT_OFFSET; /* All types will be disjunct */
|
||||
|
||||
nf = NEW(nfa, 1);
|
||||
if (nf == NULL)
|
||||
fatal("no mem for new nfa");
|
||||
nf->nf_type = type++;
|
||||
nf->nf_name = name; /* XXX strdup(name) ??? */
|
||||
nf->nf_nstates = 0;
|
||||
nf->nf_state = NULL;
|
||||
nf->nf_start = nf->nf_finish = -1;
|
||||
return nf;
|
||||
}
|
||||
|
||||
typedef struct _nfagrammar {
|
||||
int gr_nnfas;
|
||||
nfa **gr_nfa;
|
||||
labellist gr_ll;
|
||||
} nfagrammar;
|
||||
|
||||
static nfagrammar *
|
||||
newnfagrammar()
|
||||
{
|
||||
nfagrammar *gr;
|
||||
|
||||
gr = NEW(nfagrammar, 1);
|
||||
if (gr == NULL)
|
||||
fatal("no mem for new nfa grammar");
|
||||
gr->gr_nnfas = 0;
|
||||
gr->gr_nfa = NULL;
|
||||
gr->gr_ll.ll_nlabels = 0;
|
||||
gr->gr_ll.ll_label = NULL;
|
||||
addlabel(&gr->gr_ll, ENDMARKER, "EMPTY");
|
||||
return gr;
|
||||
}
|
||||
|
||||
static nfa *
|
||||
addnfa(gr, name)
|
||||
nfagrammar *gr;
|
||||
char *name;
|
||||
{
|
||||
nfa *nf;
|
||||
|
||||
nf = newnfa(name);
|
||||
RESIZE(gr->gr_nfa, nfa *, gr->gr_nnfas + 1);
|
||||
if (gr->gr_nfa == NULL)
|
||||
fatal("out of mem");
|
||||
gr->gr_nfa[gr->gr_nnfas++] = nf;
|
||||
addlabel(&gr->gr_ll, NAME, nf->nf_name);
|
||||
return nf;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
static char REQNFMT[] = "metacompile: less than %d children\n";
|
||||
|
||||
#define REQN(i, count) \
|
||||
if (i < count) { \
|
||||
fprintf(stderr, REQNFMT, count); \
|
||||
abort(); \
|
||||
} else
|
||||
|
||||
#else
|
||||
#define REQN(i, count) /* empty */
|
||||
#endif
|
||||
|
||||
static nfagrammar *
|
||||
metacompile(n)
|
||||
node *n;
|
||||
{
|
||||
nfagrammar *gr;
|
||||
int i;
|
||||
|
||||
printf("Compiling (meta-) parse tree into NFA grammar\n");
|
||||
gr = newnfagrammar();
|
||||
REQ(n, MSTART);
|
||||
i = n->n_nchildren - 1; /* Last child is ENDMARKER */
|
||||
n = n->n_child;
|
||||
for (; --i >= 0; n++) {
|
||||
if (n->n_type != NEWLINE)
|
||||
compile_rule(gr, n);
|
||||
}
|
||||
return gr;
|
||||
}
|
||||
|
||||
static
|
||||
compile_rule(gr, n)
|
||||
nfagrammar *gr;
|
||||
node *n;
|
||||
{
|
||||
nfa *nf;
|
||||
|
||||
REQ(n, RULE);
|
||||
REQN(n->n_nchildren, 4);
|
||||
n = n->n_child;
|
||||
REQ(n, NAME);
|
||||
nf = addnfa(gr, n->n_str);
|
||||
n++;
|
||||
REQ(n, COLON);
|
||||
n++;
|
||||
REQ(n, RHS);
|
||||
compile_rhs(&gr->gr_ll, nf, n, &nf->nf_start, &nf->nf_finish);
|
||||
n++;
|
||||
REQ(n, NEWLINE);
|
||||
}
|
||||
|
||||
static
|
||||
compile_rhs(ll, nf, n, pa, pb)
|
||||
labellist *ll;
|
||||
nfa *nf;
|
||||
node *n;
|
||||
int *pa, *pb;
|
||||
{
|
||||
int i;
|
||||
int a, b;
|
||||
|
||||
REQ(n, RHS);
|
||||
i = n->n_nchildren;
|
||||
REQN(i, 1);
|
||||
n = n->n_child;
|
||||
REQ(n, ALT);
|
||||
compile_alt(ll, nf, n, pa, pb);
|
||||
if (--i <= 0)
|
||||
return;
|
||||
n++;
|
||||
a = *pa;
|
||||
b = *pb;
|
||||
*pa = addnfastate(nf);
|
||||
*pb = addnfastate(nf);
|
||||
addnfaarc(nf, *pa, a, EMPTY);
|
||||
addnfaarc(nf, b, *pb, EMPTY);
|
||||
for (; --i >= 0; n++) {
|
||||
REQ(n, VBAR);
|
||||
REQN(i, 1);
|
||||
--i;
|
||||
n++;
|
||||
REQ(n, ALT);
|
||||
compile_alt(ll, nf, n, &a, &b);
|
||||
addnfaarc(nf, *pa, a, EMPTY);
|
||||
addnfaarc(nf, b, *pb, EMPTY);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
compile_alt(ll, nf, n, pa, pb)
|
||||
labellist *ll;
|
||||
nfa *nf;
|
||||
node *n;
|
||||
int *pa, *pb;
|
||||
{
|
||||
int i;
|
||||
int a, b;
|
||||
|
||||
REQ(n, ALT);
|
||||
i = n->n_nchildren;
|
||||
REQN(i, 1);
|
||||
n = n->n_child;
|
||||
REQ(n, ITEM);
|
||||
compile_item(ll, nf, n, pa, pb);
|
||||
--i;
|
||||
n++;
|
||||
for (; --i >= 0; n++) {
|
||||
if (n->n_type == COMMA) { /* XXX Temporary */
|
||||
REQN(i, 1);
|
||||
--i;
|
||||
n++;
|
||||
}
|
||||
REQ(n, ITEM);
|
||||
compile_item(ll, nf, n, &a, &b);
|
||||
addnfaarc(nf, *pb, a, EMPTY);
|
||||
*pb = b;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
compile_item(ll, nf, n, pa, pb)
|
||||
labellist *ll;
|
||||
nfa *nf;
|
||||
node *n;
|
||||
int *pa, *pb;
|
||||
{
|
||||
int i;
|
||||
int a, b;
|
||||
|
||||
REQ(n, ITEM);
|
||||
i = n->n_nchildren;
|
||||
REQN(i, 1);
|
||||
n = n->n_child;
|
||||
if (n->n_type == LSQB) {
|
||||
REQN(i, 3);
|
||||
n++;
|
||||
REQ(n, RHS);
|
||||
*pa = addnfastate(nf);
|
||||
*pb = addnfastate(nf);
|
||||
addnfaarc(nf, *pa, *pb, EMPTY);
|
||||
compile_rhs(ll, nf, n, &a, &b);
|
||||
addnfaarc(nf, *pa, a, EMPTY);
|
||||
addnfaarc(nf, b, *pb, EMPTY);
|
||||
REQN(i, 1);
|
||||
n++;
|
||||
REQ(n, RSQB);
|
||||
}
|
||||
else {
|
||||
compile_atom(ll, nf, n, pa, pb);
|
||||
if (--i <= 0)
|
||||
return;
|
||||
n++;
|
||||
addnfaarc(nf, *pb, *pa, EMPTY);
|
||||
if (n->n_type == STAR)
|
||||
*pb = *pa;
|
||||
else
|
||||
REQ(n, PLUS);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
compile_atom(ll, nf, n, pa, pb)
|
||||
labellist *ll;
|
||||
nfa *nf;
|
||||
node *n;
|
||||
int *pa, *pb;
|
||||
{
|
||||
int i;
|
||||
|
||||
REQ(n, ATOM);
|
||||
i = n->n_nchildren;
|
||||
REQN(i, 1);
|
||||
n = n->n_child;
|
||||
if (n->n_type == LPAR) {
|
||||
REQN(i, 3);
|
||||
n++;
|
||||
REQ(n, RHS);
|
||||
compile_rhs(ll, nf, n, pa, pb);
|
||||
n++;
|
||||
REQ(n, RPAR);
|
||||
}
|
||||
else if (n->n_type == NAME || n->n_type == STRING) {
|
||||
*pa = addnfastate(nf);
|
||||
*pb = addnfastate(nf);
|
||||
addnfaarc(nf, *pa, *pb, addlabel(ll, n->n_type, n->n_str));
|
||||
}
|
||||
else
|
||||
REQ(n, NAME);
|
||||
}
|
||||
|
||||
static void
|
||||
dumpstate(ll, nf, istate)
|
||||
labellist *ll;
|
||||
nfa *nf;
|
||||
int istate;
|
||||
{
|
||||
nfastate *st;
|
||||
int i;
|
||||
nfaarc *ar;
|
||||
|
||||
printf("%c%2d%c",
|
||||
istate == nf->nf_start ? '*' : ' ',
|
||||
istate,
|
||||
istate == nf->nf_finish ? '.' : ' ');
|
||||
st = &nf->nf_state[istate];
|
||||
ar = st->st_arc;
|
||||
for (i = 0; i < st->st_narcs; i++) {
|
||||
if (i > 0)
|
||||
printf("\n ");
|
||||
printf("-> %2d %s", ar->ar_arrow,
|
||||
labelrepr(&ll->ll_label[ar->ar_label]));
|
||||
ar++;
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void
|
||||
dumpnfa(ll, nf)
|
||||
labellist *ll;
|
||||
nfa *nf;
|
||||
{
|
||||
int i;
|
||||
|
||||
printf("NFA '%s' has %d states; start %d, finish %d\n",
|
||||
nf->nf_name, nf->nf_nstates, nf->nf_start, nf->nf_finish);
|
||||
for (i = 0; i < nf->nf_nstates; i++)
|
||||
dumpstate(ll, nf, i);
|
||||
}
|
||||
|
||||
|
||||
/* PART TWO -- CONSTRUCT DFA -- Algorithm 3.1 from [Aho&Ullman 77] */
|
||||
|
||||
static int
|
||||
addclosure(ss, nf, istate)
|
||||
bitset ss;
|
||||
nfa *nf;
|
||||
int istate;
|
||||
{
|
||||
if (addbit(ss, istate)) {
|
||||
nfastate *st = &nf->nf_state[istate];
|
||||
nfaarc *ar = st->st_arc;
|
||||
int i;
|
||||
|
||||
for (i = st->st_narcs; --i >= 0; ) {
|
||||
if (ar->ar_label == EMPTY)
|
||||
addclosure(ss, nf, ar->ar_arrow);
|
||||
ar++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct _ss_arc {
|
||||
bitset sa_bitset;
|
||||
int sa_arrow;
|
||||
int sa_label;
|
||||
} ss_arc;
|
||||
|
||||
typedef struct _ss_state {
|
||||
bitset ss_ss;
|
||||
int ss_narcs;
|
||||
ss_arc *ss_arc;
|
||||
int ss_deleted;
|
||||
int ss_finish;
|
||||
int ss_rename;
|
||||
} ss_state;
|
||||
|
||||
typedef struct _ss_dfa {
|
||||
int sd_nstates;
|
||||
ss_state *sd_state;
|
||||
} ss_dfa;
|
||||
|
||||
static
|
||||
makedfa(gr, nf, d)
|
||||
nfagrammar *gr;
|
||||
nfa *nf;
|
||||
dfa *d;
|
||||
{
|
||||
int nbits = nf->nf_nstates;
|
||||
bitset ss;
|
||||
int xx_nstates;
|
||||
ss_state *xx_state, *yy;
|
||||
ss_arc *zz;
|
||||
int istate, jstate, iarc, jarc, ibit;
|
||||
nfastate *st;
|
||||
nfaarc *ar;
|
||||
|
||||
ss = newbitset(nbits);
|
||||
addclosure(ss, nf, nf->nf_start);
|
||||
xx_state = NEW(ss_state, 1);
|
||||
if (xx_state == NULL)
|
||||
fatal("no mem for xx_state in makedfa");
|
||||
xx_nstates = 1;
|
||||
yy = &xx_state[0];
|
||||
yy->ss_ss = ss;
|
||||
yy->ss_narcs = 0;
|
||||
yy->ss_arc = NULL;
|
||||
yy->ss_deleted = 0;
|
||||
yy->ss_finish = testbit(ss, nf->nf_finish);
|
||||
if (yy->ss_finish)
|
||||
printf("Error: nonterminal '%s' may produce empty.\n",
|
||||
nf->nf_name);
|
||||
|
||||
/* This algorithm is from a book written before
|
||||
the invention of structured programming... */
|
||||
|
||||
/* For each unmarked state... */
|
||||
for (istate = 0; istate < xx_nstates; ++istate) {
|
||||
yy = &xx_state[istate];
|
||||
ss = yy->ss_ss;
|
||||
/* For all its states... */
|
||||
for (ibit = 0; ibit < nf->nf_nstates; ++ibit) {
|
||||
if (!testbit(ss, ibit))
|
||||
continue;
|
||||
st = &nf->nf_state[ibit];
|
||||
/* For all non-empty arcs from this state... */
|
||||
for (iarc = 0; iarc < st->st_narcs; iarc++) {
|
||||
ar = &st->st_arc[iarc];
|
||||
if (ar->ar_label == EMPTY)
|
||||
continue;
|
||||
/* Look up in list of arcs from this state */
|
||||
for (jarc = 0; jarc < yy->ss_narcs; ++jarc) {
|
||||
zz = &yy->ss_arc[jarc];
|
||||
if (ar->ar_label == zz->sa_label)
|
||||
goto found;
|
||||
}
|
||||
/* Add new arc for this state */
|
||||
RESIZE(yy->ss_arc, ss_arc, yy->ss_narcs + 1);
|
||||
if (yy->ss_arc == NULL)
|
||||
fatal("out of mem");
|
||||
zz = &yy->ss_arc[yy->ss_narcs++];
|
||||
zz->sa_label = ar->ar_label;
|
||||
zz->sa_bitset = newbitset(nbits);
|
||||
zz->sa_arrow = -1;
|
||||
found: ;
|
||||
/* Add destination */
|
||||
addclosure(zz->sa_bitset, nf, ar->ar_arrow);
|
||||
}
|
||||
}
|
||||
/* Now look up all the arrow states */
|
||||
for (jarc = 0; jarc < xx_state[istate].ss_narcs; jarc++) {
|
||||
zz = &xx_state[istate].ss_arc[jarc];
|
||||
for (jstate = 0; jstate < xx_nstates; jstate++) {
|
||||
if (samebitset(zz->sa_bitset,
|
||||
xx_state[jstate].ss_ss, nbits)) {
|
||||
zz->sa_arrow = jstate;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
RESIZE(xx_state, ss_state, xx_nstates + 1);
|
||||
if (xx_state == NULL)
|
||||
fatal("out of mem");
|
||||
zz->sa_arrow = xx_nstates;
|
||||
yy = &xx_state[xx_nstates++];
|
||||
yy->ss_ss = zz->sa_bitset;
|
||||
yy->ss_narcs = 0;
|
||||
yy->ss_arc = NULL;
|
||||
yy->ss_deleted = 0;
|
||||
yy->ss_finish = testbit(yy->ss_ss, nf->nf_finish);
|
||||
done: ;
|
||||
}
|
||||
}
|
||||
|
||||
if (debugging)
|
||||
printssdfa(xx_nstates, xx_state, nbits, &gr->gr_ll,
|
||||
"before minimizing");
|
||||
|
||||
simplify(xx_nstates, xx_state);
|
||||
|
||||
if (debugging)
|
||||
printssdfa(xx_nstates, xx_state, nbits, &gr->gr_ll,
|
||||
"after minimizing");
|
||||
|
||||
convert(d, xx_nstates, xx_state);
|
||||
|
||||
/* XXX cleanup */
|
||||
}
|
||||
|
||||
static
|
||||
printssdfa(xx_nstates, xx_state, nbits, ll, msg)
|
||||
int xx_nstates;
|
||||
ss_state *xx_state;
|
||||
int nbits;
|
||||
labellist *ll;
|
||||
char *msg;
|
||||
{
|
||||
int i, ibit, iarc;
|
||||
ss_state *yy;
|
||||
ss_arc *zz;
|
||||
|
||||
printf("Subset DFA %s\n", msg);
|
||||
for (i = 0; i < xx_nstates; i++) {
|
||||
yy = &xx_state[i];
|
||||
if (yy->ss_deleted)
|
||||
continue;
|
||||
printf(" Subset %d", i);
|
||||
if (yy->ss_finish)
|
||||
printf(" (finish)");
|
||||
printf(" { ");
|
||||
for (ibit = 0; ibit < nbits; ibit++) {
|
||||
if (testbit(yy->ss_ss, ibit))
|
||||
printf("%d ", ibit);
|
||||
}
|
||||
printf("}\n");
|
||||
for (iarc = 0; iarc < yy->ss_narcs; iarc++) {
|
||||
zz = &yy->ss_arc[iarc];
|
||||
printf(" Arc to state %d, label %s\n",
|
||||
zz->sa_arrow,
|
||||
labelrepr(&ll->ll_label[zz->sa_label]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* PART THREE -- SIMPLIFY DFA */
|
||||
|
||||
/* Simplify the DFA by repeatedly eliminating states that are
|
||||
equivalent to another oner. This is NOT Algorithm 3.3 from
|
||||
[Aho&Ullman 77]. It does not always finds the minimal DFA,
|
||||
but it does usually make a much smaller one... (For an example
|
||||
of sub-optimal behaviour, try S: x a b+ | y a b+.)
|
||||
*/
|
||||
|
||||
static int
|
||||
samestate(s1, s2)
|
||||
ss_state *s1, *s2;
|
||||
{
|
||||
int i;
|
||||
|
||||
if (s1->ss_narcs != s2->ss_narcs || s1->ss_finish != s2->ss_finish)
|
||||
return 0;
|
||||
for (i = 0; i < s1->ss_narcs; i++) {
|
||||
if (s1->ss_arc[i].sa_arrow != s2->ss_arc[i].sa_arrow ||
|
||||
s1->ss_arc[i].sa_label != s2->ss_arc[i].sa_label)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
renamestates(xx_nstates, xx_state, from, to)
|
||||
int xx_nstates;
|
||||
ss_state *xx_state;
|
||||
int from, to;
|
||||
{
|
||||
int i, j;
|
||||
|
||||
if (debugging)
|
||||
printf("Rename state %d to %d.\n", from, to);
|
||||
for (i = 0; i < xx_nstates; i++) {
|
||||
if (xx_state[i].ss_deleted)
|
||||
continue;
|
||||
for (j = 0; j < xx_state[i].ss_narcs; j++) {
|
||||
if (xx_state[i].ss_arc[j].sa_arrow == from)
|
||||
xx_state[i].ss_arc[j].sa_arrow = to;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
simplify(xx_nstates, xx_state)
|
||||
int xx_nstates;
|
||||
ss_state *xx_state;
|
||||
{
|
||||
int changes;
|
||||
int i, j, k;
|
||||
|
||||
do {
|
||||
changes = 0;
|
||||
for (i = 1; i < xx_nstates; i++) {
|
||||
if (xx_state[i].ss_deleted)
|
||||
continue;
|
||||
for (j = 0; j < i; j++) {
|
||||
if (xx_state[j].ss_deleted)
|
||||
continue;
|
||||
if (samestate(&xx_state[i], &xx_state[j])) {
|
||||
xx_state[i].ss_deleted++;
|
||||
renamestates(xx_nstates, xx_state, i, j);
|
||||
changes++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (changes);
|
||||
}
|
||||
|
||||
|
||||
/* PART FOUR -- GENERATE PARSING TABLES */
|
||||
|
||||
/* Convert the DFA into a grammar that can be used by our parser */
|
||||
|
||||
static
|
||||
convert(d, xx_nstates, xx_state)
|
||||
dfa *d;
|
||||
int xx_nstates;
|
||||
ss_state *xx_state;
|
||||
{
|
||||
int i, j;
|
||||
ss_state *yy;
|
||||
ss_arc *zz;
|
||||
|
||||
for (i = 0; i < xx_nstates; i++) {
|
||||
yy = &xx_state[i];
|
||||
if (yy->ss_deleted)
|
||||
continue;
|
||||
yy->ss_rename = addstate(d);
|
||||
}
|
||||
|
||||
for (i = 0; i < xx_nstates; i++) {
|
||||
yy = &xx_state[i];
|
||||
if (yy->ss_deleted)
|
||||
continue;
|
||||
for (j = 0; j < yy->ss_narcs; j++) {
|
||||
zz = &yy->ss_arc[j];
|
||||
addarc(d, yy->ss_rename,
|
||||
xx_state[zz->sa_arrow].ss_rename,
|
||||
zz->sa_label);
|
||||
}
|
||||
if (yy->ss_finish)
|
||||
addarc(d, yy->ss_rename, yy->ss_rename, 0);
|
||||
}
|
||||
|
||||
d->d_initial = 0;
|
||||
}
|
||||
|
||||
|
||||
/* PART FIVE -- GLUE IT ALL TOGETHER */
|
||||
|
||||
static grammar *
|
||||
maketables(gr)
|
||||
nfagrammar *gr;
|
||||
{
|
||||
int i;
|
||||
nfa *nf;
|
||||
dfa *d;
|
||||
grammar *g;
|
||||
|
||||
if (gr->gr_nnfas == 0)
|
||||
return NULL;
|
||||
g = newgrammar(gr->gr_nfa[0]->nf_type);
|
||||
/* XXX first rule must be start rule */
|
||||
g->g_ll = gr->gr_ll;
|
||||
|
||||
for (i = 0; i < gr->gr_nnfas; i++) {
|
||||
nf = gr->gr_nfa[i];
|
||||
if (debugging) {
|
||||
printf("Dump of NFA for '%s' ...\n", nf->nf_name);
|
||||
dumpnfa(&gr->gr_ll, nf);
|
||||
}
|
||||
printf("Making DFA for '%s' ...\n", nf->nf_name);
|
||||
d = adddfa(g, nf->nf_type, nf->nf_name);
|
||||
makedfa(gr, gr->gr_nfa[i], d);
|
||||
}
|
||||
|
||||
return g;
|
||||
}
|
||||
|
||||
grammar *
|
||||
pgen(n)
|
||||
node *n;
|
||||
{
|
||||
nfagrammar *gr;
|
||||
grammar *g;
|
||||
|
||||
gr = metacompile(n);
|
||||
g = maketables(gr);
|
||||
translatelabels(g);
|
||||
addfirstsets(g);
|
||||
return g;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
Input is a grammar in extended BNF (using * for repetition, + for
|
||||
at-least-once repetition, [] for optional parts, | for alternatives and
|
||||
() for grouping). This has already been parsed and turned into a parse
|
||||
tree.
|
||||
|
||||
Each rule is considered as a regular expression in its own right.
|
||||
It is turned into a Non-deterministic Finite Automaton (NFA), which
|
||||
is then turned into a Deterministic Finite Automaton (DFA), which is then
|
||||
optimized to reduce the number of states. See [Aho&Ullman 77] chapter 3,
|
||||
or similar compiler books (this technique is more often used for lexical
|
||||
analyzers).
|
||||
|
||||
The DFA's are used by the parser as parsing tables in a special way
|
||||
that's probably unique. Before they are usable, the FIRST sets of all
|
||||
non-terminals are computed.
|
||||
|
||||
Reference
|
||||
---------
|
||||
|
||||
[Aho&Ullman 77]
|
||||
Aho&Ullman, Principles of Compiler Design, Addison-Wesley 1977
|
||||
(first edition)
|
||||
|
||||
*/
|
|
@ -0,0 +1,6 @@
|
|||
/* Parser generator interface */
|
||||
|
||||
extern grammar gram;
|
||||
|
||||
extern grammar *meta_grammar PROTO((void));
|
||||
extern grammar *pgen PROTO((node *));
|
|
@ -0,0 +1,111 @@
|
|||
/* Parser generator main program */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "PROTO.h"
|
||||
#include "grammar.h"
|
||||
#include "node.h"
|
||||
#include "parsetok.h"
|
||||
#include "pgen.h"
|
||||
|
||||
int debugging;
|
||||
|
||||
#ifdef THINK_C
|
||||
char *
|
||||
askfile()
|
||||
{
|
||||
char buf[256];
|
||||
static char name[256];
|
||||
printf("Input file name: ");
|
||||
if (fgets(buf, sizeof buf, stdin) == NULL) {
|
||||
printf("EOF\n");
|
||||
exit(1);
|
||||
}
|
||||
if (sscanf(buf, " %s ", name) != 1) {
|
||||
printf("No file\n");
|
||||
exit(1);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
#endif
|
||||
|
||||
grammar *
|
||||
getgrammar(filename)
|
||||
char *filename;
|
||||
{
|
||||
FILE *fp;
|
||||
node *n;
|
||||
grammar *g0, *g;
|
||||
|
||||
fp = fopen(filename, "r");
|
||||
if (fp == NULL) {
|
||||
perror(filename);
|
||||
exit(1);
|
||||
}
|
||||
g0 = meta_grammar();
|
||||
n = NULL;
|
||||
parsefile(fp, g0, g0->g_start, (char *)NULL, (char *)NULL, &n);
|
||||
fclose(fp);
|
||||
if (n == NULL) {
|
||||
fprintf(stderr, "Parsing error.\n");
|
||||
exit(1);
|
||||
}
|
||||
g = pgen(n);
|
||||
if (g == NULL) {
|
||||
printf("Bad grammar.\n");
|
||||
exit(1);
|
||||
}
|
||||
return g;
|
||||
}
|
||||
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
grammar *g;
|
||||
node *n;
|
||||
FILE *fp;
|
||||
char *filename;
|
||||
|
||||
#ifdef THINK_C
|
||||
filename = askfile();
|
||||
#else
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "usage: %s grammar\n", argv[0]);
|
||||
exit(2);
|
||||
}
|
||||
filename = argv[1];
|
||||
#endif
|
||||
g = getgrammar(filename);
|
||||
fp = fopen("graminit.c", "w");
|
||||
if (fp == NULL) {
|
||||
perror("graminit.c");
|
||||
exit(1);
|
||||
}
|
||||
printf("Writing graminit.c ...\n");
|
||||
printgrammar(g, fp);
|
||||
fclose(fp);
|
||||
fp = fopen("graminit.h", "w");
|
||||
if (fp == NULL) {
|
||||
perror("graminit.h");
|
||||
exit(1);
|
||||
}
|
||||
printf("Writing graminit.h ...\n");
|
||||
printnonterminals(g, fp);
|
||||
fclose(fp);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void
|
||||
fatal(msg)
|
||||
char *msg;
|
||||
{
|
||||
fprintf(stderr, "pgen: FATAL ERROR: %s\n", msg);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* TO DO:
|
||||
|
||||
- improve user interface
|
||||
- check for duplicate definitions of names (instead of fatal err)
|
||||
*/
|
|
@ -0,0 +1,121 @@
|
|||
/* Print a bunch of C initializers that represent a grammar */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "PROTO.h"
|
||||
#include "grammar.h"
|
||||
|
||||
static void
|
||||
printarcs(i, d, fp)
|
||||
int i;
|
||||
dfa *d;
|
||||
FILE *fp;
|
||||
{
|
||||
arc *a;
|
||||
state *s;
|
||||
int j, k;
|
||||
|
||||
s = d->d_state;
|
||||
for (j = 0; j < d->d_nstates; j++, s++) {
|
||||
fprintf(fp, "static arc arcs_%d_%d[%d] = {\n",
|
||||
i, j, s->s_narcs);
|
||||
a = s->s_arc;
|
||||
for (k = 0; k < s->s_narcs; k++, a++)
|
||||
fprintf(fp, "\t{%d, %d},\n", a->a_lbl, a->a_arrow);
|
||||
fprintf(fp, "};\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
printstates(g, fp)
|
||||
grammar *g;
|
||||
FILE *fp;
|
||||
{
|
||||
state *s;
|
||||
dfa *d;
|
||||
int i, j;
|
||||
|
||||
d = g->g_dfa;
|
||||
for (i = 0; i < g->g_ndfas; i++, d++) {
|
||||
printarcs(i, d, fp);
|
||||
fprintf(fp, "static state states_%d[%d] = {\n",
|
||||
i, d->d_nstates);
|
||||
s = d->d_state;
|
||||
for (j = 0; j < d->d_nstates; j++, s++)
|
||||
fprintf(fp, "\t{%d, arcs_%d_%d},\n",
|
||||
s->s_narcs, i, j);
|
||||
fprintf(fp, "};\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
printdfas(g, fp)
|
||||
grammar *g;
|
||||
FILE *fp;
|
||||
{
|
||||
dfa *d;
|
||||
int i, j;
|
||||
|
||||
printstates(g, fp);
|
||||
fprintf(fp, "static dfa dfas[%d] = {\n", g->g_ndfas);
|
||||
d = g->g_dfa;
|
||||
for (i = 0; i < g->g_ndfas; i++, d++) {
|
||||
fprintf(fp, "\t{%d, \"%s\", %d, %d, states_%d,\n",
|
||||
d->d_type, d->d_name, d->d_initial, d->d_nstates, i);
|
||||
fprintf(fp, "\t \"");
|
||||
for (j = 0; j < NBYTES(g->g_ll.ll_nlabels); j++)
|
||||
fprintf(fp, "\\%03o", d->d_first[j] & 0xff);
|
||||
fprintf(fp, "\"},\n");
|
||||
}
|
||||
fprintf(fp, "};\n");
|
||||
}
|
||||
|
||||
static void
|
||||
printlabels(g, fp)
|
||||
grammar *g;
|
||||
FILE *fp;
|
||||
{
|
||||
label *l;
|
||||
int i;
|
||||
|
||||
fprintf(fp, "static label labels[%d] = {\n", g->g_ll.ll_nlabels);
|
||||
l = g->g_ll.ll_label;
|
||||
for (i = g->g_ll.ll_nlabels; --i >= 0; l++) {
|
||||
if (l->lb_str == NULL)
|
||||
fprintf(fp, "\t{%d, 0},\n", l->lb_type);
|
||||
else
|
||||
fprintf(fp, "\t{%d, \"%s\"},\n",
|
||||
l->lb_type, l->lb_str);
|
||||
}
|
||||
fprintf(fp, "};\n");
|
||||
}
|
||||
|
||||
void
|
||||
printgrammar(g, fp)
|
||||
grammar *g;
|
||||
FILE *fp;
|
||||
{
|
||||
fprintf(fp, "#include \"PROTO.h\"\n");
|
||||
fprintf(fp, "#include \"grammar.h\"\n");
|
||||
printdfas(g, fp);
|
||||
printlabels(g, fp);
|
||||
fprintf(fp, "grammar gram = {\n");
|
||||
fprintf(fp, "\t%d,\n", g->g_ndfas);
|
||||
fprintf(fp, "\tdfas,\n");
|
||||
fprintf(fp, "\t{%d, labels},\n", g->g_ll.ll_nlabels);
|
||||
fprintf(fp, "\t%d\n", g->g_start);
|
||||
fprintf(fp, "};\n");
|
||||
}
|
||||
|
||||
void
|
||||
printnonterminals(g, fp)
|
||||
grammar *g;
|
||||
FILE *fp;
|
||||
{
|
||||
dfa *d;
|
||||
int i;
|
||||
|
||||
d = g->g_dfa;
|
||||
for (i = g->g_ndfas; --i >= 0; d++)
|
||||
fprintf(fp, "#define %s %d\n", d->d_name, d->d_type);
|
||||
}
|
|
@ -0,0 +1,490 @@
|
|||
/* Tokenizer implementation */
|
||||
|
||||
/* XXX This is rather old, should be restructured perhaps */
|
||||
/* XXX Need a better interface to report errors than writing to stderr */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include "string.h"
|
||||
|
||||
#include "PROTO.h"
|
||||
#include "malloc.h"
|
||||
#include "tokenizer.h"
|
||||
#include "errcode.h"
|
||||
|
||||
#ifdef THINK_C
|
||||
#define TABSIZE 4
|
||||
#endif
|
||||
|
||||
#ifndef TABSIZE
|
||||
#define TABSIZE 8
|
||||
#endif
|
||||
|
||||
/* Token names */
|
||||
|
||||
char *tok_name[] = {
|
||||
"ENDMARKER",
|
||||
"NAME",
|
||||
"NUMBER",
|
||||
"STRING",
|
||||
"NEWLINE",
|
||||
"INDENT",
|
||||
"DEDENT",
|
||||
"LPAR",
|
||||
"RPAR",
|
||||
"LSQB",
|
||||
"RSQB",
|
||||
"COLON",
|
||||
"COMMA",
|
||||
"SEMI",
|
||||
"PLUS",
|
||||
"MINUS",
|
||||
"STAR",
|
||||
"SLASH",
|
||||
"VBAR",
|
||||
"AMPER",
|
||||
"LESS",
|
||||
"GREATER",
|
||||
"EQUAL",
|
||||
"DOT",
|
||||
"PERCENT",
|
||||
"BACKQUOTE",
|
||||
"LBRACE",
|
||||
"RBRACE",
|
||||
"OP",
|
||||
"<ERRORTOKEN>",
|
||||
"<N_TOKENS>"
|
||||
};
|
||||
|
||||
|
||||
/* Create and initialize a new tok_state structure */
|
||||
|
||||
static struct tok_state *
|
||||
tok_new()
|
||||
{
|
||||
struct tok_state *tok = NEW(struct tok_state, 1);
|
||||
if (tok == NULL)
|
||||
return NULL;
|
||||
tok->buf = tok->cur = tok->end = tok->inp = NULL;
|
||||
tok->done = E_OK;
|
||||
tok->fp = NULL;
|
||||
tok->tabsize = TABSIZE;
|
||||
tok->indent = 0;
|
||||
tok->indstack[0] = 0;
|
||||
tok->atbol = 1;
|
||||
tok->pendin = 0;
|
||||
tok->prompt = tok->nextprompt = NULL;
|
||||
tok->lineno = 0;
|
||||
return tok;
|
||||
}
|
||||
|
||||
|
||||
/* Set up tokenizer for string */
|
||||
|
||||
struct tok_state *
|
||||
tok_setups(str)
|
||||
char *str;
|
||||
{
|
||||
struct tok_state *tok = tok_new();
|
||||
if (tok == NULL)
|
||||
return NULL;
|
||||
tok->buf = tok->cur = str;
|
||||
tok->end = tok->inp = strchr(str, '\0');
|
||||
return tok;
|
||||
}
|
||||
|
||||
|
||||
/* Set up tokenizer for string */
|
||||
|
||||
struct tok_state *
|
||||
tok_setupf(fp, ps1, ps2)
|
||||
FILE *fp;
|
||||
char *ps1, *ps2;
|
||||
{
|
||||
struct tok_state *tok = tok_new();
|
||||
if (tok == NULL)
|
||||
return NULL;
|
||||
if ((tok->buf = NEW(char, BUFSIZ)) == NULL) {
|
||||
DEL(tok);
|
||||
return NULL;
|
||||
}
|
||||
tok->cur = tok->inp = tok->buf;
|
||||
tok->end = tok->buf + BUFSIZ;
|
||||
tok->fp = fp;
|
||||
tok->prompt = ps1;
|
||||
tok->nextprompt = ps2;
|
||||
return tok;
|
||||
}
|
||||
|
||||
|
||||
/* Free a tok_state structure */
|
||||
|
||||
void
|
||||
tok_free(tok)
|
||||
struct tok_state *tok;
|
||||
{
|
||||
/* XXX really need a separate flag to say 'my buffer' */
|
||||
if (tok->fp != NULL && tok->buf != NULL)
|
||||
DEL(tok->buf);
|
||||
DEL(tok);
|
||||
}
|
||||
|
||||
|
||||
/* Get next char, updating state; error code goes into tok->done */
|
||||
|
||||
static int
|
||||
tok_nextc(tok)
|
||||
register struct tok_state *tok;
|
||||
{
|
||||
if (tok->done != E_OK)
|
||||
return EOF;
|
||||
|
||||
for (;;) {
|
||||
if (tok->cur < tok->inp)
|
||||
return *tok->cur++;
|
||||
if (tok->fp == NULL) {
|
||||
tok->done = E_EOF;
|
||||
return EOF;
|
||||
}
|
||||
if (tok->inp > tok->buf && tok->inp[-1] == '\n')
|
||||
tok->inp = tok->buf;
|
||||
if (tok->inp == tok->end) {
|
||||
int n = tok->end - tok->buf;
|
||||
char *new = tok->buf;
|
||||
RESIZE(new, char, n+n);
|
||||
if (new == NULL) {
|
||||
fprintf(stderr, "tokenizer out of mem\n");
|
||||
tok->done = E_NOMEM;
|
||||
return EOF;
|
||||
}
|
||||
tok->buf = new;
|
||||
tok->inp = tok->buf + n;
|
||||
tok->end = tok->inp + n;
|
||||
}
|
||||
#ifdef USE_READLINE
|
||||
if (tok->prompt != NULL) {
|
||||
extern char *readline PROTO((char *prompt));
|
||||
static int been_here;
|
||||
if (!been_here) {
|
||||
/* Force rebind of TAB to insert-tab */
|
||||
extern int rl_insert();
|
||||
rl_bind_key('\t', rl_insert);
|
||||
been_here++;
|
||||
}
|
||||
if (tok->buf != NULL)
|
||||
free(tok->buf);
|
||||
tok->buf = readline(tok->prompt);
|
||||
(void) intrcheck(); /* Clear pending interrupt */
|
||||
if (tok->nextprompt != NULL)
|
||||
tok->prompt = tok->nextprompt;
|
||||
/* XXX different semantics w/o readline()! */
|
||||
if (tok->buf == NULL) {
|
||||
tok->done = E_EOF;
|
||||
}
|
||||
else {
|
||||
unsigned int n = strlen(tok->buf);
|
||||
if (n > 0)
|
||||
add_history(tok->buf);
|
||||
/* Append the '\n' that readline()
|
||||
doesn't give us, for the tokenizer... */
|
||||
tok->buf = realloc(tok->buf, n+2);
|
||||
if (tok->buf == NULL)
|
||||
tok->done = E_NOMEM;
|
||||
else {
|
||||
tok->end = tok->buf + n;
|
||||
*tok->end++ = '\n';
|
||||
*tok->end = '\0';
|
||||
tok->inp = tok->end;
|
||||
tok->cur = tok->buf;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
tok->cur = tok->inp;
|
||||
if (tok->prompt != NULL && tok->inp == tok->buf) {
|
||||
fprintf(stderr, "%s", tok->prompt);
|
||||
tok->prompt = tok->nextprompt;
|
||||
}
|
||||
tok->done = fgets_intr(tok->inp,
|
||||
(int)(tok->end - tok->inp), tok->fp);
|
||||
}
|
||||
if (tok->done != E_OK) {
|
||||
if (tok->prompt != NULL)
|
||||
fprintf(stderr, "\n");
|
||||
return EOF;
|
||||
}
|
||||
tok->inp = strchr(tok->inp, '\0');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Back-up one character */
|
||||
|
||||
static void
|
||||
tok_backup(tok, c)
|
||||
register struct tok_state *tok;
|
||||
register int c;
|
||||
{
|
||||
if (c != EOF) {
|
||||
if (--tok->cur < tok->buf) {
|
||||
fprintf(stderr, "tok_backup: begin of buffer\n");
|
||||
abort();
|
||||
}
|
||||
if (*tok->cur != c)
|
||||
*tok->cur = c;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Return the token corresponding to a single character */
|
||||
|
||||
int
|
||||
tok_1char(c)
|
||||
int c;
|
||||
{
|
||||
switch (c) {
|
||||
case '(': return LPAR;
|
||||
case ')': return RPAR;
|
||||
case '[': return LSQB;
|
||||
case ']': return RSQB;
|
||||
case ':': return COLON;
|
||||
case ',': return COMMA;
|
||||
case ';': return SEMI;
|
||||
case '+': return PLUS;
|
||||
case '-': return MINUS;
|
||||
case '*': return STAR;
|
||||
case '/': return SLASH;
|
||||
case '|': return VBAR;
|
||||
case '&': return AMPER;
|
||||
case '<': return LESS;
|
||||
case '>': return GREATER;
|
||||
case '=': return EQUAL;
|
||||
case '.': return DOT;
|
||||
case '%': return PERCENT;
|
||||
case '`': return BACKQUOTE;
|
||||
case '{': return LBRACE;
|
||||
case '}': return RBRACE;
|
||||
default: return OP;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Get next token, after space stripping etc. */
|
||||
|
||||
int
|
||||
tok_get(tok, p_start, p_end)
|
||||
register struct tok_state *tok; /* In/out: tokenizer state */
|
||||
char **p_start, **p_end; /* Out: point to start/end of token */
|
||||
{
|
||||
register int c;
|
||||
|
||||
/* Get indentation level */
|
||||
if (tok->atbol) {
|
||||
register int col = 0;
|
||||
tok->atbol = 0;
|
||||
tok->lineno++;
|
||||
for (;;) {
|
||||
c = tok_nextc(tok);
|
||||
if (c == ' ')
|
||||
col++;
|
||||
else if (c == '\t')
|
||||
col = (col/tok->tabsize + 1) * tok->tabsize;
|
||||
else
|
||||
break;
|
||||
}
|
||||
tok_backup(tok, c);
|
||||
if (col == tok->indstack[tok->indent]) {
|
||||
/* No change */
|
||||
}
|
||||
else if (col > tok->indstack[tok->indent]) {
|
||||
/* Indent -- always one */
|
||||
if (tok->indent+1 >= MAXINDENT) {
|
||||
fprintf(stderr, "excessive indent\n");
|
||||
tok->done = E_TOKEN;
|
||||
return ERRORTOKEN;
|
||||
}
|
||||
tok->pendin++;
|
||||
tok->indstack[++tok->indent] = col;
|
||||
}
|
||||
else /* col < tok->indstack[tok->indent] */ {
|
||||
/* Dedent -- any number, must be consistent */
|
||||
while (tok->indent > 0 &&
|
||||
col < tok->indstack[tok->indent]) {
|
||||
tok->indent--;
|
||||
tok->pendin--;
|
||||
}
|
||||
if (col != tok->indstack[tok->indent]) {
|
||||
fprintf(stderr, "inconsistent dedent\n");
|
||||
tok->done = E_TOKEN;
|
||||
return ERRORTOKEN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*p_start = *p_end = tok->cur;
|
||||
|
||||
/* Return pending indents/dedents */
|
||||
if (tok->pendin != 0) {
|
||||
if (tok->pendin < 0) {
|
||||
tok->pendin++;
|
||||
return DEDENT;
|
||||
}
|
||||
else {
|
||||
tok->pendin--;
|
||||
return INDENT;
|
||||
}
|
||||
}
|
||||
|
||||
again:
|
||||
/* Skip spaces */
|
||||
do {
|
||||
c = tok_nextc(tok);
|
||||
} while (c == ' ' || c == '\t');
|
||||
|
||||
/* Set start of current token */
|
||||
*p_start = tok->cur - 1;
|
||||
|
||||
/* Skip comment */
|
||||
if (c == '#') {
|
||||
/* Hack to allow overriding the tabsize in the file.
|
||||
This is also recognized by vi, when it occurs near the
|
||||
beginning or end of the file. (Will vi never die...?) */
|
||||
int x;
|
||||
if (sscanf(tok->cur, " vi:set tabsize=%d:", &x) == 1 &&
|
||||
x >= 1 && x <= 40) {
|
||||
fprintf(stderr, "# vi:set tabsize=%d:\n", x);
|
||||
tok->tabsize = x;
|
||||
}
|
||||
do {
|
||||
c = tok_nextc(tok);
|
||||
} while (c != EOF && c != '\n');
|
||||
}
|
||||
|
||||
/* Check for EOF and errors now */
|
||||
if (c == EOF)
|
||||
return tok->done == E_EOF ? ENDMARKER : ERRORTOKEN;
|
||||
|
||||
/* Identifier (most frequent token!) */
|
||||
if (isalpha(c) || c == '_') {
|
||||
do {
|
||||
c = tok_nextc(tok);
|
||||
} while (isalnum(c) || c == '_');
|
||||
tok_backup(tok, c);
|
||||
*p_end = tok->cur;
|
||||
return NAME;
|
||||
}
|
||||
|
||||
/* Newline */
|
||||
if (c == '\n') {
|
||||
tok->atbol = 1;
|
||||
*p_end = tok->cur - 1; /* Leave '\n' out of the string */
|
||||
return NEWLINE;
|
||||
}
|
||||
|
||||
/* Number */
|
||||
if (isdigit(c)) {
|
||||
if (c == '0') {
|
||||
/* Hex or octal */
|
||||
c = tok_nextc(tok);
|
||||
if (c == '.')
|
||||
goto fraction;
|
||||
if (c == 'x' || c == 'X') {
|
||||
/* Hex */
|
||||
do {
|
||||
c = tok_nextc(tok);
|
||||
} while (isxdigit(c));
|
||||
}
|
||||
else {
|
||||
/* Octal; c is first char of it */
|
||||
/* There's no 'isoctdigit' macro, sigh */
|
||||
while ('0' <= c && c < '8') {
|
||||
c = tok_nextc(tok);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Decimal */
|
||||
do {
|
||||
c = tok_nextc(tok);
|
||||
} while (isdigit(c));
|
||||
/* Accept floating point numbers.
|
||||
XXX This accepts incomplete things like 12e or 1e+;
|
||||
worry about that at run-time.
|
||||
XXX Doesn't accept numbers starting with a dot */
|
||||
if (c == '.') {
|
||||
fraction:
|
||||
/* Fraction */
|
||||
do {
|
||||
c = tok_nextc(tok);
|
||||
} while (isdigit(c));
|
||||
}
|
||||
if (c == 'e' || c == 'E') {
|
||||
/* Exponent part */
|
||||
c = tok_nextc(tok);
|
||||
if (c == '+' || c == '-')
|
||||
c = tok_nextc(tok);
|
||||
while (isdigit(c)) {
|
||||
c = tok_nextc(tok);
|
||||
}
|
||||
}
|
||||
}
|
||||
tok_backup(tok, c);
|
||||
*p_end = tok->cur;
|
||||
return NUMBER;
|
||||
}
|
||||
|
||||
/* String */
|
||||
if (c == '\'') {
|
||||
for (;;) {
|
||||
c = tok_nextc(tok);
|
||||
if (c == '\n' || c == EOF) {
|
||||
tok->done = E_TOKEN;
|
||||
return ERRORTOKEN;
|
||||
}
|
||||
if (c == '\\') {
|
||||
c = tok_nextc(tok);
|
||||
*p_end = tok->cur;
|
||||
if (c == '\n' || c == EOF) {
|
||||
tok->done = E_TOKEN;
|
||||
return ERRORTOKEN;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (c == '\'')
|
||||
break;
|
||||
}
|
||||
*p_end = tok->cur;
|
||||
return STRING;
|
||||
}
|
||||
|
||||
/* Line continuation */
|
||||
if (c == '\\') {
|
||||
c = tok_nextc(tok);
|
||||
if (c != '\n') {
|
||||
tok->done = E_TOKEN;
|
||||
return ERRORTOKEN;
|
||||
}
|
||||
goto again; /* Read next line */
|
||||
}
|
||||
|
||||
/* Punctuation character */
|
||||
*p_end = tok->cur;
|
||||
return tok_1char(c);
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
void
|
||||
tok_dump(type, start, end)
|
||||
int type;
|
||||
char *start, *end;
|
||||
{
|
||||
printf("%s", tok_name[type]);
|
||||
if (type == NAME || type == NUMBER || type == STRING || type == OP)
|
||||
printf("(%.*s)", (int)(end - start), start);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,29 @@
|
|||
/* Tokenizer interface */
|
||||
|
||||
#include "token.h" /* For token types */
|
||||
|
||||
#define MAXINDENT 100 /* Max indentation level */
|
||||
|
||||
/* Tokenizer state */
|
||||
struct tok_state {
|
||||
/* Input state; buf <= cur <= inp <= end */
|
||||
/* NB an entire token must fit in the buffer */
|
||||
char *buf; /* Input buffer */
|
||||
char *cur; /* Next character in buffer */
|
||||
char *inp; /* End of data in buffer */
|
||||
char *end; /* End of input buffer */
|
||||
int done; /* 0 normally, 1 at EOF, -1 after error */
|
||||
FILE *fp; /* Rest of input; NULL if tokenizing a string */
|
||||
int tabsize; /* Tab spacing */
|
||||
int indent; /* Current indentation index */
|
||||
int indstack[MAXINDENT]; /* Stack of indents */
|
||||
int atbol; /* Nonzero if at begin of new line */
|
||||
int pendin; /* Pending indents (if > 0) or dedents (if < 0) */
|
||||
char *prompt, *nextprompt; /* For interactive prompting */
|
||||
int lineno; /* Current line number */
|
||||
};
|
||||
|
||||
extern struct tok_state *tok_setups PROTO((char *));
|
||||
extern struct tok_state *tok_setupf PROTO((FILE *, char *ps1, char *ps2));
|
||||
extern void tok_free PROTO((struct tok_state *));
|
||||
extern int tok_get PROTO((struct tok_state *, char **, char **));
|
|
@ -0,0 +1,369 @@
|
|||
/* Functions used by cgen output */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#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();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
/* 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 UNIX 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 getoserror() (sp.?) 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_set(valexception,
|
||||
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 <stdio.h>
|
||||
|
||||
#include "PROTO.h"
|
||||
#include "object.h"
|
||||
#include "stringobject.h"
|
||||
#include "errors.h"
|
||||
|
||||
/* Last exception stored by err_setval() */
|
||||
|
||||
static object *last_exception;
|
||||
static object *last_exc_val;
|
||||
|
||||
void
|
||||
err_setval(exception, value)
|
||||
object *exception;
|
||||
object *value;
|
||||
{
|
||||
if (last_exception != NULL)
|
||||
DECREF(last_exception);
|
||||
if (exception != NULL)
|
||||
INCREF(exception);
|
||||
last_exception = exception;
|
||||
|
||||
if (last_exc_val != NULL)
|
||||
DECREF(last_exc_val);
|
||||
if (value != NULL)
|
||||
INCREF(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);
|
||||
if (value != NULL)
|
||||
DECREF(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()
|
||||
{
|
||||
if (last_exception != NULL) {
|
||||
DECREF(last_exception);
|
||||
last_exception = NULL;
|
||||
}
|
||||
if (last_exc_val != NULL) {
|
||||
DECREF(last_exc_val);
|
||||
last_exc_val = NULL;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/* Portable fmod(x, y) implementation for systems that don't have it */
|
||||
|
||||
#include <math.h>
|
||||
#include <errno.h>
|
||||
|
||||
extern int errno;
|
||||
|
||||
double
|
||||
fmod(x, y)
|
||||
double x, y;
|
||||
{
|
||||
double i, f;
|
||||
|
||||
if (y == 0.0) {
|
||||
errno = EDOM;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
/* return f such that x = i*y + f for some integer i
|
||||
such that |f| < |y| and f has the same sign as x */
|
||||
|
||||
i = floor(x/y);
|
||||
f = x - i*y;
|
||||
if ((x < 0.0) != (y < 0.0))
|
||||
f = f-y;
|
||||
return f;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,252 @@
|
|||
/* Module definition and import implementation */
|
||||
|
||||
#include <stdio.h>
|
||||
#include "string.h"
|
||||
|
||||
#include "PROTO.h"
|
||||
#include "object.h"
|
||||
#include "stringobject.h"
|
||||
#include "listobject.h"
|
||||
#include "dictobject.h"
|
||||
#include "moduleobject.h"
|
||||
#include "node.h"
|
||||
#include "context.h"
|
||||
#include "token.h"
|
||||
#include "graminit.h"
|
||||
#include "run.h"
|
||||
#include "support.h"
|
||||
#include "import.h"
|
||||
#include "errcode.h"
|
||||
#include "sysmodule.h"
|
||||
|
||||
/* Define pathname separator and delimiter in $PYTHONPATH */
|
||||
|
||||
#ifdef THINK_C
|
||||
#define SEP ':'
|
||||
#define DELIM ' '
|
||||
#endif
|
||||
|
||||
#ifndef SEP
|
||||
#define SEP '/'
|
||||
#endif
|
||||
|
||||
#ifndef DELIM
|
||||
#define DELIM ':'
|
||||
#endif
|
||||
|
||||
void
|
||||
initimport()
|
||||
{
|
||||
object *v;
|
||||
if ((v = newdictobject()) == NULL)
|
||||
fatal("no mem for module table");
|
||||
if (sysset("modules", v) != 0)
|
||||
fatal("can't assign sys.modules");
|
||||
}
|
||||
|
||||
object *
|
||||
new_module(name)
|
||||
char *name;
|
||||
{
|
||||
object *m;
|
||||
object *mtab;
|
||||
mtab = sysget("modules");
|
||||
if (mtab == NULL || !is_dictobject(mtab)) {
|
||||
errno = EBADF;
|
||||
return NULL;
|
||||
}
|
||||
m = newmoduleobject(name);
|
||||
if (m == NULL)
|
||||
return NULL;
|
||||
if (dictinsert(mtab, name, m) != 0) {
|
||||
DECREF(m);
|
||||
return NULL;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
void
|
||||
define_module(ctx, name)
|
||||
context *ctx;
|
||||
char *name;
|
||||
{
|
||||
object *m, *d;
|
||||
m = new_module(name);
|
||||
if (m == NULL) {
|
||||
puterrno(ctx);
|
||||
return;
|
||||
}
|
||||
d = getmoduledict(m);
|
||||
INCREF(d);
|
||||
DECREF(ctx->ctx_locals);
|
||||
ctx->ctx_locals = d;
|
||||
INCREF(d);
|
||||
DECREF(ctx->ctx_globals);
|
||||
ctx->ctx_globals = d;
|
||||
DECREF(m);
|
||||
}
|
||||
|
||||
object *
|
||||
parsepath(path, delim)
|
||||
char *path;
|
||||
int delim;
|
||||
{
|
||||
int i, n;
|
||||
char *p;
|
||||
object *v, *w;
|
||||
|
||||
n = 1;
|
||||
p = path;
|
||||
while ((p = strchr(p, delim)) != NULL) {
|
||||
n++;
|
||||
p++;
|
||||
}
|
||||
v = newlistobject(n);
|
||||
if (v == NULL)
|
||||
return NULL;
|
||||
for (i = 0; ; i++) {
|
||||
p = strchr(path, delim);
|
||||
if (p == NULL)
|
||||
p = strchr(path, '\0'); /* End of string */
|
||||
w = newsizedstringobject(path, (int) (p - path));
|
||||
if (w == NULL) {
|
||||
DECREF(v);
|
||||
return NULL;
|
||||
}
|
||||
setlistitem(v, i, w);
|
||||
if (*p == '\0')
|
||||
break;
|
||||
path = p+1;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
void
|
||||
setpythonpath(path)
|
||||
char *path;
|
||||
{
|
||||
object *v;
|
||||
if ((v = parsepath(path, DELIM)) != NULL) {
|
||||
if (sysset("path", v) != 0)
|
||||
fatal("can't assign sys.path");
|
||||
DECREF(v);
|
||||
}
|
||||
}
|
||||
|
||||
static FILE *
|
||||
open_module(name, suffix)
|
||||
char *name;
|
||||
char *suffix;
|
||||
{
|
||||
object *path;
|
||||
char namebuf[256];
|
||||
FILE *fp;
|
||||
|
||||
path = sysget("path");
|
||||
if (path == NULL || !is_listobject(path)) {
|
||||
strcpy(namebuf, name);
|
||||
strcat(namebuf, suffix);
|
||||
fp = fopen(namebuf, "r");
|
||||
}
|
||||
else {
|
||||
int npath = getlistsize(path);
|
||||
int i;
|
||||
fp = NULL;
|
||||
for (i = 0; i < npath; i++) {
|
||||
object *v = getlistitem(path, i);
|
||||
int len;
|
||||
if (!is_stringobject(v))
|
||||
continue;
|
||||
strcpy(namebuf, getstringvalue(v));
|
||||
len = getstringsize(v);
|
||||
if (len > 0 && namebuf[len-1] != SEP)
|
||||
namebuf[len++] = SEP;
|
||||
strcpy(namebuf+len, name); /* XXX check for overflow */
|
||||
strcat(namebuf, suffix); /* XXX ditto */
|
||||
fp = fopen(namebuf, "r");
|
||||
if (fp != NULL)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return fp;
|
||||
}
|
||||
|
||||
static object *
|
||||
load_module(ctx, name)
|
||||
context *ctx;
|
||||
char *name;
|
||||
{
|
||||
object *m;
|
||||
char **p;
|
||||
FILE *fp;
|
||||
node *n, *mh;
|
||||
int err;
|
||||
object *mtab;
|
||||
object *save_locals, *save_globals;
|
||||
|
||||
mtab = sysget("modules");
|
||||
if (mtab == NULL || !is_dictobject(mtab)) {
|
||||
errno = EBADF;
|
||||
return NULL;
|
||||
}
|
||||
fp = open_module(name, ".py");
|
||||
if (fp == NULL) {
|
||||
/* XXX Compatibility hack */
|
||||
fprintf(stderr,
|
||||
"Can't find '%s.py' in sys.path, trying '%s'\n",
|
||||
name, name);
|
||||
fp = open_module(name, "");
|
||||
}
|
||||
if (fp == NULL) {
|
||||
name_error(ctx, name);
|
||||
return NULL;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Reading module %s from file '%s'\n", name, namebuf);
|
||||
#endif
|
||||
err = parseinput(fp, file_input, &n);
|
||||
fclose(fp);
|
||||
if (err != E_DONE) {
|
||||
input_error(ctx, err);
|
||||
return NULL;
|
||||
}
|
||||
save_locals = ctx->ctx_locals;
|
||||
INCREF(save_locals);
|
||||
save_globals = ctx->ctx_globals;
|
||||
INCREF(save_globals);
|
||||
define_module(ctx, name);
|
||||
exec_node(ctx, n);
|
||||
DECREF(ctx->ctx_locals);
|
||||
ctx->ctx_locals = save_locals;
|
||||
DECREF(ctx->ctx_globals);
|
||||
ctx->ctx_globals = save_globals;
|
||||
/* XXX need to free the tree n here; except referenced defs */
|
||||
if (ctx->ctx_exception) {
|
||||
dictremove(mtab, name); /* Undefine the module */
|
||||
return NULL;
|
||||
}
|
||||
m = dictlookup(mtab, name);
|
||||
if (m == NULL) {
|
||||
error(ctx, "module not defined after loading");
|
||||
return NULL;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
object *
|
||||
import_module(ctx, name)
|
||||
context *ctx;
|
||||
char *name;
|
||||
{
|
||||
object *m;
|
||||
object *mtab;
|
||||
mtab = sysget("modules");
|
||||
if (mtab == NULL || !is_dictobject(mtab)) {
|
||||
error(ctx, "bad sys.modules");
|
||||
return NULL;
|
||||
}
|
||||
if ((m = dictlookup(mtab, name)) == NULL) {
|
||||
m = load_module(ctx, name);
|
||||
}
|
||||
return m;
|
||||
}
|
|
@ -0,0 +1,398 @@
|
|||
/* Module support implementation */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "PROTO.h"
|
||||
#include "object.h"
|
||||
#include "intobject.h"
|
||||
#include "stringobject.h"
|
||||
#include "tupleobject.h"
|
||||
#include "listobject.h"
|
||||
#include "methodobject.h"
|
||||
#include "moduleobject.h"
|
||||
#include "modsupport.h"
|
||||
#include "import.h"
|
||||
#include "errors.h"
|
||||
|
||||
|
||||
/* Find a method in a module's method table.
|
||||
Usually called from a module's getattr method. */
|
||||
|
||||
object *
|
||||
findmethod(ml, op, name)
|
||||
struct methodlist *ml;
|
||||
object *op;
|
||||
char *name;
|
||||
{
|
||||
for (; ml->ml_name != NULL; ml++) {
|
||||
if (strcmp(name, ml->ml_name) == 0)
|
||||
return newmethodobject(ml->ml_name, ml->ml_meth, op);
|
||||
}
|
||||
err_setstr(NameError, name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
object *
|
||||
initmodule(name, methods)
|
||||
char *name;
|
||||
struct methodlist *methods;
|
||||
{
|
||||
object *m, *d, *v;
|
||||
struct methodlist *ml;
|
||||
if ((m = new_module(name)) == NULL) {
|
||||
fprintf(stderr, "initializing module: %s\n", name);
|
||||
fatal("can't create a module");
|
||||
}
|
||||
d = getmoduledict(m);
|
||||
for (ml = methods; ml->ml_name != NULL; ml++) {
|
||||
v = newmethodobject(ml->ml_name, ml->ml_meth, (object *)NULL);
|
||||
if (v == NULL || dictinsert(d, ml->ml_name, v) != 0) {
|
||||
fprintf(stderr, "initializing module: %s\n", name);
|
||||
fatal("can't initialize module");
|
||||
}
|
||||
DECREF(v);
|
||||
}
|
||||
DECREF(m);
|
||||
return m; /* Yes, it still exists, in sys.modules... */
|
||||
}
|
||||
|
||||
|
||||
/* Convenience functions to set a type error exception and return 0 */
|
||||
|
||||
int
|
||||
err_badarg()
|
||||
{
|
||||
err_setstr(TypeError, "illegal argument type for built-in function");
|
||||
return 0;
|
||||
}
|
||||
|
||||
object *
|
||||
err_nomem()
|
||||
{
|
||||
err_setstr(MemoryError, "in built-in function");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Argument list handling tools.
|
||||
All return 1 for success, or call err_set*() and return 0 for failure */
|
||||
|
||||
int
|
||||
getnoarg(v)
|
||||
object *v;
|
||||
{
|
||||
if (v != NULL) {
|
||||
return err_badarg();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
getintarg(v, a)
|
||||
object *v;
|
||||
int *a;
|
||||
{
|
||||
if (v == NULL || !is_intobject(v)) {
|
||||
return err_badarg();
|
||||
}
|
||||
*a = getintvalue(v);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
getintintarg(v, a, b)
|
||||
object *v;
|
||||
int *a;
|
||||
int *b;
|
||||
{
|
||||
if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2) {
|
||||
return err_badarg();
|
||||
}
|
||||
return getintarg(gettupleitem(v, 0), a) &&
|
||||
getintarg(gettupleitem(v, 1), b);
|
||||
}
|
||||
|
||||
int
|
||||
getlongarg(v, a)
|
||||
object *v;
|
||||
long *a;
|
||||
{
|
||||
if (v == NULL || !is_intobject(v)) {
|
||||
return err_badarg();
|
||||
}
|
||||
*a = getintvalue(v);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
getlonglongargs(v, a, b)
|
||||
object *v;
|
||||
long *a, *b;
|
||||
{
|
||||
if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2) {
|
||||
return err_badarg();
|
||||
}
|
||||
return getlongarg(gettupleitem(v, 0), a) &&
|
||||
getlongarg(gettupleitem(v, 1), b);
|
||||
}
|
||||
|
||||
int
|
||||
getlonglongobjectargs(v, a, b, c)
|
||||
object *v;
|
||||
long *a, *b;
|
||||
object **c;
|
||||
{
|
||||
if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 3) {
|
||||
return err_badarg();
|
||||
}
|
||||
if (getlongarg(gettupleitem(v, 0), a) &&
|
||||
getlongarg(gettupleitem(v, 1), b)) {
|
||||
*c = gettupleitem(v, 2);
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return err_badarg();
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
getstrarg(v, a)
|
||||
object *v;
|
||||
object **a;
|
||||
{
|
||||
if (v == NULL || !is_stringobject(v)) {
|
||||
return err_badarg();
|
||||
}
|
||||
*a = v;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
getstrstrarg(v, a, b)
|
||||
object *v;
|
||||
object **a;
|
||||
object **b;
|
||||
{
|
||||
if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2) {
|
||||
return err_badarg();
|
||||
}
|
||||
return getstrarg(gettupleitem(v, 0), a) &&
|
||||
getstrarg(gettupleitem(v, 1), b);
|
||||
}
|
||||
|
||||
int
|
||||
getstrstrintarg(v, a, b, c)
|
||||
object *v;
|
||||
object **a;
|
||||
object **b;
|
||||
int *c;
|
||||
{
|
||||
if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 3) {
|
||||
return err_badarg();
|
||||
}
|
||||
return getstrarg(gettupleitem(v, 0), a) &&
|
||||
getstrarg(gettupleitem(v, 1), b) &&
|
||||
getintarg(gettupleitem(v, 2), c);
|
||||
}
|
||||
|
||||
int
|
||||
getstrintarg(v, a, b)
|
||||
object *v;
|
||||
object **a;
|
||||
int *b;
|
||||
{
|
||||
if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2) {
|
||||
return err_badarg();
|
||||
}
|
||||
return getstrarg(gettupleitem(v, 0), a) &&
|
||||
getintarg(gettupleitem(v, 1), b);
|
||||
}
|
||||
|
||||
int
|
||||
getintstrarg(v, a, b)
|
||||
object *v;
|
||||
int *a;
|
||||
object **b;
|
||||
{
|
||||
if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2) {
|
||||
return err_badarg();
|
||||
}
|
||||
return getintarg(gettupleitem(v, 0), a) &&
|
||||
getstrarg(gettupleitem(v, 1), b);
|
||||
}
|
||||
|
||||
int
|
||||
getpointarg(v, a)
|
||||
object *v;
|
||||
int *a; /* [2] */
|
||||
{
|
||||
return getintintarg(v, a, a+1);
|
||||
}
|
||||
|
||||
int
|
||||
get3pointarg(v, a)
|
||||
object *v;
|
||||
int *a; /* [6] */
|
||||
{
|
||||
if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 3) {
|
||||
return err_badarg();
|
||||
}
|
||||
return getpointarg(gettupleitem(v, 0), a) &&
|
||||
getpointarg(gettupleitem(v, 1), a+2) &&
|
||||
getpointarg(gettupleitem(v, 2), a+4);
|
||||
}
|
||||
|
||||
int
|
||||
getrectarg(v, a)
|
||||
object *v;
|
||||
int *a; /* [2+2] */
|
||||
{
|
||||
if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2) {
|
||||
return err_badarg();
|
||||
}
|
||||
return getpointarg(gettupleitem(v, 0), a) &&
|
||||
getpointarg(gettupleitem(v, 1), a+2);
|
||||
}
|
||||
|
||||
int
|
||||
getrectintarg(v, a)
|
||||
object *v;
|
||||
int *a; /* [4+1] */
|
||||
{
|
||||
if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2) {
|
||||
return err_badarg();
|
||||
}
|
||||
return getrectarg(gettupleitem(v, 0), a) &&
|
||||
getintarg(gettupleitem(v, 1), a+4);
|
||||
}
|
||||
|
||||
int
|
||||
getpointintarg(v, a)
|
||||
object *v;
|
||||
int *a; /* [2+1] */
|
||||
{
|
||||
if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2) {
|
||||
return err_badarg();
|
||||
}
|
||||
return getpointarg(gettupleitem(v, 0), a) &&
|
||||
getintarg(gettupleitem(v, 1), a+2);
|
||||
}
|
||||
|
||||
int
|
||||
getpointstrarg(v, a, b)
|
||||
object *v;
|
||||
int *a; /* [2] */
|
||||
object **b;
|
||||
{
|
||||
if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2) {
|
||||
return err_badarg();
|
||||
}
|
||||
return getpointarg(gettupleitem(v, 0), a) &&
|
||||
getstrarg(gettupleitem(v, 1), b);
|
||||
}
|
||||
|
||||
int
|
||||
getstrintintarg(v, a, b, c)
|
||||
object *v;
|
||||
object *a;
|
||||
int *b, *c;
|
||||
{
|
||||
if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 3) {
|
||||
return err_badarg();
|
||||
}
|
||||
return getstrarg(gettupleitem(v, 0), a) &&
|
||||
getintarg(gettupleitem(v, 1), b) &&
|
||||
getintarg(gettupleitem(v, 2), c);
|
||||
}
|
||||
|
||||
int
|
||||
getrectpointarg(v, a)
|
||||
object *v;
|
||||
int *a; /* [4+2] */
|
||||
{
|
||||
if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2) {
|
||||
return err_badarg();
|
||||
}
|
||||
return getrectarg(gettupleitem(v, 0), a) &&
|
||||
getpointarg(gettupleitem(v, 1), a+4);
|
||||
}
|
||||
|
||||
int
|
||||
getlongtuplearg(args, a, n)
|
||||
object *args;
|
||||
long *a; /* [n] */
|
||||
int n;
|
||||
{
|
||||
int i;
|
||||
if (!is_tupleobject(args) || gettuplesize(args) != n) {
|
||||
return err_badarg();
|
||||
}
|
||||
for (i = 0; i < n; i++) {
|
||||
object *v = gettupleitem(args, i);
|
||||
if (!is_intobject(v)) {
|
||||
return err_badarg();
|
||||
}
|
||||
a[i] = getintvalue(v);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
getshorttuplearg(args, a, n)
|
||||
object *args;
|
||||
short *a; /* [n] */
|
||||
int n;
|
||||
{
|
||||
int i;
|
||||
if (!is_tupleobject(args) || gettuplesize(args) != n) {
|
||||
return err_badarg();
|
||||
}
|
||||
for (i = 0; i < n; i++) {
|
||||
object *v = gettupleitem(args, i);
|
||||
if (!is_intobject(v)) {
|
||||
return err_badarg();
|
||||
}
|
||||
a[i] = getintvalue(v);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
getlonglistarg(args, a, n)
|
||||
object *args;
|
||||
long *a; /* [n] */
|
||||
int n;
|
||||
{
|
||||
int i;
|
||||
if (!is_listobject(args) || getlistsize(args) != n) {
|
||||
return err_badarg();
|
||||
}
|
||||
for (i = 0; i < n; i++) {
|
||||
object *v = getlistitem(args, i);
|
||||
if (!is_intobject(v)) {
|
||||
return err_badarg();
|
||||
}
|
||||
a[i] = getintvalue(v);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
getshortlistarg(args, a, n)
|
||||
object *args;
|
||||
short *a; /* [n] */
|
||||
int n;
|
||||
{
|
||||
int i;
|
||||
if (!is_listobject(args) || getlistsize(args) != n) {
|
||||
return err_badarg();
|
||||
}
|
||||
for (i = 0; i < n; i++) {
|
||||
object *v = getlistitem(args, i);
|
||||
if (!is_intobject(v)) {
|
||||
return err_badarg();
|
||||
}
|
||||
a[i] = getintvalue(v);
|
||||
}
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,297 @@
|
|||
/* Python interpreter main program */
|
||||
|
||||
/* XXX This is still a mess */
|
||||
|
||||
#ifdef THINK_C
|
||||
#define USE_STDWIN
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include "string.h"
|
||||
|
||||
#ifdef USE_STDWIN
|
||||
#include "stdwin.h"
|
||||
int use_stdwin;
|
||||
#endif
|
||||
|
||||
extern char *getenv();
|
||||
|
||||
#include "PROTO.h"
|
||||
#include "grammar.h"
|
||||
#include "node.h"
|
||||
#include "parsetok.h"
|
||||
#include "graminit.h"
|
||||
#include "errcode.h"
|
||||
#include "object.h"
|
||||
#include "stringobject.h"
|
||||
#include "sysmodule.h"
|
||||
|
||||
extern grammar gram; /* From graminit.c */
|
||||
|
||||
#ifndef PYTHONPATH
|
||||
|
||||
#ifdef THINK_C
|
||||
|
||||
#define PYTHONPATH ": :mod"
|
||||
|
||||
#else /* !THINK_C */
|
||||
|
||||
#ifdef AMOEBA
|
||||
#define PYTHONPATH ".:/profile/module/python"
|
||||
#else /* !AMOEBA */
|
||||
#define PYTHONPATH ".:/usr/local/lib/python"
|
||||
#endif /* !AMOEBA */
|
||||
|
||||
#endif /* !THINK_C */
|
||||
|
||||
#endif /* !PYTHONPATH */
|
||||
|
||||
int debugging;
|
||||
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
char *path;
|
||||
char *filename = NULL;
|
||||
FILE *fp = stdin;
|
||||
int ret;
|
||||
|
||||
#ifdef USE_STDWIN
|
||||
#ifdef THINK_C
|
||||
wsetstdio(1);
|
||||
#else THINK_C
|
||||
/* Must use "python -s" now to get stdwin support */
|
||||
if (argc > 1 && strcmp(argv[1], "-s") == 0)
|
||||
argv[1] = argv[0],
|
||||
argc--, argv++,
|
||||
#endif /* !THINK_C */
|
||||
use_stdwin = 1;
|
||||
if (use_stdwin)
|
||||
winitargs(&argc, &argv);
|
||||
#endif /* USE_STDWIN */
|
||||
|
||||
#ifdef THINK_C_not_today
|
||||
printf("argc = %d, argv[0] = '%s'\n", argc, argv[0]);
|
||||
if (argc <= 1)
|
||||
askargs(&argc, &argv);
|
||||
#endif
|
||||
|
||||
initintr(); /* For intrcheck() */
|
||||
|
||||
if (argc > 1 && strcmp(argv[1], "-") != 0)
|
||||
filename = argv[1];
|
||||
|
||||
if (filename != NULL) {
|
||||
if ((fp = fopen(filename, "r")) == NULL) {
|
||||
fprintf(stderr, "python: can't open file '%s'\n",
|
||||
filename);
|
||||
exit(2);
|
||||
}
|
||||
}
|
||||
|
||||
/* XXX what is the ideal initialization order? */
|
||||
|
||||
initsys(argc-1, argv+1);
|
||||
inittime();
|
||||
initmath();
|
||||
|
||||
#ifndef THINK_C
|
||||
path = getenv("PYTHONPATH");
|
||||
if (path == NULL)
|
||||
#endif
|
||||
path = PYTHONPATH;
|
||||
setpythonpath(path);
|
||||
|
||||
initrun();
|
||||
|
||||
#ifdef USE_POSIX
|
||||
initposix();
|
||||
#endif
|
||||
|
||||
#ifdef THINK_C
|
||||
initmac();
|
||||
#endif
|
||||
|
||||
#ifdef USE_AUDIO
|
||||
initaudio();
|
||||
#endif
|
||||
|
||||
#ifdef USE_AMOEBA
|
||||
initamoeba();
|
||||
#endif
|
||||
|
||||
#ifdef USE_STDWIN
|
||||
if (use_stdwin)
|
||||
initstdwin();
|
||||
#endif
|
||||
|
||||
#ifdef USE_GL
|
||||
initgl();
|
||||
#endif
|
||||
|
||||
#ifdef USE_PANEL
|
||||
initpanel();
|
||||
#endif
|
||||
|
||||
if (!isatty(fileno(fp))) {
|
||||
ret = runfile(fp, file_input, (char *)NULL, (char *)NULL);
|
||||
}
|
||||
else {
|
||||
sysset("ps1", newstringobject(">>> "));
|
||||
sysset("ps2", newstringobject("... "));
|
||||
for (;;) {
|
||||
object *v = sysget("ps1"), *w = sysget("ps2");
|
||||
char *ps1 = NULL, *ps2 = NULL;
|
||||
if (v != NULL && is_stringobject(v)) {
|
||||
INCREF(v);
|
||||
ps1 = getstringvalue(v);
|
||||
}
|
||||
else
|
||||
v = NULL;
|
||||
if (w != NULL && is_stringobject(w)) {
|
||||
INCREF(w);
|
||||
ps2 = getstringvalue(w);
|
||||
}
|
||||
else
|
||||
w = NULL;
|
||||
ret = runfile(fp, single_input, ps1, ps2);
|
||||
if (v != NULL)
|
||||
DECREF(v);
|
||||
if (w != NULL)
|
||||
DECREF(w);
|
||||
if (ret == E_EOF || ret == E_NOMEM)
|
||||
break;
|
||||
}
|
||||
}
|
||||
goaway(ret == E_DONE || ret == E_EOF ? 0 : 1);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
goaway(sts)
|
||||
int sts;
|
||||
{
|
||||
closerun();
|
||||
#ifdef USE_STDWIN
|
||||
if (use_stdwin)
|
||||
wdone();
|
||||
#endif
|
||||
#ifdef THINK_C
|
||||
#ifndef TRACE_REFS
|
||||
/* Avoid 'click mouse to continue' in Lightspeed C */
|
||||
if (sts == 0)
|
||||
Click_On(0);
|
||||
#endif
|
||||
#endif
|
||||
exit(sts);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
/* Parse input from a file and execute it */
|
||||
|
||||
static int
|
||||
runfile(fp, start, ps1, ps2)
|
||||
FILE *fp;
|
||||
int start;
|
||||
char *ps1, *ps2;
|
||||
{
|
||||
node *n;
|
||||
int ret;
|
||||
ret = parsefile(fp, &gram, start, ps1, ps2, &n);
|
||||
if (ret != E_DONE)
|
||||
return ret;
|
||||
return execute(n) == 0 ? E_DONE : E_ERROR;
|
||||
}
|
||||
|
||||
#ifdef THINK_C
|
||||
|
||||
/* Ask a yes/no question */
|
||||
|
||||
int
|
||||
askyesno(prompt)
|
||||
char *prompt;
|
||||
{
|
||||
char buf[256];
|
||||
|
||||
printf("%s [ny] ", prompt);
|
||||
if (fgets(buf, sizeof buf, stdin) == NULL)
|
||||
return 0;
|
||||
return buf[0] == 'y' || buf[0] == 'Y';
|
||||
}
|
||||
|
||||
/* Check for file descriptor connected to interactive device.
|
||||
Pretend that stdin is always interactive, other files never. */
|
||||
|
||||
int
|
||||
isatty(fd)
|
||||
int fd;
|
||||
{
|
||||
return fd == fileno(stdin);
|
||||
}
|
||||
|
||||
/* Kludge to get arguments on the Mac */
|
||||
|
||||
#define MAXARGS 20
|
||||
|
||||
static char *
|
||||
nextarg(pnext)
|
||||
char **pnext;
|
||||
{
|
||||
char *ret;
|
||||
char *p = *pnext;
|
||||
while (isspace(*p))
|
||||
p++;
|
||||
if (*p == '\0')
|
||||
return NULL;
|
||||
ret = p;
|
||||
while (!isspace(*p))
|
||||
p++;
|
||||
if (*p != '\0')
|
||||
*p++ = '\0';
|
||||
*pnext = p;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static
|
||||
askargs(pargc, pargv)
|
||||
int *pargc;
|
||||
char ***pargv; /* sic */
|
||||
{
|
||||
static char buf[256];
|
||||
static char *argv[MAXARGS];
|
||||
int argc;
|
||||
char *p, *next;
|
||||
fprintf(stderr, "Args: ");
|
||||
if (fgets(buf, sizeof buf, stdin) == NULL)
|
||||
return;
|
||||
next = buf;
|
||||
if ((p = nextarg(&next)) == NULL)
|
||||
return;
|
||||
if (*pargc > 0)
|
||||
argv[0] = (*pargv)[0];
|
||||
else
|
||||
argv[0] = "PYTHON";
|
||||
argc = 1;
|
||||
argv[argc++] = p;
|
||||
while (argc+1 < MAXARGS && (p = nextarg(&next)) != NULL)
|
||||
argv[argc++] = p;
|
||||
argv[argc] = NULL;
|
||||
*pargc = argc;
|
||||
*pargv = argv;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* WISH LIST
|
||||
|
||||
- improved per-module error handling; different use of errno
|
||||
- possible new types:
|
||||
- iterator (for range, keys, ...)
|
||||
- improve interpreter error handling, e.g., true tracebacks
|
||||
- release parse trees when no longer needed (make them objects?)
|
||||
- faster parser (for long modules)
|
||||
- save precompiled modules on file?
|
||||
- fork threads, locking
|
||||
- allow syntax extensions
|
||||
*/
|
|
@ -0,0 +1,18 @@
|
|||
/* PD implementation of strerror() for BSD derivatives that don't have it.
|
||||
Author: Guido van Rossum, CWI Amsterdam, Oct. 1990, <guido@cwi.nl>. */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
extern int sys_nerr;
|
||||
extern char *sys_errlist[];
|
||||
|
||||
char *
|
||||
strerror(err)
|
||||
int err;
|
||||
{
|
||||
static char buf[20];
|
||||
if (err >= 0 && err < sys_nerr)
|
||||
return sys_errlist[err];
|
||||
sprintf(buf, "Unknown errno %d", err);
|
||||
return buf;
|
||||
}
|
|
@ -0,0 +1,156 @@
|
|||
/* System module */
|
||||
|
||||
/*
|
||||
Various bits of information used by the interpreter are collected in
|
||||
module 'sys'.
|
||||
Data members:
|
||||
- stdin, stdout, stderr: standard file objects
|
||||
- ps1, ps2: primary and secondary prompts (strings)
|
||||
- path: module search path (list of strings)
|
||||
- modules: the table of modules (dictionary)
|
||||
Function members:
|
||||
- exit(sts): call exit()
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "PROTO.h"
|
||||
#include "object.h"
|
||||
#include "stringobject.h"
|
||||
#include "listobject.h"
|
||||
#include "dictobject.h"
|
||||
#include "fileobject.h"
|
||||
#include "moduleobject.h"
|
||||
#include "sysmodule.h"
|
||||
#include "node.h" /* For context.h */
|
||||
#include "context.h" /* For import.h */
|
||||
#include "import.h"
|
||||
#include "methodobject.h"
|
||||
#include "modsupport.h"
|
||||
#include "errors.h"
|
||||
|
||||
static object *sysdict;
|
||||
|
||||
object *
|
||||
sysget(name)
|
||||
char *name;
|
||||
{
|
||||
return dictlookup(sysdict, name);
|
||||
}
|
||||
|
||||
FILE *
|
||||
sysgetfile(name, def)
|
||||
char *name;
|
||||
FILE *def;
|
||||
{
|
||||
FILE *fp = NULL;
|
||||
object *v = sysget(name);
|
||||
if (v != NULL)
|
||||
fp = getfilefile(v);
|
||||
if (fp == NULL)
|
||||
fp = def;
|
||||
return fp;
|
||||
}
|
||||
|
||||
int
|
||||
sysset(name, v)
|
||||
char *name;
|
||||
object *v;
|
||||
{
|
||||
if (v == NULL)
|
||||
return dictremove(sysdict, name);
|
||||
else
|
||||
return dictinsert(sysdict, name, v);
|
||||
}
|
||||
|
||||
static object *
|
||||
makeargv(argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
int i;
|
||||
object *av, *v;
|
||||
if (argc < 0 || argv == NULL)
|
||||
argc = 0;
|
||||
av = newlistobject(argc);
|
||||
if (av != NULL) {
|
||||
for (i = 0; i < argc; i++) {
|
||||
v = newstringobject(argv[i]);
|
||||
if (v == NULL) {
|
||||
DECREF(av);
|
||||
av = NULL;
|
||||
break;
|
||||
}
|
||||
setlistitem(av, i, v);
|
||||
}
|
||||
}
|
||||
if (av == NULL)
|
||||
fatal("no mem for sys.argv");
|
||||
return av;
|
||||
}
|
||||
|
||||
/* sys.exit method */
|
||||
|
||||
static object *
|
||||
sys_exit(self, args)
|
||||
object *self;
|
||||
object *args;
|
||||
{
|
||||
int sts;
|
||||
if (!getintarg(args, &sts))
|
||||
return NULL;
|
||||
goaway(sts);
|
||||
exit(sts); /* Just in case */
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
static object *sysin, *sysout, *syserr;
|
||||
|
||||
void
|
||||
initsys(argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
object *v;
|
||||
object *exit;
|
||||
if ((sysdict = newdictobject()) == NULL)
|
||||
fatal("can't create sys dict");
|
||||
/* NB keep an extra ref to the std files to avoid closing them
|
||||
when the user deletes them */
|
||||
sysin = newopenfileobject(stdin, "<stdin>", "r");
|
||||
sysout = newopenfileobject(stdout, "<stdout>", "w");
|
||||
syserr = newopenfileobject(stderr, "<stderr>", "w");
|
||||
v = makeargv(argc, argv);
|
||||
exit = newmethodobject("exit", sys_exit, (object *)NULL);
|
||||
if (err_occurred())
|
||||
fatal("can't create sys.* objects");
|
||||
dictinsert(sysdict, "stdin", sysin);
|
||||
dictinsert(sysdict, "stdout", sysout);
|
||||
dictinsert(sysdict, "stderr", syserr);
|
||||
dictinsert(sysdict, "argv", v);
|
||||
dictinsert(sysdict, "exit", exit);
|
||||
if (err_occurred())
|
||||
fatal("can't insert sys.* objects in sys dict");
|
||||
DECREF(v);
|
||||
/* The other symbols are added elsewhere */
|
||||
|
||||
/* Only now can we initialize the import stuff, after which
|
||||
we can turn ourselves into a module */
|
||||
initimport();
|
||||
if ((v = new_module("sys")) == NULL)
|
||||
fatal("can't create sys module");
|
||||
if (setmoduledict(v, sysdict) != 0)
|
||||
fatal("can't assign sys dict to sys module");
|
||||
}
|
||||
|
||||
void
|
||||
closesys()
|
||||
{
|
||||
object *mtab;
|
||||
mtab = sysget("modules");
|
||||
if (mtab != NULL && is_dictobject(mtab))
|
||||
dictremove(mtab, "sys"); /* Get rid of recursion */
|
||||
else
|
||||
fprintf(stderr, "[module sys not found]\n");
|
||||
DECREF(sysdict);
|
||||
}
|
Loading…
Reference in New Issue