--- a/compiler/PPCScannerCodeGenerator.st Tue Aug 18 22:46:10 2015 +0100
+++ b/compiler/PPCScannerCodeGenerator.st Mon Aug 24 15:56:20 2015 +0100
@@ -3,22 +3,13 @@
"{ NameSpace: Smalltalk }"
Object subclass:#PPCScannerCodeGenerator
- instanceVariableNames:'codeGen fsa backlinkStates backlinkTransitions arguments openSet
- incommingTransitions methodCache id resultStrategy fsaCache'
+ instanceVariableNames:'codeGen fsa arguments incommingTransitions resultStrategy
+ fsaCache'
classVariableNames:''
poolDictionaries:''
category:'PetitCompiler-Scanner'
!
-
-!PPCScannerCodeGenerator class methodsFor:'instance creation'!
-
-new
- "return an initialized instance"
-
- ^ self basicNew initialize.
-! !
-
!PPCScannerCodeGenerator methodsFor:'accessing'!
arguments
@@ -26,7 +17,8 @@
!
arguments: anObject
- arguments := anObject
+ arguments := anObject.
+ codeGen arguments: anObject.
!
codeGen
@@ -39,26 +31,24 @@
!PPCScannerCodeGenerator methodsFor:'analysis'!
-analyzeBacklinks
- backlinkTransitions := fsa backTransitions.
- backlinkStates := IdentityDictionary new.
-
- backlinkTransitions do: [ :t |
- (self backlinksTo: (t destination)) add: t.
- ].
-!
-
analyzeDistinctRetvals
- (fsa hasDistinctRetvals) ifTrue: [
- resultStrategy := PPCDistinctResultStrategy new
+ (fsa hasNoRetvals) ifTrue: [
+ ^ resultStrategy := PPCNoResultStrategy new
codeGen: codeGen;
yourself
- ] ifFalse: [
- resultStrategy := PPCUniversalResultStrategy new
+ ].
+
+
+ (fsa hasDistinctRetvals) ifTrue: [
+ ^ resultStrategy := PPCDistinctResultStrategy new
codeGen: codeGen;
- tokens: fsa retvals asArray;
yourself
- ]
+ ].
+
+ resultStrategy := PPCUniversalResultStrategy new
+ codeGen: codeGen;
+ tokens: fsa retvals asArray;
+ yourself
!
analyzeTransitions
@@ -72,8 +62,8 @@
].
!
-backlinksTo: state
- ^ backlinkStates at: state ifAbsentPut: [ OrderedCollection new ]
+clazz: aPPCClass
+ codeGen clazz: aPPCClass
!
containsBacklink: state
@@ -92,12 +82,23 @@
^ incommingTransitions at: state ifAbsentPut: [ IdentitySet new ]
!
-isBacklink: transition
- ^ backlinkTransitions includes: transition
+isSingleTerminatingRetval: state
+ (state retvals size == 1 and: [ state isFinal ]) ifFalse: [ ^ false ].
+
+ state transitions isEmpty ifTrue: [ ^ true ].
+ ((state transitions size == 1) and: [state destination == state]) ifTrue: [ ^ self startsSimpleLoop: state ].
+
+ ^ false
!
-isBacklinkDestination: state
- ^ (self backlinksTo: state) isEmpty not
+isSingleTransitionFsa
+ fsa allTransitions size == 1 ifFalse: [ ^ false ].
+ "do not allow loop!!"
+ fsa startState destination == fsa startState ifTrue: [ ^ false ].
+ "so far only single char allowed"
+ fsa startState transition isCharacterTransition ifFalse: [ ^ false ].
+ fsa startState transition isSingleCharacter ifFalse: [ ^ false ].
+ ^ true
!
startsSimpleLoop: state
@@ -115,7 +116,7 @@
!PPCScannerCodeGenerator methodsFor:'caching'!
cache: anFsa method: method
- fsaCache at: anFsa put: method
+ ^ fsaCache at: anFsa put: method
!
cachedValueForIsomorphicFsa: anFsa
@@ -125,37 +126,33 @@
!
isomorphicIsCached: anFsa
- ^ fsaCache keys anySatisfy: [ :e | e isIsomorphicTo: anFsa ]
+ ^ fsaCache keys anySatisfy: [ :e | (e isIsomorphicTo: anFsa) and: [ e name = anFsa name ] ]
! !
!PPCScannerCodeGenerator methodsFor:'code generation'!
generate
- | method |
self assert: fsa isDeterministic.
self assert: fsa isWithoutEpsilons.
self assert: fsa checkConsistency.
(self isomorphicIsCached: fsa) ifTrue: [
+ "JK: please not, right now, checks for isomorphism and name
+ this might be improved in future and name can be 'reused'
+ "
^ self cachedValueForIsomorphicFsa: fsa
].
- self analyzeBacklinks.
self analyzeTransitions.
self analyzeDistinctRetvals.
- openSet := IdentitySet new.
codeGen startMethod: (codeGen idFor: fsa).
- codeGen codeComment: (Character codePoint: 13) asString, fsa asString.
+" codeGen codeComment: (Character codePoint: 13) asString, fsa asString."
resultStrategy reset.
self generateFor: fsa startState.
- method := codeGen stopMethod.
- self cache: fsa method: method.
-
- ^ method.
-
+ ^ self cache: fsa method: codeGen stopMethod.
!
@@ -191,6 +188,16 @@
!
generateFinalFor: state offset: offset
+ "Handle one retval specially"
+ (self isSingleTerminatingRetval: state) ifTrue: [
+ state isFsaFailure ifTrue: [
+ resultStrategy returnFailure: state retval offset: offset.
+ ] ifFalse: [
+ resultStrategy returnMatch: state retval offset: offset.
+ ].
+ ^ self
+ ].
+
state retvalsAndInfosDo: [:retval :info |
info isFinal ifTrue: [
info isFsaFailure ifTrue: [
@@ -203,12 +210,26 @@
!
generateFor: state
- codeGen cachedValue: (codeGen idFor: state) ifPresent: [ :method |
+ codeGen cachedMethod: (codeGen idFor: state) ifPresent: [ :method |
"if state is already cached, it has multiple incomming links.
In such a case, it is compiled as a method, thus return immediatelly"
^ codeGen codeAbsoluteReturn: method call
].
+ self flag: 'TODO JK: Hack alert, fix this:'.
+ (state isKindOf: PEGFsaParserState) ifTrue: [
+ | id |
+ self assert: state transitions isEmpty.
+ id := codeGen idFor: state parser defaultName: 'parser'.
+ codeGen addConstant: state parser as: id.
+ codeGen code: id, ' parseOn: context'.
+ ^ self
+ ].
+
+ (self isSingleTransitionFsa) ifTrue: [
+ ^ self generateForSingleTransitionFsa: state.
+ ].
+
(self startsSimpleLoop: state) ifTrue: [
^ self generateSimpleLoopFor: state
].
@@ -216,29 +237,31 @@
^ self generateStandardFor: state
!
-generateForSingleTransition: t from: state
+generateForSingleTransitionFsa: startState
+ | transition |
+ self assert: fsa startState == startState.
- (self isJoinPoint: t destination) ifTrue: [ self removeJoinTransition: t ].
+ transition := startState transition.
- codeGen codeAssertPeek: t ifFalse: [
- resultStrategy returnResult: state
- ].
-" (self isBacklink: t) ifTrue: [
- codeGen add: 'true'
+ transition isSingleCharacter ifTrue: [
+ codeGen codeIf: 'context peek == ', transition character storeString then: [
+ codeGen code: 'self step'; codeDot.
+ self generateFinalFor: transition destination.
+ ].
+ codeGen codeReturn: 'false'.
] ifFalse: [
- self generateFor: t destination.
+ self error: 'should be implemented'
]
-"
- self generateFor: t destination
!
generateForTransition: t from: state
-" (self isBacklink: t) ifTrue: [
+"
+ (self isBacklink: t) ifTrue: [
codeGen codeAssertPeek: (t characterSet) ifTrue: [
codeGen add: 'true'
]
] ifFalse: [
- codeGen codeAssertPeek: (t characterSet) ifTrue: [.
+ codeGen codeAssertPeek: (t characterSet) ifTrue: [
self generateFor: t destination.
].
].
@@ -255,8 +278,12 @@
!
generateReturnFor: state
- codeGen codeNl.
- resultStrategy returnResult: state.
+" codeGen codeNl."
+ (self isSingleTerminatingRetval: state) ifFalse: [
+ resultStrategy returnResult: state.
+ ] ifTrue: [
+ "return already generated within the match"
+ ]
!
generateSimpleLoopFor: state
@@ -271,7 +298,9 @@
"Last transition did not passed the loop, therefore, we have to record succes with offset -1"
self generateFinalFor: state offset: 1.
- self generateTransitions: (state transitions reject: [ :t | t == selfTransition ]) for: state.
+ self generateTransitions: (state transitions reject: [ :t | t == selfTransition ])
+ for: state
+ offset: 1.
!
@@ -285,6 +314,7 @@
!
generateStartMethod: state
+ | id |
id := codeGen idFor: state.
codeGen codeComment: 'START - Generated from state: ', state asString.
@@ -306,19 +336,18 @@
codeGen codeComment: 'STOP - Generated from state: ', state asString.
!
-generateTransitions: transitions for: state
+generateTransitions: transitions for: state offset: offset
(transitions size = 0) ifTrue: [
- self generateReturnFor: state.
+ (offset > 0 and: [ state isFinal not ]) ifTrue: [
+ codeGen codeIf: 'currentChar isNil' then: nil else: [
+ codeGen codeOnLine: 'context skip: -', offset asString
+ ].
+ ].
^ self
].
-" (state transitions size = 1) ifTrue: [
- self generateForSingleTransition: state transitions anyOne from: state.
- ^ self
- ]."
-
- codeGen codeNl.
- transitions do: [ :t |
+" codeGen codeNl.
+" transitions do: [ :t |
self generateForTransition: t from: state
].
@@ -326,8 +355,8 @@
self generateReturnFor: state.
codeGen dedent.
codeGen codeNl.
- transitions size timesRepeat: [ codeGen addOnLine: ']' ].
- codeGen addOnLine: '.'.
+ transitions size timesRepeat: [ codeGen codeOnLine: ']' ].
+ codeGen codeDot.
" self closedJoinPoints isEmpty ifFalse: [
@@ -342,7 +371,7 @@
!
generateTransitionsFor: state
- ^ self generateTransitions: state transitions for: state
+ ^ self generateTransitions: state transitions for: state offset: 0
!
setMaxNumericId
@@ -374,9 +403,9 @@
builder := PPCClassBuilder new.
builder compiledClassName: arguments scannerName.
- builder compiledSuperclass: PPCScanner.
- builder methodDictionary: codeGen methodDictionary.
- builder constants: codeGen constants.
+ builder compiledSuperclass: arguments scannerSuperclass.
+ builder methodDictionary: codeGen clazz methodDictionary.
+ builder constants: codeGen clazz constants.
^ builder compileClass.
! !
@@ -391,10 +420,3 @@
fsaCache := IdentityDictionary new.
! !
-!PPCScannerCodeGenerator class methodsFor:'documentation'!
-
-version_HG
-
- ^ '$Changeset: <not expanded> $'
-! !
-