SmaCC__SmaCCParser.st
changeset 1 b8cca2663544
child 15 8b8cd1701c33
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SmaCC__SmaCCParser.st	Thu Apr 10 09:11:12 2008 +0000
@@ -0,0 +1,445 @@
+"{ Package: 'stx:goodies/smaCC' }"
+
+"{ NameSpace: SmaCC }"
+
+Object subclass:#SmaCCParser
+	instanceVariableNames:'scanner currentToken errorToken stateStack nodeStack'
+	classVariableNames:''
+	poolDictionaries:''
+	category:'SmaCC-Runtime'
+!
+
+SmaCCParser comment:'SmaCCParser is an abstract class that defines most of the parsing actions. Subclasses will define methods that specify their transitions and reduction actions. These are normally defined automatically when compiling the parser.
+
+Subclasses must implement the following messages:
+	accessing
+		emptySymbolTokenId
+		reduceTable
+		transitionTable
+
+Instance Variables:
+	currentToken	<SmaCCToken>	the token last returned by the scanner that has not been shifted (reduce actions leave the current token alone)
+	nodeStack	<OrderedCollection>	collection of items on stack. These items are specific to the parser and can be any object. 
+	scanner	<SmaCCScanner>	our scanner
+	stateStack	<OrderedCollection of: Integer>	the stack of states for our parser (standard LR state stack)
+
+'
+!
+
+
+!SmaCCParser class methodsFor:'instance creation'!
+
+new
+	^(super new)
+		initialize;
+		yourself
+!
+
+on: aStream 
+	| parser scanner |
+	scanner := self scannerClass on: aStream.
+	parser := self new.
+	parser scanner: scanner.
+	^parser
+! !
+
+!SmaCCParser class methodsFor:'accessing'!
+
+parse: aString 
+	^self parse: aString startingAt: self defaultStartingState
+!
+
+parse: aString onError: aBlock
+        ^[self parse: aString] on: SmaCCParserError
+                do: [:ex | 
+                    Smalltalk isSmalltalkX ifTrue:[
+                        ex return: (aBlock value: ex description value: ex parameter position)
+                    ].
+                    ex return: (aBlock value: ex description value: ex tag position)
+                ]
+!
+
+parse: aString startingAt: anInteger 
+	^self parseStream: (ReadStream on: aString) startingAt: anInteger
+!
+
+parse: aString startingAt: anInteger onError: aBlock
+        ^[self parse: aString startingAt: anInteger] on: SmaCCParserError
+                do: [:ex | 
+                    Smalltalk isSmalltalkX ifTrue:[
+                        ex return: (aBlock value: ex description value: ex parameter position)
+                    ].
+                    ex return: (aBlock value: ex description value: ex tag position)]
+!
+
+parseStream: aStream 
+	^self parseStream: aStream startingAt: self defaultStartingState
+!
+
+parseStream: aStream onError: aBlock
+        ^[self parseStream: aStream] on: SmaCCParserError
+                do: [:ex | 
+                    Smalltalk isSmalltalkX ifTrue:[
+                        ex return: (aBlock value: ex description value: ex parameter position)
+                    ].
+                    ex return: (aBlock value: ex description value: ex tag position)]
+!
+
+parseStream: aStream startingAt: anInteger 
+	| parser |
+	parser := self on: aStream.
+	parser setStartingState: anInteger.
+	^parser parse
+!
+
+parseStream: aStream startingAt: anInteger onError: aBlock
+        ^[self parseStream: aStream startingAt: anInteger] on: SmaCCParserError
+                do: [:ex | 
+                    Smalltalk isSmalltalkX ifTrue:[
+                        ex return: (aBlock value: ex description value: ex parameter position)
+                    ].
+                    ex return: (aBlock value: ex description value: ex tag position)]
+! !
+
+!SmaCCParser class methodsFor:'private'!
+
+defaultStartingState
+	^1
+!
+
+scannerClass
+	^self subclassResponsibility
+! !
+
+!SmaCCParser methodsFor:'accessing'!
+
+emptySymbolTokenId
+	^scanner emptySymbolTokenId
+!
+
+errorTable
+	^#()
+!
+
+errorTokenId
+	^scanner errorTokenId
+!
+
+parse
+	self setDefaultStartingStateIfNone.
+	self performParsingLoop.
+	^nodeStack last
+!
+
+position
+	^currentToken isNil 
+		ifTrue: [scanner position]
+		ifFalse: [currentToken startPosition]
+!
+
+reduceTable
+	^self subclassResponsibility
+!
+
+transitionTable
+	^self subclassResponsibility
+! !
+
+!SmaCCParser methodsFor:'initialize-release'!
+
+initialize
+	nodeStack := OrderedCollection new
+!
+
+scanner: aScanner 
+	scanner := aScanner
+!
+
+setStartingState: startingState 
+	stateStack := OrderedCollection with: startingState
+! !
+
+!SmaCCParser methodsFor:'private'!
+
+acceptAction
+	^0
+!
+
+actionFor: aSymbolIndex 
+	^self actionForState: self currentState and: aSymbolIndex
+!
+
+actionForCurrentToken
+	^self actionFor: currentToken id first
+!
+
+actionForState: stateIndex and: aSymbolIndex 
+	| index row |
+	row := self transitionTable at: stateIndex.
+	^(row at: 1) == 0 
+		ifTrue: 
+			[index := self 
+						binarySearchIn: row
+						for: aSymbolIndex
+						size: 2.
+			index == 0 
+				ifTrue: [^self errorAction]
+				ifFalse: [^((row at: 2) bitShift: 8) + (row at: 3)]]
+		ifFalse: 
+			[index := self 
+						binarySearchIn: row
+						for: aSymbolIndex
+						size: 4.
+			index == 0 
+				ifTrue: [^self errorAction]
+				ifFalse: [^((row at: index - 2) bitShift: 8) + (row at: index - 1)]]
+!
+
+actionMask
+	^2r11
+!
+
+binarySearchIn: aRow for: aSymbolIndex size: step 
+	| start mid length high low midItem stop |
+	high := aSymbolIndex bitShift: -8.
+	low := aSymbolIndex bitAnd: 16rFF.
+	start := 4.
+	stop := aRow size - 1.
+	length := (stop - start) // step.
+	[length > 4] whileTrue: 
+			[length := length bitShift: -1.
+			mid := length * step + start.
+			midItem := aRow at: mid.
+			((midItem == high and: [(aRow at: mid + 1) <= low]) or: [midItem < high]) 
+				ifTrue: [start := mid]
+				ifFalse: [stop := mid]].
+	[start <= stop] whileTrue: 
+			[((aRow at: start) == high and: [(aRow at: start + 1) == low]) 
+				ifTrue: [^start].
+			start := start + step].
+	^0
+!
+
+currentState
+	^stateStack last
+!
+
+errorAction
+	^3
+!
+
+findErrorHandlerIfNoneUseErrorNumber: anInteger 
+	| handlerStates index startingErrorToken newStack |
+	handlerStates := self errorHandlerStates reverse.
+	startingErrorToken := currentToken.
+	
+	[index := (1 to: handlerStates size) detect: 
+					[:each | 
+					| state |
+					state := handlerStates at: each.
+					state ~= 0 and: 
+							[newStack := stateStack copyFrom: 1 to: handlerStates size - each + 1.
+							newStack add: state.
+							self willShift: newStack]]
+				ifNone: [nil].
+	index isNil] 
+			whileTrue: 
+				[self dismissErrorToken.
+				currentToken id first = self emptySymbolTokenId 
+					ifTrue: 
+						[currentToken := startingErrorToken.
+						self reportError: anInteger]].
+	index - 1 timesRepeat: [self dismissStackTopForErrorRecovery].
+	stateStack addLast: (handlerStates at: index).
+	nodeStack addLast: startingErrorToken
+!
+
+getNextToken
+	currentToken isNil ifTrue: [currentToken := scanner next]
+!
+
+liftFirstValue: aCollection 
+	^aCollection first
+!
+
+liftLastValue: aCollection 
+	^aCollection last
+!
+
+liftSecondValue: aCollection 
+	^aCollection at: 2
+!
+
+performParsingLoop
+	| action actionType |
+	
+	[self getNextToken.
+	action := self actionForCurrentToken.
+	action = self acceptAction] 
+			whileFalse: 
+				[actionType := action bitAnd: self actionMask.
+				action := action bitShift: -2.
+				actionType == self shiftAction 
+					ifTrue: [self shift: action]
+					ifFalse: 
+						[actionType == self reduceAction 
+							ifTrue: [self reduce: action]
+							ifFalse: [self handleError: action]]].
+	self checkForErrors
+!
+
+performReduceMethod: aSymbol with: items 
+	^aSymbol last == $: 
+		ifTrue: [self perform: aSymbol with: items]
+		ifFalse: [self perform: aSymbol]
+!
+
+reduce: anInteger 
+	| reduceEntry items size |
+	reduceEntry := self reduceTable at: anInteger.
+	items := OrderedCollection new: (size := reduceEntry at: 2).
+	size timesRepeat: 
+			[items addFirst: nodeStack removeLast.
+			stateStack removeLast].
+	nodeStack add: (self performReduceMethod: (reduceEntry at: 3) with: items).
+	stateStack add: ((self actionFor: (reduceEntry at: 1)) bitShift: -2)
+!
+
+reduceAction
+	^2r10
+!
+
+reduceFor: aCollection 
+	| newCollection item |
+	(aCollection allSatisfy: [:each | each class ~~ OrderedCollection]) 
+		ifTrue: [^aCollection].
+	aCollection first class == OrderedCollection 
+		ifTrue: 
+			[newCollection := aCollection first.
+			2 to: aCollection size
+				do: 
+					[:i | 
+					item := aCollection at: i.
+					item class = OrderedCollection 
+						ifTrue: [newCollection addAll: item]
+						ifFalse: [newCollection add: item]].
+			^newCollection].
+	newCollection := OrderedCollection new.
+	aCollection do: 
+			[:each | 
+			each class == OrderedCollection 
+				ifTrue: [newCollection addAll: each]
+				ifFalse: [newCollection add: each]].
+	^newCollection
+!
+
+setDefaultStartingStateIfNone
+	stateStack isNil 
+		ifTrue: [self setStartingState: self class defaultStartingState]
+!
+
+shift: stateIndex 
+	stateStack add: stateIndex.
+	nodeStack add: currentToken.
+	currentToken := nil
+!
+
+shiftAction
+	^2r01
+! !
+
+!SmaCCParser methodsFor:'private-error handling'!
+
+checkForErrors
+	"If we have an error correction installed, we might have handled the errors. If we did, we don't 
+	want to return the result, so we raise a final exception that can't be proceeded."
+
+	errorToken isNil ifTrue: [^self].
+	currentToken := errorToken.
+	self reportErrorMessage: 'Token not expected'
+!
+
+dismissErrorToken
+	currentToken := nil.
+	self getNextToken
+!
+
+dismissStackTopForErrorRecovery
+	stateStack removeLast.
+	^nodeStack removeLast
+!
+
+errorHandlerStates
+	^stateStack collect: 
+			[:each | 
+			| action |
+			action := self actionForState: each and: self errorTokenId.
+			(action bitAnd: self actionMask) = 1 
+				ifTrue: [action bitShift: -2]
+				ifFalse: [0]]
+!
+
+handleError: anInteger 
+	errorToken isNil ifTrue: [errorToken := currentToken].
+	(currentToken id first = self emptySymbolTokenId 
+		or: [self hasErrorHandler not]) ifTrue: [self reportError: anInteger].
+	self findErrorHandlerIfNoneUseErrorNumber: anInteger
+!
+
+hasErrorHandler
+	^self errorHandlerStates anySatisfy: [:each | each ~~ 0]
+!
+
+reportError: anInteger 
+	self reportErrorMessage: (anInteger = 0 
+				ifTrue: ['Token not expected']
+				ifFalse: [self errorTable at: anInteger])
+!
+
+reportErrorMessage: aString
+        Smalltalk isSmalltalkX ifTrue:[
+            errorToken ifNotNil:[
+                | errorMessage |
+                errorMessage := ((errorToken value = '') and:[scanner stream atEnd])
+                                    ifTrue:['Unexpected end of file']
+                                    ifFalse:[aString , ': ' , errorToken value].
+                SmaCCParserError raiseSignal: errorMessage with: self
+            ] ifNil:[
+                SmaCCParserError raiseSignal: aString with:self
+            ]
+        ] ifFalse:[
+            SmaCCParserError signal: aString with: self
+        ]
+
+    "Modified: / 05-01-2007 / 13:04:48 / janfrog"
+!
+
+willShift: potentialStateStack 
+	| action compoundAction reduceEntry size |
+	compoundAction := self actionForState: potentialStateStack last
+				and: currentToken id first.
+	action := compoundAction bitAnd: self actionMask.
+	action == self shiftAction ifTrue: [^true].
+	action == self reduceAction 
+		ifTrue: 
+			[reduceEntry := self reduceTable at: (compoundAction bitShift: -2).
+			size := reduceEntry at: 2.
+			size timesRepeat: [potentialStateStack removeLast].
+			potentialStateStack 
+				add: ((self actionForState: potentialStateStack last
+						and: (reduceEntry at: 1)) bitShift: -2).
+			^self willShift: potentialStateStack].
+	^false
+! !
+
+!SmaCCParser methodsFor:'public'!
+
+isEOFToken
+	^currentToken id first = self emptySymbolTokenId
+! !
+
+!SmaCCParser class methodsFor:'documentation'!
+
+version
+    ^ '$Header: /opt/data/cvs/stx/goodies/smaCC/SmaCC__SmaCCParser.st,v 1.4 2007-01-05 15:16:41 vranyj1 Exp $'
+! !