guido@cwi.nl (Guido van Rossum) (02/20/91)
: This is a shell archive. : Extract with 'sh this_file'. : : Extract part 01 first since it makes all directories echo 'Start of pack.out, part 11 out of 21:' if test -s 'lib/Buttons.py' then echo '*** I will not over-write existing file lib/Buttons.py' else echo 'x - lib/Buttons.py' sed 's/^X//' > 'lib/Buttons.py' << 'EOF' X# Module 'Buttons' X X X# Import module 'rect' renamed as '_rect' to avoid exporting it on X# 'from Buttons import *' X# Ximport rect X_rect = rect Xdel rect X X X# Field indices in mouse event detail X# X_HV = 0 X_CLICKS = 1 X_BUTTON = 2 X_MASK = 3 X X X# LabelAppearance provides defaults for all appearance methods. X# selected state not visible X# disabled --> crossed out X# hilited --> inverted X# Xclass LabelAppearance(): X # X # Initialization X # X def init_appearance(self): X self.bounds = _rect.empty X self.enabled = 1 X self.hilited = 0 X self.selected = 0 X self.text = '' X # X # Size enquiry X # X def minsize(self, m): X try: X self.text = self.text X except NameError: X self.text = '' X return m.textwidth(self.text) + 6, m.lineheight() + 6 X # X def getbounds(self): X return self.bounds X # X # Changing the parameters X # X def settext(self, text): X self.text = text X if self.bounds <> _rect.empty: X self.recalctextpos() X self.redraw() X # X def setbounds(self, bounds): X if self.bounds <> _rect.empty: X self.parent.change(self.bounds) X self.bounds = bounds X if self.bounds <> _rect.empty: X self.recalc() X self.parent.change(bounds) X # X # Changing the state bits X # X def enable(self, flag): X if flag <> self.enabled: X self.enabled = flag X if self.bounds <> _rect.empty: X self.flipenable(self.parent.begindrawing()) X # X def hilite(self, flag): X if flag <> self.hilited: X self.hilited = flag X if self.bounds <> _rect.empty: X self.fliphilite(self.parent.begindrawing()) X # X def select(self, flag): X if flag <> self.selected: X self.selected = flag X if self.bounds <> _rect.empty: X self.redraw() X # X # Recalculate the box bounds and text position. X # This can be overridden by buttons that draw different boxes X # or want their text in a different position. X # X def recalc(self): X if self.bounds <> _rect.empty: X self.recalcbounds() X self.recalctextpos() X # X def recalcbounds(self): X self.hilitebounds = _rect.inset(self.bounds, (3, 3)) X self.crossbounds = self.bounds X # X def recalctextpos(self): X (left, top), (right, bottom) = self.bounds X m = self.parent.beginmeasuring() X h = (left + right - m.textwidth(self.text)) / 2 X v = (top + bottom - m.lineheight()) / 2 X self.textpos = h, v X # X # Generic drawing interface. X # Do not override redraw() or draw() methods; override drawit() c.s. X # X def redraw(self): X if self.bounds <> _rect.empty: X self.draw(self.parent.begindrawing(), self.bounds) X # X def draw(self, (d, area)): X area = _rect.intersect(area, self.bounds) X if area = _rect.empty: X return X d.cliprect(area) X d.erase(self.bounds) X self.drawit(d) X d.noclip() X # X # The drawit() method is fairly generic but may be overridden. X # X def drawit(self, d): X self.drawpict(d) X if self.text: X d.text(self.textpos, self.text) X if not self.enabled: X self.flipenable(d) X if self.hilited: X self.fliphilite(d) X # X # Default drawing detail functions. X # Overriding these is normally sufficient to get different X # appearances. X # X def drawpict(self, d): X pass X # X def flipenable(self, d): X _xorcross(d, self.crossbounds) X # X def fliphilite(self, d): X d.invert(self.hilitebounds) X X X# ButtonAppearance displays a centered string in a box. X# selected --> bold border X# disabled --> crossed out X# hilited --> inverted X# Xclass ButtonAppearance() = LabelAppearance(): X # X def drawpict(self, d): X d.box(_rect.inset(self.bounds, (1, 1))) X if self.selected: X # Make a thicker box X d.box(self.bounds) X d.box(_rect.inset(self.bounds, (2, 2))) X d.box(_rect.inset(self.bounds, (3, 3))) X # X X X# CheckAppearance displays a small square box and a left-justified string. X# selected --> a cross appears in the box X# disabled --> whole button crossed out X# hilited --> box is inverted X# Xclass CheckAppearance() = LabelAppearance(): X # X def minsize(self, m): X width, height = m.textwidth(self.text) + 6, m.lineheight() + 6 X return width + height + m.textwidth(' '), height X # X def drawpict(self, d): X d.box(self.boxbounds) X if self.selected: _xorcross(d, self.boxbounds) X # X def recalcbounds(self): X LabelAppearance.recalcbounds(self) X (left, top), (right, bottom) = self.bounds X self.size = bottom - top - 4 X self.boxbounds = (left+2, top+2), (left+2+self.size, bottom-2) X self.hilitebounds = self.boxbounds X # X def recalctextpos(self): X m = self.parent.beginmeasuring() X (left, top), (right, bottom) = self.boxbounds X h = right + m.textwidth(' ') X v = top + (self.size - m.lineheight()) / 2 X self.textpos = h, v X # X X X# RadioAppearance displays a round indicator and a left-justified string. X# selected --> a dot appears in the indicator X# disabled --> whole button crossed out X# hilited --> indicator is inverted X# Xclass RadioAppearance() = CheckAppearance(): X # X def drawpict(self, d): X (left, top), (right, bottom) = self.boxbounds X radius = self.size / 2 X h, v = left + radius, top + radius X d.circle((h, v), radius) X if self.selected: X some = radius/3 X d.paint((h-some, v-some), (h+some, v+some)) X # X X X# NoReactivity ignores mouse events. X# Xclass NoReactivity(): X def init_reactivity(self): pass X X X# BaseReactivity defines hooks and asks for mouse events, X# but provides only dummy mouse event handlers. X# The trigger methods call the corresponding hooks set by the user. X# Hooks (and triggers) mean the following: X# down_hook called on some mouse-down events X# move_hook called on some mouse-move events X# up_hook called on mouse-up events X# on_hook called for buttons with on/off state, when it goes on X# hook called when a button 'fires' or a radiobutton goes on X# There are usually extra conditions, e.g., hooks are only called X# when the button is enabled, or active, or selected (on). X# Xclass BaseReactivity(): X # X def init_reactivity(self): X self.down_hook = self.move_hook = self.up_hook = \ X self.on_hook = self.off_hook = \ X self.hook = self.active = 0 X self.parent.need_mouse(self) X # X def mousetest(self, hv): X return _rect.pointinrect(hv, self.bounds) X # X def mouse_down(self, detail): X pass X # X def mouse_move(self, detail): X pass X # X def mouse_up(self, detail): X pass X # X def down_trigger(self): X if self.down_hook: self.down_hook(self) X # X def move_trigger(self): X if self.move_hook: self.move_hook(self) X # X def up_trigger(self): X if self.up_hook: self.up_hook(self) X # X def on_trigger(self): X if self.on_hook: self.on_hook(self) X # X def off_trigger(self): X if self.off_hook: self.off_hook(self) X # X def trigger(self): X if self.hook: self.hook(self) X X X# ToggleReactivity acts like a simple pushbutton. X# It toggles its hilite state on mouse down events. X# Xclass ToggleReactivity() = BaseReactivity(): X # X def mouse_down(self, detail): X if self.enabled and self.mousetest(detail[_HV]): X self.active = 1 X self.hilite(not self.hilited) X self.down_trigger() X # X def mouse_move(self, detail): X if self.active: X self.move_trigger() X # X def mouse_up(self, detail): X if self.active: X self.up_trigger() X self.active = 0 X # X def down_trigger(self): X if self.hilited: X self.on_trigger() X else: X self.off_trigger() X self.trigger() X # X X X# TriggerReactivity acts like a fancy pushbutton. X# It hilites itself while the mouse is down within its bounds. X# Xclass TriggerReactivity() = BaseReactivity(): X # X def mouse_down(self, detail): X if self.enabled and self.mousetest(detail[_HV]): X self.active = 1 X self.hilite(1) X self.down_trigger() X # X def mouse_move(self, detail): X if self.active: X self.hilite(self.mousetest(detail[_HV])) X if self.hilited: X self.move_trigger() X # X def mouse_up(self, detail): X if self.active: X self.hilite(self.mousetest(detail[_HV])) X if self.hilited: X self.up_trigger() X self.trigger() X self.active = 0 X self.hilite(0) X # X X X# CheckReactivity handles mouse events like TriggerReactivity, X# It overrides the up_trigger method to flip its selected state. X# Xclass CheckReactivity() = TriggerReactivity(): X # X def up_trigger(self): X self.select(not self.selected) X if self.selected: X self.on_trigger() X else: X self.off_trigger() X self.trigger() X X X# RadioReactivity turns itself on and the other buttons in its group X# off when its up_trigger method is called. X# Xclass RadioReactivity() = TriggerReactivity(): X # X def init_reactivity(self): X TriggerReactivity.init_reactivity(self) X self.group = [] X # X def up_trigger(self): X for b in self.group: X if b <> self: X if b.selected: X b.select(0) X b.off_trigger() X self.select(1) X self.on_trigger() X self.trigger() X X X# Auxiliary class for 'define' method. X# Call the initializers in the right order. X# Xclass Define(): X # X def define(self, parent): X self.parent = parent X parent.addchild(self) X self.init_appearance() X self.init_reactivity() X return self X # X def destroy(self): X self.parent = 0 X # X def definetext(self, (parent, text)): X self = self.define(parent) X self.settext(text) X return self X X X# Subroutine to cross out a rectangle. X# Xdef _xorcross(d, bounds): X ((left, top), (right, bottom)) = bounds X # This is s bit funny to make it look better X left = left + 2 X right = right - 2 X top = top + 2 X bottom = bottom - 3 X d.xorline(((left, top), (right, bottom))) X d.xorline((left, bottom), (right, top)) X X X# Ready-made button classes. X# Xclass Label() = NoReactivity(), LabelAppearance(), Define(): pass Xclass PushButton() = TriggerReactivity(), ButtonAppearance(), Define(): pass Xclass CheckButton() = CheckReactivity(), CheckAppearance(), Define(): pass Xclass RadioButton() = RadioReactivity(), RadioAppearance(), Define(): pass Xclass ToggleButton() = ToggleReactivity(), ButtonAppearance(), Define(): pass EOF fi if test -s 'lib/TclUtil.py' then echo '*** I will not over-write existing file lib/TclUtil.py' else echo 'x - lib/TclUtil.py' sed 's/^X//' > 'lib/TclUtil.py' << 'EOF' X# Utilities used by 'Tcl' emulator. X X X# Many functions in this file parse specific constructs from strings. X# In order to limit the number of slice operations (the strings can X# be very large), they always receive indices into the string that X# indicate the slice of the string that should be considered. X# The return value is in general another index, pointing to the first X# character in the string beyond the recognized construct. X# Errors are reported as exceptions (TclSyntaxError, TclMatchingError). X# A few functions have multiple return values. X X X# For efficiency, the Tcl "tokenizing" routines used pre-compiled X# regular expressions. This is less readable but should be much faster X# than scanning the string a character at a time. X# X# The global variables X# containing the compiled regexp's are named _foo_prog where foo is X# an indication of the function that uses them. X# X# The patterns always X# have the form <something>* so they always match at the start of the X# search buffer---maybe with the empty string. This makes it possible X# to use the expression "_foo_prog.exec(str, i)[0][1]" to find the first X# character beyond the matched string. Note that this may be beyond the X# end variable -- where this matters, "min(i, end)" is used. X X# Constructs that cannot X# be recognized by a finite automaton (like matching braces) are scanned X# by a hybrid technique where the regular expression excludes the X# braces. X# X# Many regular expressions contain an expression that matches X# a Tcl backslash sequence as a subpart: X# \\\\C?M?(.|\n) X# X# This is a bit hard to X# read because the backslash contained in it must be doubled twice: X# once to get past Python's backslash mechanism, once to get past that X# of regular expressions. It uses (.|\n) to match absolutely X# *every character*, becase the MULTILINE regular expression package does X# not accept '\n' as a match for '.'. X# X# There is also a simplification in the pattern for backslashes: X# *any* single character following a backslash is escaped, X# so hex and octal X# excapes are not scanned fully. The forms \Cx, \Mx and \CMx are X# scanned correctly, as these may hide a special character. X# (This does not invalidate the recognition of strings, although the X# match is effectuated in a different way than by the Backslash function.) X Ximport regexp X X X# Exceptions raised for various error conditions. X XTclAssertError = 'Tcl assert error' XTclSyntaxError = 'Tcl syntax error' XTclRuntimeError = 'Tcl runtime error' XTclMatchingError = 'Tcl matching error' X X X# Find a variable name. X# A variable name is either a (possiblly empty) sequence of letters, X# digits and underscores, or anything enclosed in matching braces. X# Return the index past the end of the name. X X_varname_prog = regexp.compile('[a-zA-Z0-9_]*') X Xdef FindVarName(str, i, end): X if i < end and str[i] = '{': return BalanceBraces(str, i, end) X i = _varname_prog.exec(str, i)[0][1] X return min(i, end) X X X# Split a list into its elements. X# Return a list of elements (strings). X Xdef SplitList(str): X i, end = 0, len(str) X list = [] X while 1: X i = SkipSpaces(str, i, end) X if i >= end: break X j = i X i = FindNextElement(str, i, end) X if str[j] = '{' and str[i-1] = '}': X element = str[j+1:i-1] X else: X element = Collapse(str[j:i]) X list.append(element) X return list X X X# Find the next element from a list. X X_element_prog = regexp.compile('([^ \t\n\\]+|\\\\C?M?(.|\n))*') X Xdef FindNextElement(str, i, end): X if i < end and str[i] = '{': X i = BalanceBraces(str, i, end) X if i < end and str[i] not in ' \t\n': X raise TclSyntaxError, 'Garbage after } in list' X return i X i = _element_prog.exec(str, i)[0][1] X return min(i, end) X X X# Copy a string, expanding all backslash sequences. X X_collapse_prog = regexp.compile('(\n|[^\\]+)*') X Xdef Collapse(str): X if '\\' not in str: return str X i, end = 0, len(str) X result = '' X while i < end: X j = _collapse_prog.exec(str, i)[0][1] X j = min(j, end) X result = result + str[i:j] X if j >= end: break X c = str[j] X if c <> '\\': raise TclAssertError, 'collapse error' X x, i = Backslash(str, j, end) X result = result + x X return result X X X# Find the next full command. X# Return a list of begin, end indices of words in the string, X# and an index pointing just after the terminating newline or X# semicolon. X# Initial spaces are skipped. X# If the command begins with '#', it is considered empty and X# characters until '\n' are skipped. X X_eol_prog = regexp.compile('[^\n]*') X Xdef FindNextCommand(str, i, end, bracketed): X i = SkipSpaces(str, i, end) X if i >= end: return [], end X if str[i] = '#': X i = _eol_prog.exec(str, i) X i = min(i, end) X if i < end and str[i] = '\n': i = i+1 X return [], i X if bracketed: terminators = [';'] X else: terminators = [';', '\n'] X list = [] X while i < end: X j = FindNextWord(str, i, end) X word = str[i:j] X if word in terminators: X i = j X break X if word <> '\n': list.append(i, j) X i = SkipSpaces(str, j, end) X return list, i X X X# Find the next word of a command. X# Semicolon and newline terminate words but also count as a word X# themselves. X# The start index must point to the start of the word. X X_word_prog = regexp.compile('([^ \t\n;[\\]+|\\\\C?M?(.|\n))*') X Xdef FindNextWord(str, i, end): X if i >= end: return end X if str[i] in '{"': X if str[i] = '{': i = BalanceBraces(str, i, end) X else: i = BalanceQuotes(str, i, end) X if i >= end or str[i] in ' \t\n;': return min(i, end) X raise TclSyntaxError, 'Garbage after } or "' X begin = i X while i < end: X i = _word_prog.exec(str, i)[0][1] X if i >= end: X i = end X break X c = str[i] X if c in ' \t': break X if c in ';\n': X if i = begin: i = i+1 X break X if c = '[': i = BalanceBrackets(str, i, end) X else: raise TclAssertError, 'word error' X return i X X X# Parse balanced brackets from str[i:end]. X# str[i] must be '['. X# Returns end such that str[i:end] ends with ']' X# and contains balanced braces and brackets. X X_brackets_prog = regexp.compile('([^][{\\]+|\n|\\\\C?M?(.|\n))*') X Xdef BalanceBrackets(str, i, end): X if i >= end or str[i] <> '[': X raise TclAssertError, 'BalanceBrackets' X nesting = 0 X while i < end: X i = _brackets_prog.exec(str, i)[0][1] X if i >= end: break X c = str[i] X if c = '{': i = BalanceBraces(str, i, end) X else: X i = i+1 X if c = '[': nesting = nesting + 1 X elif c = ']': X nesting = nesting - 1 X if nesting = 0: return i X else: raise TclAssertError, 'brackets error' X raise TclMatchingError, 'Unmatched bracket ([)' X X X# Parse balanced braces from str[i:end]. X# str[i] must be '{'. X# Returns end such that str[i:end] ends with '}' X# and contains balanced braces. X X_braces_prog = regexp.compile('([^{}\\]+|\n|\\\\C?M?(.|\n))*') X Xdef BalanceBraces(str, i, end): X if i >= end or str[i] <> '{': X raise TclAssertError, 'BalanceBraces' X nesting = 0 X while i < end: X i = _braces_prog.exec(str, i)[0][1] X if i >= end: break X c = str[i] X i = i+1 X if c = '{': nesting = nesting + 1 X elif c = '}': X nesting = nesting - 1 X if nesting = 0: return i X else: raise TclAssertError, 'braces error' X raise TclMatchingError, 'Unmatched brace ({)' X X X# Parse double quotes from str[i:end]. X# str[i] must be '"'. X# Returns end such that str[i:end] ends with an unescaped '"'. X X_quotes_prog = regexp.compile('([^"\\]+|\n|\\\\C?M?(.|\n))*') X Xdef BalanceQuotes(str, i, end): X if i >= end or str[i] <> '"': X raise TclAssertError, 'BalanceQuotes' X i = _quotes_prog.exec(str, i+1)[0][1] X if i < end and str[i] = '"': return i+1 X raise TclMatchingError, 'Unmatched quote (")' X X X# Static data used by Backslash() X X_bstab = {} X_bstab['n'] = '\n' X_bstab['r'] = '\r' X_bstab['t'] = '\t' X_bstab['b'] = '\b' X_bstab['e'] = '\033' X_bstab['\n'] = '' Xfor c in ' {}[]$";\\': _bstab[c] = c Xdel c X X# Backslash interpretation. X# First character must be a backslash. X# Return a pair (<replacement string>, <end of sequence>). X# Unrecognized or incomplete backslash sequences are not errors; X# this takes only the backslash itself off the string. X Xdef Backslash(str, i, end): X if i >= end or str[i] <> '\\': X raise TclAssertError, 'Backslash' X i = i+1 X if i = end: return '\\', i X c = str[i] X i = i+1 X if _bstab.has_key(c): return _bstab[c], i X if c = 'C': X if i = end: return '\\', i-1 X c = str[i] X i = i+1 X if c = 'M': X if i = end: return '\\', i-2 X c = str[i] X i = i+1 X x = ord(c) % 040 + 0200 X else: X x = ord(c) % 040 X return chr(x), i X elif c = 'M': X if i = end: return '\\', i-1 X c = str[i] X i = i+1 X x = ord(c) X if x < 0200: x = x + 0200 X return chr(x), i X elif c and c in '0123456789': X x = ord(c) - ord('0') X end = min(end, i+2) X while i < end: X c = str[i] X if c not in '0123456789': break X i = i+1 X x = x*8 + ord(c) - ord('0') X return ord(x), i X else: X # Not something that we recognize X return '\\', i-1 X X X# Skip over spaces and tabs (but not newlines). X X_spaces_prog = regexp.compile('[ \t]*') X Xdef SkipSpaces(str, i, end): X i = _spaces_prog.exec(str, i)[0][1] X return min(i, end) X X X# Concatenate the elements of a list with intervening spaces. X Xdef Concat(argv): X result = '' X sep = '' X for arg in argv: X result = result + (sep + arg) X sep = ' ' X return result X X X# Concatenate list elements, adding braces etc. to make them parseable X# again with SplitList. X Xdef BuildList(argv): X result = '' X sep = '' X for arg in argv: X arg = AddBraces(arg) X result = result + (sep + arg) X sep = ' ' X return result X X X# Add braces around a string if necessary to make it parseable by SplitList. X Xdef AddBraces(str): X # Special case for empty string X if str = '': return '{}' X # See if it contains balanced braces X res = '{' + str + '}' X if TryNextElement(res): X # See if it would survive unquoted X # XXX should escape [] and $ as well??? X if TryNextElement(str) and Collapse(str) = str: return str X # No -- return with added braces X return res X # Unbalanced braces. Add backslashes before suspect characters X res = '' X for c in str: X if c in '$\\[]{} ;': c = '\\' + c X elif c = '\n': c = '\\n' X elif c = '\t': c = '\\t' X res = res + c X return res X X Xdef TryNextElement(str): X end = len(str) X try: X i = FindNextElement(str, 0, end) X return i = end X except (TclSyntaxError, TclMatchingError): X return 0 EOF fi if test -s 'lib/testall.py' then echo '*** I will not over-write existing file lib/testall.py' else echo 'x - lib/testall.py' sed 's/^X//' > 'lib/testall.py' << 'EOF' X# Module 'testall' X# X# Python test set, should exercise: X# - all lexical and grammatical constructs X# - all opcodes from "opcode.h" X# - all operations on all object types X# - all builtin functions X# Ideally also: X# - all possible exception situations (Thank God we've got 'try') X# - all boundary cases X X XTestFailed = 'testall -- test failed' # Exception X X X######################################################### X# Part 1. Test all lexical and grammatical constructs. X# This just tests whether the parser accepts them all. X######################################################### X Xprint '1. Parser' X Xprint '1.1 Tokens' X Xprint '1.1.1 Backslashes' X X# Backslash means line continuation: Xx = 1 \ X+ 1 Xif x <> 2: raise TestFailed, 'backslash for line continuation' X X# Backslash does not means continuation in comments :\ Xx = 0 Xif x <> 0: raise TestFailed, 'backslash ending comment' X Xprint '1.1.2 Number formats' X Xif 0xff <> 255: raise TestFailed, 'hex number' Xif 0377 <> 255: raise TestFailed, 'octal number' Xx = 3.14 Xx = 0.314 Xx = 3e14 Xx = 3E14 Xx = 3e-14 X Xprint '1.2 Grammar' X Xprint 'single_input' # NEWLINE | simple_stmt | compound_stmt NEWLINE X# XXX can't test in a script -- this rule is only used when interactive X Xprint 'file_input' # (NEWLINE | stmt)* ENDMARKER X# Being tested as this very moment this very module X Xprint 'expr_input' # testlist NEWLINE X# XXX Hard to test -- used only in calls to input() X Xprint 'eval_input' # testlist ENDMARKER Xx = eval('1, 0 or 1') X Xprint 'funcdef' # 'def' NAME parameters ':' suite X### parameters: '(' [fplist] ')' X### fplist: fpdef (',' fpdef)* X### fpdef: NAME | '(' fplist ')' Xdef f1(): pass Xdef f2(one_argument): pass Xdef f3(two, arguments): pass Xdef f4(two, (compound, (arguments))): pass X X### stmt: simple_stmt | compound_stmt X### simple_stmt: expr_stmt | print_stmt | pass_stmt | del_stmt | flow_stmt | import_stmt X# Tested below X Xprint 'expr_stmt' # (exprlist '=')* exprlist NEWLINE X1 X1, 2, 3 Xx = 1 Xx = 1, 2, 3 Xx = y = z = 1, 2, 3 Xx, y, z = 1, 2, 3 Xabc = a, b, c = x, y, z = xyz = 1, 2, (3, 4) X# NB these variables are deleted below X Xprint 'print_stmt' # 'print' (test ',')* [test] NEWLINE Xprint 1, 2, 3 Xprint 1, 2, 3, Xprint Xprint 0 or 1, 0 or 1, Xprint 0 or 1 X Xprint 'del_stmt' # 'del' exprlist NEWLINE Xdel abc Xdel x, y, (z, xyz) X Xprint 'pass_stmt' # 'pass' NEWLINE Xpass X Xprint 'flow_stmt' # break_stmt | return_stmt | raise_stmt X# Tested below X Xprint 'break_stmt' # 'break' NEWLINE Xwhile 1: break X Xprint 'return_stmt' # 'return' [testlist] NEWLINE Xdef g1(): return Xdef g2(): return 1 Xg1() Xx = g2() X Xprint 'raise_stmt' # 'raise' expr [',' expr] NEWLINE Xtry: raise RuntimeError, 'just testing' Xexcept RuntimeError: pass Xtry: raise KeyboardInterrupt Xexcept KeyboardInterrupt: pass X Xprint 'import_stmt' # 'import' NAME (',' NAME)* NEWLINE | 'from' NAME 'import' ('*' | NAME (',' NAME)*) NEWLINE X[1] Ximport sys X[2] Ximport time, math X[3] Xfrom time import sleep X[4] Xfrom math import * X[5] Xfrom sys import modules, ps1, ps2 X[6] X X### compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | funcdef | classdef X# Tested below X Xprint 'if_stmt' # 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite] Xif 1: pass Xif 1: pass Xelse: pass Xif 0: pass Xelif 0: pass Xif 0: pass Xelif 0: pass Xelif 0: pass Xelif 0: pass Xelse: pass X Xprint 'while_stmt' # 'while' test ':' suite ['else' ':' suite] Xwhile 0: pass Xwhile 0: pass Xelse: pass X Xprint 'for_stmt' # 'for' exprlist 'in' exprlist ':' suite ['else' ':' suite] X[1] Xfor i in 1, 2, 3: pass X[2] Xfor i, j, k in (): pass Xelse: pass X[3] X Xprint 'try_stmt' # 'try' ':' suite (except_clause ':' suite)* ['finally' ':' suite] X### except_clause: 'except' [expr [',' expr]] Xtry: pass Xtry: 1/0 Xexcept RuntimeError: pass Xtry: 1/0 Xexcept EOFError: pass Xexcept TypeError, msg: pass Xexcept RuntimeError, msg: pass Xexcept: pass Xtry: pass Xfinally: pass Xtry: 1/0 Xexcept: pass Xfinally: pass X Xprint 'suite' # simple_stmt | NEWLINE INDENT NEWLINE* (stmt NEWLINE*)+ DEDENT Xif 1: pass Xif 1: X pass Xif 1: X # X # X # X pass X pass X # X pass X # X Xprint 'test' # and_test ('or' and_test)* X### and_test: not_test ('and' not_test)* X### not_test: 'not' not_test | comparison X### comparison: expr (comp_op expr)* X### comp_op: '<'|'>'|'='|'>' '='|'<' '='|'<' '>'|'in'|'not' 'in'|'is'|'is' 'not' Xif 1: pass Xif 1 = 1: pass Xif 1 < 1 > 1 = 1 >= 1 <= 1 <> 1 in 1 not in 1 is 1 is not 1: pass Xif not 1 = 1 = 1: pass Xif not 1 = 1 and 1 and 1: pass Xif 1 and 1 or 1 and 1 and 1 or not 1 = 1 = 1 and 1: pass X Xprint 'expr' # term (('+'|'-') term)* Xx = 1 Xx = 1 + 1 Xx = 1 - 1 - 1 Xx = 1 - 1 + 1 - 1 + 1 X Xprint 'term' # factor (('*'|'/'|'%') factor)* Xx = 1 * 1 Xx = 1 / 1 Xx = 1 % 1 Xx = 1 / 1 * 1 % 1 X Xprint 'factor' # ('+'|'-') factor | atom trailer* X### trailer: '(' [testlist] ')' | '[' subscript ']' | '.' NAME X### subscript: expr | [expr] ':' [expr] Xx = +1 Xx = -1 Xx = 1 Xc = sys.ps1[0] Xx = time.time() Xx = sys.modules['time'].time() Xa = '01234' Xc = a[0] Xc = a[0:5] Xc = a[:5] Xc = a[0:] Xc = a[:] Xc = a[-5:] Xc = a[:-1] Xc = a[-4:-3] X Xprint 'atom' # '(' [testlist] ')' | '[' [testlist] ']' | '{' '}' | '`' testlist '`' | NAME | NUMBER | STRING Xx = (1) Xx = (1 or 2 or 3) Xx = (1 or 2 or 3, 2, 3) Xx = [] Xx = [1] Xx = [1 or 2 or 3] Xx = [1 or 2 or 3, 2, 3] Xx = [] Xx = {} Xx = `x` Xx = x Xx = 'x' Xx = 123 X X### exprlist: expr (',' expr)* [','] X### testlist: test (',' test)* [','] X# These have been exercised enough above X Xprint 'classdef' # 'class' NAME parameters ['=' baselist] ':' suite X### baselist: atom arguments (',' atom arguments)* X### arguments: '(' [testlist] ')' Xclass B(): pass Xclass C1() = B(): pass Xclass C2() = B(): pass Xclass D() = C1(), C2(), B(): pass Xclass C(): X def meth1(self): pass X def meth2(self, arg): pass X def meth3(self, (a1, a2)): pass X X X######################################################### X# Part 2. Test all opcodes from "opcode.h" X######################################################### X Xprint '2. Opcodes' Xprint 'XXX Not yet fully implemented' X Xprint '2.1 try inside for loop' Xn = 0 Xfor i in range(10): X n = n+i X try: 1/0 X except NameError: pass X except RuntimeError: pass X except TypeError: pass X finally: pass X try: pass X except: pass X try: pass X finally: pass X n = n+i Xif n <> 90: X raise TestFailed, 'try inside for' X X X######################################################### X# Part 3. Test all operations on all object types X######################################################### X Xprint '3. Object types' Xprint 'XXX Not yet implemented' X X X######################################################### X# Part 4. Test all built-in functions X######################################################### X Xprint '4. Built-in functions' X Xprint 'abs' Xif abs(0) <> 0: raise TestFailed, 'abs(0)' Xif abs(1234) <> 1234: raise TestFailed, 'abs(1234)' Xif abs(-1234) <> 1234: raise TestFailed, 'abs(-1234)' Xif abs(0.0) <> 0.0: raise TestFailed, 'abs(0.0)' Xif abs(3.14) <> 3.14: raise TestFailed, 'abs(3.14)' Xif abs(-3.14) <> 3.14: raise TestFailed, 'abs(-3.14)' X Xprint 'dir' Xif 'x' not in dir(): raise TestFailed, 'dir()' Xif 'modules' not in dir(sys): raise TestFailed, 'dir(sys)' X Xprint 'divmod' Xif divmod(12, 7) <> (1, 5): raise TestFailed, 'divmod(12, 7)' Xif divmod(-12, 7) <> (-2, 2): raise TestFailed, 'divmod(-12, 7)' Xif divmod(12, -7) <> (-2, -2): raise TestFailed, 'divmod(12, -7)' Xif divmod(-12, -7) <> (1, -5): raise TestFailed, 'divmod(-12, -7)' X Xprint 'eval' Xif eval('1+1') <> 2: raise TestFailed, 'eval(\'1+1\')' X Xprint 'exec' Xexec('z=1+1\n') Xif z <> 2: raise TestFailed, 'exec(\'z=1+1\'\\n)' X Xprint 'float' Xif float(3.14) <> 3.14: raise TestFailed, 'float(3.14)' Xif float(314) <> 314.0: raise TestFailed, 'float(314)' X Xprint 'input' X# Can't test in a script X Xprint 'int' Xif int(100) <> 100: raise TestFailed, 'int(100)' Xif int(3.14) <> 3: raise TestFailed, 'int(3.14)' X Xprint 'len' Xif len('123') <> 3: raise TestFailed, 'len(\'123\')' Xif len(()) <> 0: raise TestFailed, 'len(())' Xif len((1, 2, 3, 4)) <> 4: raise TestFailed, 'len((1, 2, 3, 4))' Xif len([1, 2, 3, 4]) <> 4: raise TestFailed, 'len([1, 2, 3, 4])' Xif len({}) <> 0: raise TestFailed, 'len({})' X Xprint 'min' Xif min('123123') <> '1': raise TestFailed, 'min(\'123123\')' Xif min(1, 2, 3) <> 1: raise TestFailed, 'min(1, 2, 3)' Xif min((1, 2, 3, 1, 2, 3)) <> 1: raise TestFailed, 'min((1, 2, 3, 1, 2, 3))' Xif min([1, 2, 3, 1, 2, 3]) <> 1: raise TestFailed, 'min([1, 2, 3, 1, 2, 3])' X Xprint 'max' Xif max('123123') <> '3': raise TestFailed, 'max(\'123123\')' Xif max(1, 2, 3) <> 3: raise TestFailed, 'max(1, 2, 3)' Xif max((1, 2, 3, 1, 2, 3)) <> 3: raise TestFailed, 'max((1, 2, 3, 1, 2, 3))' Xif max([1, 2, 3, 1, 2, 3]) <> 3: raise TestFailed, 'max([1, 2, 3, 1, 2, 3])' X Xprint 'open' Xprint 'NB! This test creates a file named "@test" in the current directory.' Xfp = open('@test', 'w') Xfp.write('The quick brown fox jumps over the lazy dog') Xfp.write('.\n') Xfp.write('Dear John\n') Xfp.write('XXX'*100) Xfp.write('YYY'*100) Xfp.close() Xdel fp Xfp = open('@test', 'r') Xif fp.readline() <> 'The quick brown fox jumps over the lazy dog.\n': X raise TestFailed, 'readline()' Xif fp.readline(4) <> 'Dear': raise TestFailed, 'readline(4) # short' Xif fp.readline(100) <> ' John\n': raise TestFailed, 'readline(100)' Xif fp.read(300) <> 'XXX'*100: raise TestFailed, 'read(300)' Xif fp.read(1000) <> 'YYY'*100: raise TestFailed, 'read(1000) # truncate' Xfp.close() Xdel fp X Xprint 'range' Xif range(3) <> [0, 1, 2]: raise TestFailed, 'range(3)' Xif range(1, 5) <> [1, 2, 3, 4]: raise TestFailed, 'range(1, 5)' Xif range(0) <> []: raise TestFailed, 'range(0)' Xif range(-3) <> []: raise TestFailed, 'range(-3)' Xif range(1, 10, 3) <> [1, 4, 7]: raise TestFailed, 'range(1, 10, 3)' Xif range(5, -5, -3) <> [5, 2, -1, -4]: raise TestFailed, 'range(5, -5, -3)' X Xprint 'raw_input' Xsavestdin = sys.stdin Xtry: X sys.stdin = open('@test', 'r') X if raw_input() <> 'The quick brown fox jumps over the lazy dog.': X raise TestFailed, 'raw_input()' X if raw_input('testing\n') <> 'Dear John': X raise TestFailed, 'raw_input(\'testing\\n\')' Xfinally: X sys.stdin = savestdin X Xprint 'reload' Ximport string Xreload(string) X Xprint 'type' Xif type('') <> type('123') or type('') = type(()): X raise TestFailed, 'type()' X X Xprint 'Passed all tests.' X Xtry: X import mac X unlink = mac.unlink Xexcept NameError: X try: X import posix X unlink = posix.unlink X except NameError: X pass X Xunlink('@test') Xprint 'Unlinked @test' EOF fi if test -s 'src/listobject.c' then echo '*** I will not over-write existing file src/listobject.c' else echo 'x - src/listobject.c' sed 's/^X//' > 'src/listobject.c' << 'EOF' X/*********************************************************** XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The XNetherlands. X X All Rights Reserved X XPermission to use, copy, modify, and distribute this software and its Xdocumentation for any purpose and without fee is hereby granted, Xprovided that the above copyright notice appear in all copies and that Xboth that copyright notice and this permission notice appear in Xsupporting documentation, and that the names of Stichting Mathematisch XCentrum or CWI not be used in advertising or publicity pertaining to Xdistribution of the software without specific, written prior permission. X XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. X X******************************************************************/ X X/* List object implementation */ X X#include "allobjects.h" X Xobject * Xnewlistobject(size) X int size; X{ X int i; X listobject *op; X if (size < 0) { X err_badcall(); X return NULL; X } X op = (listobject *) malloc(sizeof(listobject)); X if (op == NULL) { X return err_nomem(); X } X if (size <= 0) { X op->ob_item = NULL; X } X else { X op->ob_item = (object **) malloc(size * sizeof(object *)); X if (op->ob_item == NULL) { X free((ANY *)op); X return err_nomem(); X } X } X NEWREF(op); X op->ob_type = &Listtype; X op->ob_size = size; X for (i = 0; i < size; i++) X op->ob_item[i] = NULL; X return (object *) op; X} X Xint Xgetlistsize(op) X object *op; X{ X if (!is_listobject(op)) { X err_badcall(); X return -1; X } X else X return ((listobject *)op) -> ob_size; X} X Xobject * Xgetlistitem(op, i) X object *op; X int i; X{ X if (!is_listobject(op)) { X err_badcall(); X return NULL; X } X if (i < 0 || i >= ((listobject *)op) -> ob_size) { X err_setstr(IndexError, "list index out of range"); X return NULL; X } X return ((listobject *)op) -> ob_item[i]; X} X Xint Xsetlistitem(op, i, newitem) X register object *op; X register int i; X register object *newitem; X{ X register object *olditem; X if (!is_listobject(op)) { X if (newitem != NULL) X DECREF(newitem); X err_badcall(); X return -1; X } X if (i < 0 || i >= ((listobject *)op) -> ob_size) { X if (newitem != NULL) X DECREF(newitem); X err_setstr(IndexError, "list assignment index out of range"); X return -1; X } X olditem = ((listobject *)op) -> ob_item[i]; X ((listobject *)op) -> ob_item[i] = newitem; X if (olditem != NULL) X DECREF(olditem); X return 0; X} X Xstatic int Xins1(self, where, v) X listobject *self; X int where; X object *v; X{ X int i; X object **items; X if (v == NULL) { X err_badcall(); X return -1; X } X items = self->ob_item; X RESIZE(items, object *, self->ob_size+1); X if (items == NULL) { X err_nomem(); X return -1; X } X if (where < 0) X where = 0; X if (where > self->ob_size) X where = self->ob_size; X for (i = self->ob_size; --i >= where; ) X items[i+1] = items[i]; X INCREF(v); X items[where] = v; X self->ob_item = items; X self->ob_size++; X return 0; X} X Xint Xinslistitem(op, where, newitem) X object *op; X int where; X object *newitem; X{ X if (!is_listobject(op)) { X err_badcall(); X return -1; X } X return ins1((listobject *)op, where, newitem); X} X Xint Xaddlistitem(op, newitem) X object *op; X object *newitem; X{ X if (!is_listobject(op)) { X err_badcall(); X return -1; X } X return ins1((listobject *)op, X (int) ((listobject *)op)->ob_size, newitem); X} X X/* Methods */ X Xstatic void Xlist_dealloc(op) X listobject *op; X{ X int i; X for (i = 0; i < op->ob_size; i++) { X if (op->ob_item[i] != NULL) X DECREF(op->ob_item[i]); X } X if (op->ob_item != NULL) X free((ANY *)op->ob_item); X free((ANY *)op); X} X Xstatic void Xlist_print(op, fp, flags) X listobject *op; X FILE *fp; X int flags; X{ X int i; X fprintf(fp, "["); X for (i = 0; i < op->ob_size && !StopPrint; i++) { X if (i > 0) { X fprintf(fp, ", "); X } X printobject(op->ob_item[i], fp, flags); X } X fprintf(fp, "]"); X} X Xobject * Xlist_repr(v) X listobject *v; X{ X object *s, *t, *comma; X int i; X s = newstringobject("["); X comma = newstringobject(", "); X for (i = 0; i < v->ob_size && s != NULL; i++) { X if (i > 0) X joinstring(&s, comma); X t = reprobject(v->ob_item[i]); X joinstring(&s, t); X DECREF(t); X } X DECREF(comma); X t = newstringobject("]"); X joinstring(&s, t); X DECREF(t); X return s; X} X Xstatic int Xlist_compare(v, w) X listobject *v, *w; X{ X int len = (v->ob_size < w->ob_size) ? v->ob_size : w->ob_size; X int i; X for (i = 0; i < len; i++) { X int cmp = cmpobject(v->ob_item[i], w->ob_item[i]); X if (cmp != 0) X return cmp; X } X return v->ob_size - w->ob_size; X} X Xstatic int Xlist_length(a) X listobject *a; X{ X return a->ob_size; X} X Xstatic object * Xlist_item(a, i) X listobject *a; X int i; X{ X if (i < 0 || i >= a->ob_size) { X err_setstr(IndexError, "list index out of range"); X return NULL; X } X INCREF(a->ob_item[i]); X return a->ob_item[i]; X} X Xstatic object * Xlist_slice(a, ilow, ihigh) X listobject *a; X int ilow, ihigh; X{ X listobject *np; X int i; X if (ilow < 0) X ilow = 0; X else if (ilow > a->ob_size) X ilow = a->ob_size; X if (ihigh < 0) X ihigh = 0; X if (ihigh < ilow) X ihigh = ilow; X else if (ihigh > a->ob_size) X ihigh = a->ob_size; X np = (listobject *) newlistobject(ihigh - ilow); X if (np == NULL) X return NULL; X for (i = ilow; i < ihigh; i++) { X object *v = a->ob_item[i]; X INCREF(v); X np->ob_item[i - ilow] = v; X } X return (object *)np; X} X Xstatic object * Xlist_concat(a, bb) X listobject *a; X object *bb; X{ X int size; X int i; X listobject *np; X if (!is_listobject(bb)) { X err_badarg(); X return NULL; X } X#define b ((listobject *)bb) X size = a->ob_size + b->ob_size; X np = (listobject *) newlistobject(size); X if (np == NULL) { X return err_nomem(); X } X for (i = 0; i < a->ob_size; i++) { X object *v = a->ob_item[i]; X INCREF(v); X np->ob_item[i] = v; X } X for (i = 0; i < b->ob_size; i++) { X object *v = b->ob_item[i]; X INCREF(v); X np->ob_item[i + a->ob_size] = v; X } X return (object *)np; X#undef b X} X Xstatic int Xlist_ass_item(a, i, v) X listobject *a; X int i; X object *v; X{ X if (i < 0 || i >= a->ob_size) { X err_setstr(IndexError, "list assignment index out of range"); X return -1; X } X if (v == NULL) X return list_ass_slice(a, i, i+1, v); X INCREF(v); X DECREF(a->ob_item[i]); X a->ob_item[i] = v; X return 0; X} X Xstatic int Xlist_ass_slice(a, ilow, ihigh, v) X listobject *a; X int ilow, ihigh; X object *v; X{ X object **item; X int n; /* Size of replacement list */ X int d; /* Change in size */ X int k; /* Loop index */ X#define b ((listobject *)v) X if (v == NULL) X n = 0; X else if (is_listobject(v)) X n = b->ob_size; X else { X err_badarg(); X return -1; X } X if (ilow < 0) X ilow = 0; X else if (ilow > a->ob_size) X ilow = a->ob_size; X if (ihigh < 0) X ihigh = 0; X if (ihigh < ilow) X ihigh = ilow; X else if (ihigh > a->ob_size) X ihigh = a->ob_size; X item = a->ob_item; X d = n - (ihigh-ilow); X if (d <= 0) { /* Delete -d items; DECREF ihigh-ilow items */ X for (k = ilow; k < ihigh; k++) X DECREF(item[k]); X if (d < 0) { X for (/*k = ihigh*/; k < a->ob_size; k++) X item[k+d] = item[k]; X a->ob_size += d; X RESIZE(item, object *, a->ob_size); /* Can't fail */ X a->ob_item = item; X } X } X else { /* Insert d items; DECREF ihigh-ilow items */ X RESIZE(item, object *, a->ob_size + d); X if (item == NULL) { X err_nomem(); X return -1; X } X for (k = a->ob_size; --k >= ihigh; ) X item[k+d] = item[k]; X for (/*k = ihigh-1*/; k >= ilow; --k) X DECREF(item[k]); X a->ob_item = item; X a->ob_size += d; X } X for (k = 0; k < n; k++, ilow++) { X object *w = b->ob_item[k]; X INCREF(w); X item[ilow] = w; X } X return 0; X#undef b X} X Xstatic object * Xins(self, where, v) X listobject *self; X int where; X object *v; X{ X if (ins1(self, where, v) != 0) X return NULL; X INCREF(None); X return None; X} X Xstatic object * Xlistinsert(self, args) X listobject *self; X object *args; X{ X int i; X if (args == NULL || !is_tupleobject(args) || gettuplesize(args) != 2) { X err_badarg(); X return NULL; X } X if (!getintarg(gettupleitem(args, 0), &i)) X return NULL; X return ins(self, i, gettupleitem(args, 1)); X} X Xstatic object * Xlistappend(self, args) X listobject *self; X object *args; X{ X return ins(self, (int) self->ob_size, args); X} X Xstatic int Xcmp(v, w) X char *v, *w; X{ X return cmpobject(* (object **) v, * (object **) w); X} X Xstatic object * Xlistsort(self, args) X listobject *self; X object *args; X{ X if (args != NULL) { X err_badarg(); X return NULL; X } X err_clear(); X if (self->ob_size > 1) X qsort((char *)self->ob_item, X (int) self->ob_size, sizeof(object *), cmp); X if (err_occurred()) X return NULL; X INCREF(None); X return None; X} X Xint Xsortlist(v) X object *v; X{ X if (v == NULL || !is_listobject(v)) { X err_badcall(); X return -1; X } X v = listsort((listobject *)v, (object *)NULL); X if (v == NULL) X return -1; X DECREF(v); X return 0; X} X Xstatic struct methodlist list_methods[] = { X {"append", listappend}, X {"insert", listinsert}, X {"sort", listsort}, X {NULL, NULL} /* sentinel */ X}; X Xstatic object * Xlist_getattr(f, name) X listobject *f; X char *name; X{ X return findmethod(list_methods, (object *)f, name); X} X Xstatic sequence_methods list_as_sequence = { X list_length, /*sq_length*/ X list_concat, /*sq_concat*/ X 0, /*sq_repeat*/ X list_item, /*sq_item*/ X list_slice, /*sq_slice*/ X list_ass_item, /*sq_ass_item*/ X list_ass_slice, /*sq_ass_slice*/ X}; X Xtypeobject Listtype = { X OB_HEAD_INIT(&Typetype) X 0, X "list", X sizeof(listobject), X 0, X list_dealloc, /*tp_dealloc*/ X list_print, /*tp_print*/ X list_getattr, /*tp_getattr*/ X 0, /*tp_setattr*/ X list_compare, /*tp_compare*/ X list_repr, /*tp_repr*/ X 0, /*tp_as_number*/ X &list_as_sequence, /*tp_as_sequence*/ X 0, /*tp_as_mapping*/ X}; EOF fi if test -s 'src/parser.c' then echo '*** I will not over-write existing file src/parser.c' else echo 'x - src/parser.c' sed 's/^X//' > 'src/parser.c' << 'EOF' X/*********************************************************** XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The XNetherlands. X X All Rights Reserved X XPermission to use, copy, modify, and distribute this software and its Xdocumentation for any purpose and without fee is hereby granted, Xprovided that the above copyright notice appear in all copies and that Xboth that copyright notice and this permission notice appear in Xsupporting documentation, and that the names of Stichting Mathematisch XCentrum or CWI not be used in advertising or publicity pertaining to Xdistribution of the software without specific, written prior permission. X XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. X X******************************************************************/ X X/* Parser implementation */ X X/* For a description, see the comments at end of this file */ X X/* XXX To do: error recovery */ X X#include "pgenheaders.h" X#include "assert.h" X#include "token.h" X#include "grammar.h" X#include "node.h" X#include "parser.h" X#include "errcode.h" X X X#ifdef DEBUG Xextern int debugging; X#define D(x) if (!debugging); else x X#else X#define D(x) X#endif X X X/* STACK DATA TYPE */ X Xstatic void s_reset PROTO((stack *)); X Xstatic void Xs_reset(s) X stack *s; X{ X s->s_top = &s->s_base[MAXSTACK]; X} X X#define s_empty(s) ((s)->s_top == &(s)->s_base[MAXSTACK]) X Xstatic int s_push PROTO((stack *, dfa *, node *)); X Xstatic int Xs_push(s, d, parent) X register stack *s; X dfa *d; X node *parent; X{ X register stackentry *top; X if (s->s_top == s->s_base) { X fprintf(stderr, "s_push: parser stack overflow\n"); X return -1; X } X top = --s->s_top; X top->s_dfa = d; X top->s_parent = parent; X top->s_state = 0; X return 0; X} X X#ifdef DEBUG X Xstatic void s_pop PROTO((stack *)); X Xstatic void Xs_pop(s) X register stack *s; X{ X if (s_empty(s)) { X fprintf(stderr, "s_pop: parser stack underflow -- FATAL\n"); X abort(); X } X s->s_top++; X} X X#else /* !DEBUG */ X X#define s_pop(s) (s)->s_top++ X X#endif X X X/* PARSER CREATION */ X Xparser_state * Xnewparser(g, start) X grammar *g; X int start; X{ X parser_state *ps; X X if (!g->g_accel) X addaccelerators(g); X ps = NEW(parser_state, 1); X if (ps == NULL) X return NULL; X ps->p_grammar = g; X ps->p_tree = newtree(start); X if (ps->p_tree == NULL) { X DEL(ps); X return NULL; X } X s_reset(&ps->p_stack); X (void) s_push(&ps->p_stack, finddfa(g, start), ps->p_tree); X return ps; X} X Xvoid Xdelparser(ps) X parser_state *ps; X{ X /* NB If you want to save the parse tree, X you must set p_tree to NULL before calling delparser! */ X freetree(ps->p_tree); X DEL(ps); X} X X X/* PARSER STACK OPERATIONS */ X Xstatic int shift PROTO((stack *, int, char *, int, int)); X Xstatic int Xshift(s, type, str, newstate, lineno) X register stack *s; X int type; X char *str; X int newstate; X int lineno; X{ X assert(!s_empty(s)); X if (addchild(s->s_top->s_parent, type, str, lineno) == NULL) { X fprintf(stderr, "shift: no mem in addchild\n"); X return -1; X } X s->s_top->s_state = newstate; X return 0; X} X Xstatic int push PROTO((stack *, int, dfa *, int, int)); X Xstatic int Xpush(s, type, d, newstate, lineno) X register stack *s; X int type; X dfa *d; X int newstate; X int lineno; X{ X register node *n; X n = s->s_top->s_parent; X assert(!s_empty(s)); X if (addchild(n, type, (char *)NULL, lineno) == NULL) { X fprintf(stderr, "push: no mem in addchild\n"); X return -1; X } X s->s_top->s_state = newstate; X return s_push(s, d, CHILD(n, NCH(n)-1)); X} X X X/* PARSER PROPER */ X Xstatic int classify PROTO((grammar *, int, char *)); X Xstatic int Xclassify(g, type, str) X grammar *g; X register int type; X char *str; X{ X register int n = g->g_ll.ll_nlabels; X X if (type == NAME) { X register char *s = str; X register label *l = g->g_ll.ll_label; X register int i; X for (i = n; i > 0; i--, l++) { X if (l->lb_type == NAME && l->lb_str != NULL && X l->lb_str[0] == s[0] && X strcmp(l->lb_str, s) == 0) { X D(printf("It's a keyword\n")); X return n - i; X } X } X } X X { X register label *l = g->g_ll.ll_label; X register int i; X for (i = n; i > 0; i--, l++) { X if (l->lb_type == type && l->lb_str == NULL) { X D(printf("It's a token we know\n")); X return n - i; X } X } X } X X D(printf("Illegal token\n")); X return -1; X} X Xint Xaddtoken(ps, type, str, lineno) X register parser_state *ps; X register int type; X char *str; X int lineno; X{ X register int ilabel; X X D(printf("Token %s/'%s' ... ", tok_name[type], str)); X X /* Find out which label this token is */ X ilabel = classify(ps->p_grammar, type, str); X if (ilabel < 0) X return E_SYNTAX; X X /* Loop until the token is shifted or an error occurred */ X for (;;) { X /* Fetch the current dfa and state */ X register dfa *d = ps->p_stack.s_top->s_dfa; X register state *s = &d->d_state[ps->p_stack.s_top->s_state]; X X D(printf(" DFA '%s', state %d:", X d->d_name, ps->p_stack.s_top->s_state)); X X /* Check accelerator */ X if (s->s_lower <= ilabel && ilabel < s->s_upper) { X register int x = s->s_accel[ilabel - s->s_lower]; X if (x != -1) { X if (x & (1<<7)) { X /* Push non-terminal */ X int nt = (x >> 8) + NT_OFFSET; X int arrow = x & ((1<<7)-1); X dfa *d1 = finddfa(ps->p_grammar, nt); X if (push(&ps->p_stack, nt, d1, X arrow, lineno) < 0) { X D(printf(" MemError: push.\n")); X return E_NOMEM; X } X D(printf(" Push ...\n")); X continue; X } X X /* Shift the token */ X if (shift(&ps->p_stack, type, str, X x, lineno) < 0) { X D(printf(" MemError: shift.\n")); X return E_NOMEM; X } X D(printf(" Shift.\n")); X /* Pop while we are in an accept-only state */ X while (s = &d->d_state X [ps->p_stack.s_top->s_state], X s->s_accept && s->s_narcs == 1) { X D(printf(" Direct pop.\n")); X s_pop(&ps->p_stack); X if (s_empty(&ps->p_stack)) { X D(printf(" ACCEPT.\n")); X return E_DONE; X } X d = ps->p_stack.s_top->s_dfa; X } X return E_OK; X } X } X X if (s->s_accept) { X /* Pop this dfa and try again */ X s_pop(&ps->p_stack); X D(printf(" Pop ...\n")); X if (s_empty(&ps->p_stack)) { X D(printf(" Error: bottom of stack.\n")); X return E_SYNTAX; X } X continue; X } X X /* Stuck, report syntax error */ X D(printf(" Error.\n")); X return E_SYNTAX; X } X} X X X#ifdef DEBUG X X/* DEBUG OUTPUT */ X Xvoid Xdumptree(g, n) X grammar *g; X node *n; X{ X int i; X X if (n == NULL) X printf("NIL"); X else { X label l; X l.lb_type = TYPE(n); X l.lb_str = TYPE(str); X printf("%s", labelrepr(&l)); X if (ISNONTERMINAL(TYPE(n))) { X printf("("); X for (i = 0; i < NCH(n); i++) { X if (i > 0) X printf(","); X dumptree(g, CHILD(n, i)); X } X printf(")"); X } X } X} X Xvoid Xshowtree(g, n) X grammar *g; X node *n; X{ X int i; X X if (n == NULL) X return; X if (ISNONTERMINAL(TYPE(n))) { X for (i = 0; i < NCH(n); i++) X showtree(g, CHILD(n, i)); X } X else if (ISTERMINAL(TYPE(n))) { X printf("%s", tok_name[TYPE(n)]); X if (TYPE(n) == NUMBER || TYPE(n) == NAME) X printf("(%s)", STR(n)); X printf(" "); X } X else X printf("? "); X} X Xvoid Xprinttree(ps) X parser_state *ps; X{ X if (debugging) { X printf("Parse tree:\n"); X dumptree(ps->p_grammar, ps->p_tree); X printf("\n"); X printf("Tokens:\n"); X showtree(ps->p_grammar, ps->p_tree); X printf("\n"); X } X printf("Listing:\n"); X listtree(ps->p_tree); X printf("\n"); X} X X#endif /* DEBUG */ X X/* X XDescription X----------- X XThe parser's interface is different than usual: the function addtoken() Xmust be called for each token in the input. This makes it possible to Xturn it into an incremental parsing system later. The parsing system Xconstructs a parse tree as it goes. X XA parsing rule is represented as a Deterministic Finite-state Automaton X(DFA). A node in a DFA represents a state of the parser; an arc represents Xa transition. Transitions are either labeled with terminal symbols or Xwith non-terminals. When the parser decides to follow an arc labeled Xwith a non-terminal, it is invoked recursively with the DFA representing Xthe parsing rule for that as its initial state; when that DFA accepts, Xthe parser that invoked it continues. The parse tree constructed by the Xrecursively called parser is inserted as a child in the current parse tree. X XThe DFA's can be constructed automatically from a more conventional Xlanguage description. An extended LL(1) grammar (ELL(1)) is suitable. XCertain restrictions make the parser's life easier: rules that can produce Xthe empty string should be outlawed (there are other ways to put loops Xor optional parts in the language). To avoid the need to construct XFIRST sets, we can require that all but the last alternative of a rule X(really: arc going out of a DFA's state) must begin with a terminal Xsymbol. X XAs an example, consider this grammar: X Xexpr: term (OP term)* Xterm: CONSTANT | '(' expr ')' X XThe DFA corresponding to the rule for expr is: X X------->.---term-->.-------> X ^ | X | | X \----OP----/ X XThe parse tree generated for the input a+b is: X X(expr: (term: (NAME: a)), (OP: +), (term: (NAME: b))) X X*/ EOF fi if test -s 'src/patchlevel.h' then echo '*** I will not over-write existing file src/patchlevel.h' else echo 'x - src/patchlevel.h' sed 's/^X//' > 'src/patchlevel.h' << 'EOF' X1 EOF fi if test -s 'src/posixmodule.c' then echo '*** I will not over-write existing file src/posixmodule.c' else echo 'x - src/posixmodule.c' sed 's/^X//' > 'src/posixmodule.c' << 'EOF' X/*********************************************************** XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The XNetherlands. X X All Rights Reserved X XPermission to use, copy, modify, and distribute this software and its Xdocumentation for any purpose and without fee is hereby granted, Xprovided that the above copyright notice appear in all copies and that Xboth that copyright notice and this permission notice appear in Xsupporting documentation, and that the names of Stichting Mathematisch XCentrum or CWI not be used in advertising or publicity pertaining to Xdistribution of the software without specific, written prior permission. X XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. X X******************************************************************/ X X/* POSIX module implementation */ X X#include <signal.h> X#include <string.h> X#include <setjmp.h> X#include <sys/types.h> X#include <sys/stat.h> X#include <sys/time.h> X#ifdef SYSV X#include <dirent.h> X#define direct dirent X#else X#include <sys/dir.h> X#endif X X#include "allobjects.h" X#include "modsupport.h" X Xextern char *strerror PROTO((int)); X X#ifdef AMOEBA X#define NO_LSTAT X#endif X X X/* Return a dictionary corresponding to the POSIX environment table */ X Xextern char **environ; X Xstatic object * Xconvertenviron() X{ X object *d; X char **e; X d = newdictobject(); X if (d == NULL) X return NULL; X if (environ == NULL) X return d; X /* XXX This part ignores errors */ X for (e = environ; *e != NULL; e++) { X object *v; X char *p = strchr(*e, '='); X if (p == NULL) X continue; X v = newstringobject(p+1); X if (v == NULL) X continue; X *p = '\0'; X (void) dictinsert(d, *e, v); X *p = '='; X DECREF(v); X } X return d; X} X X Xstatic object *PosixError; /* Exception posix.error */ X X/* Set a POSIX-specific error from errno, and return NULL */ X Xstatic object * Xposix_error() X{ X return err_errno(PosixError); X} X X X/* POSIX generic methods */ X Xstatic object * Xposix_1str(args, func) X object *args; X int (*func) FPROTO((const char *)); X{ X object *path1; X if (!getstrarg(args, &path1)) X return NULL; X if ((*func)(getstringvalue(path1)) < 0) X return posix_error(); X INCREF(None); X return None; X} X Xstatic object * Xposix_2str(args, func) X object *args; X int (*func) FPROTO((const char *, const char *)); X{ X object *path1, *path2; X if (!getstrstrarg(args, &path1, &path2)) X return NULL; X if ((*func)(getstringvalue(path1), getstringvalue(path2)) < 0) X return posix_error(); X INCREF(None); X return None; X} X Xstatic object * Xposix_strint(args, func) X object *args; X int (*func) FPROTO((const char *, int)); X{ X object *path1; X int i; X if (!getstrintarg(args, &path1, &i)) X return NULL; X if ((*func)(getstringvalue(path1), i) < 0) X return posix_error(); X INCREF(None); X return None; X} X Xstatic object * Xposix_do_stat(self, args, statfunc) X object *self; X object *args; X int (*statfunc) FPROTO((const char *, struct stat *)); X{ X struct stat st; X object *path; X object *v; X if (!getstrarg(args, &path)) X return NULL; X if ((*statfunc)(getstringvalue(path), &st) != 0) X return posix_error(); X v = newtupleobject(10); X if (v == NULL) X return NULL; X#define SET(i, st_member) settupleitem(v, i, newintobject((long)st.st_member)) X SET(0, st_mode); X SET(1, st_ino); X SET(2, st_dev); X SET(3, st_nlink); X SET(4, st_uid); X SET(5, st_gid); X SET(6, st_size); X SET(7, st_atime); X SET(8, st_mtime); X SET(9, st_ctime); X#undef SET X if (err_occurred()) { X DECREF(v); X return NULL; X } X return v; X} X X X/* POSIX methods */ X Xstatic object * Xposix_chdir(self, args) X object *self; X object *args; X{ X extern int chdir PROTO((const char *)); X return posix_1str(args, chdir); X} X Xstatic object * Xposix_chmod(self, args) X object *self; X object *args; X{ X extern int chmod PROTO((const char *, mode_t)); X return posix_strint(args, chmod); X} X Xstatic object * Xposix_getcwd(self, args) X object *self; X object *args; X{ X char buf[1026]; X extern char *getcwd PROTO((char *, int)); X if (!getnoarg(args)) X return NULL; X if (getcwd(buf, sizeof buf) == NULL) X return posix_error(); X return newstringobject(buf); X} X Xstatic object * Xposix_link(self, args) X object *self; X object *args; X{ X extern int link PROTO((const char *, const char *)); X return posix_2str(args, link); X} X Xstatic object * Xposix_listdir(self, args) X object *self; X object *args; X{ X object *name, *d, *v; X DIR *dirp; X struct direct *ep; X if (!getstrarg(args, &name)) X return NULL; X if ((dirp = opendir(getstringvalue(name))) == NULL) X return posix_error(); X if ((d = newlistobject(0)) == NULL) { X closedir(dirp); X return NULL; X } X while ((ep = readdir(dirp)) != NULL) { X v = newstringobject(ep->d_name); X if (v == NULL) { X DECREF(d); X d = NULL; X break; X } X if (addlistitem(d, v) != 0) { X DECREF(v); X DECREF(d); X d = NULL; X break; X } X DECREF(v); X } X closedir(dirp); X return d; X} X Xstatic object * Xposix_mkdir(self, args) X object *self; X object *args; X{ X extern int mkdir PROTO((const char *, mode_t)); X return posix_strint(args, mkdir); X} X Xstatic object * Xposix_rename(self, args) X object *self; X object *args; X{ X extern int rename PROTO((const char *, const char *)); X return posix_2str(args, rename); X} X Xstatic object * Xposix_rmdir(self, args) X object *self; X object *args; X{ X extern int rmdir PROTO((const char *)); X return posix_1str(args, rmdir); X} X Xstatic object * Xposix_stat(self, args) X object *self; X object *args; X{ X extern int stat PROTO((const char *, struct stat *)); X return posix_do_stat(self, args, stat); X} X Xstatic object * Xposix_system(self, args) X object *self; X object *args; X{ X object *command; X int sts; X if (!getstrarg(args, &command)) X return NULL; X sts = system(getstringvalue(command)); X return newintobject((long)sts); X} X Xstatic object * Xposix_umask(self, args) X object *self; X object *args; X{ X int i; X if (!getintarg(args, &i)) X return NULL; X i = umask(i); X if (i < 0) X return posix_error(); X return newintobject((long)i); X} X Xstatic object * Xposix_unlink(self, args) X object *self; X object *args; X{ X extern int unlink PROTO((const char *)); X return posix_1str(args, unlink); X} X Xstatic object * Xposix_utimes(self, args) X object *self; X object *args; X{ X object *path; X struct timeval tv[2]; X if (args == NULL || !is_tupleobject(args) || gettuplesize(args) != 2) { X err_badarg(); X return NULL; X } X if (!getstrarg(gettupleitem(args, 0), &path) || X !getlonglongargs(gettupleitem(args, 1), X &tv[0].tv_sec, &tv[1].tv_sec)) X return NULL; X tv[0].tv_usec = tv[1].tv_usec = 0; X if (utimes(getstringvalue(path), tv) < 0) X return posix_error(); X INCREF(None); X return None; X} X X X#ifndef NO_LSTAT X Xstatic object * Xposix_lstat(self, args) X object *self; X object *args; X{ X extern int lstat PROTO((const char *, struct stat *)); X return posix_do_stat(self, args, lstat); X} X Xstatic object * Xposix_readlink(self, args) X object *self; X object *args; X{ X char buf[1024]; /* XXX Should use MAXPATHLEN */ X object *path; X int n; X if (!getstrarg(args, &path)) X return NULL; X n = readlink(getstringvalue(path), buf, sizeof buf); X if (n < 0) X return posix_error(); X return newsizedstringobject(buf, n); X} X Xstatic object * Xposix_symlink(self, args) X object *self; X object *args; X{ X extern int symlink PROTO((const char *, const char *)); X return posix_2str(args, symlink); X} X X#endif /* NO_LSTAT */ X X Xstatic struct methodlist posix_methods[] = { X {"chdir", posix_chdir}, X {"chmod", posix_chmod}, X {"getcwd", posix_getcwd}, X {"link", posix_link}, X {"listdir", posix_listdir}, X {"mkdir", posix_mkdir}, X {"rename", posix_rename}, X {"rmdir", posix_rmdir}, X {"stat", posix_stat}, X {"system", posix_system}, X {"umask", posix_umask}, X {"unlink", posix_unlink}, X {"utimes", posix_utimes}, X#ifndef NO_LSTAT X {"lstat", posix_lstat}, X {"readlink", posix_readlink}, X {"symlink", posix_symlink}, X#endif X {NULL, NULL} /* Sentinel */ X}; X X Xvoid Xinitposix() X{ X object *m, *d, *v; X X m = initmodule("posix", posix_methods); X d = getmoduledict(m); X X /* Initialize posix.environ dictionary */ X v = convertenviron(); X if (v == NULL || dictinsert(d, "environ", v) != 0) X fatal("can't define posix.environ"); X DECREF(v); X X /* Initialize posix.error exception */ X PosixError = newstringobject("posix.error"); X if (PosixError == NULL || dictinsert(d, "error", PosixError) != 0) X fatal("can't define posix.error"); X} EOF fi echo 'Part 11 out of 21 of pack.out complete.' exit 0