compiler/PPCScannerCodeGenerator.st
changeset 502 1e45d3c96ec5
child 503 ff58cd9f1f3c
child 515 b5316ef15274
equal deleted inserted replaced
464:f6d77fee9811 502:1e45d3c96ec5
       
     1 "{ Package: 'stx:goodies/petitparser/compiler' }"
       
     2 
       
     3 "{ NameSpace: Smalltalk }"
       
     4 
       
     5 Object subclass:#PPCScannerCodeGenerator
       
     6 	instanceVariableNames:'codeGen fsa backlinkStates backlinkTransitions arguments openSet
       
     7 		joinPoints incommingTransitions methodCache id'
       
     8 	classVariableNames:''
       
     9 	poolDictionaries:''
       
    10 	category:'PetitCompiler-Scanner'
       
    11 !
       
    12 
       
    13 !PPCScannerCodeGenerator methodsFor:'accessing'!
       
    14 
       
    15 arguments
       
    16     ^ arguments 
       
    17 !
       
    18 
       
    19 arguments: anObject
       
    20     arguments := anObject
       
    21 ! !
       
    22 
       
    23 !PPCScannerCodeGenerator methodsFor:'analysis'!
       
    24 
       
    25 analyzeBacklinks
       
    26     backlinkTransitions := fsa backTransitions.
       
    27     backlinkStates := IdentityDictionary new.
       
    28     
       
    29     backlinkTransitions do: [ :t |
       
    30         (self backlinksTo: (t destination)) add: t.
       
    31     ].
       
    32 !
       
    33 
       
    34 analyzeJoinPoints
       
    35     | joinTransitions |
       
    36     joinTransitions := fsa joinTransitions.
       
    37     joinTransitions := joinTransitions reject: [ :t | self isBacklinkDestination: t destination ].
       
    38     joinPoints := IdentityDictionary new.
       
    39     
       
    40     joinTransitions do: [ :t |
       
    41         (joinPoints at: t destination ifAbsentPut: [ IdentitySet new ]) add: t.
       
    42     ]
       
    43     
       
    44 !
       
    45 
       
    46 analyzeTransitions
       
    47     | transitions |
       
    48     transitions := fsa allTransitions.
       
    49     incommingTransitions := IdentityDictionary new.
       
    50     (self incommingTransitionsFor: fsa startState) add: #transitionStub.
       
    51     
       
    52     transitions do: [ :t |
       
    53         (self incommingTransitionsFor: t destination) add: t.
       
    54     ].
       
    55 !
       
    56 
       
    57 backlinksTo: state
       
    58     ^ backlinkStates at: state ifAbsentPut: [ OrderedCollection new ] 
       
    59 !
       
    60 
       
    61 closedJoinPoints
       
    62     | closed |
       
    63     closed := IdentitySet new.
       
    64     
       
    65     joinPoints keysAndValuesDo: [ :key :value | 
       
    66         value isEmpty ifTrue: [ closed add: key ].
       
    67     ].
       
    68 
       
    69     ^ closed
       
    70 !
       
    71 
       
    72 containsBacklink: state
       
    73     state transitions do: [ :t |
       
    74         (self isBacklink:  t) ifTrue: [ ^ true ]
       
    75     ].
       
    76 
       
    77     ^ false
       
    78 !
       
    79 
       
    80 hasMultipleIncommings: state
       
    81     ^ (incommingTransitions at: state ifAbsent: [ self error: 'should not happen']) size > 1
       
    82 !
       
    83 
       
    84 incommingTransitionsFor: state
       
    85     ^ incommingTransitions  at: state ifAbsentPut: [ IdentitySet new ]
       
    86 !
       
    87 
       
    88 isBacklink: transition
       
    89     ^ backlinkTransitions includes: transition
       
    90 !
       
    91 
       
    92 isBacklinkDestination: state
       
    93     ^ (self backlinksTo: state)  isEmpty not
       
    94 !
       
    95 
       
    96 isJoinPoint: state
       
    97     "Please note that joinPoints are removed as the compilaction proceeds"
       
    98     ^ joinPoints keys includes: state
       
    99 !
       
   100 
       
   101 joinTransitionsTo: joinPoint "state"
       
   102     ^ joinPoints at: joinPoint ifAbsent: [ #() ]
       
   103 ! !
       
   104 
       
   105 !PPCScannerCodeGenerator methodsFor:'code generation'!
       
   106 
       
   107 generate
       
   108     self assert: fsa isDeterministic.
       
   109     self assert: fsa isWithoutEpsilons.
       
   110     self assert: fsa checkConsistency.
       
   111 
       
   112 
       
   113     self analyzeBacklinks.
       
   114     self analyzeJoinPoints.
       
   115     self analyzeTransitions.
       
   116     
       
   117     openSet := IdentitySet new.
       
   118     
       
   119     codeGen startMethod: (codeGen idFor: fsa).
       
   120     codeGen codeComment: (Character codePoint: 13) asString, fsa asString.
       
   121 
       
   122     self generateFor: fsa startState.
       
   123 
       
   124     codeGen stopMethod.	
       
   125         
       
   126     ^ self compileScannerClass new
       
   127 
       
   128 
       
   129 !
       
   130 
       
   131 generate: aPEGFsa
       
   132     fsa := aPEGFsa.
       
   133 
       
   134     fsa compact.
       
   135     fsa checkSanity.
       
   136     
       
   137     ^ self generate
       
   138 !
       
   139 
       
   140 generateFinalFor: state
       
   141     state isFinal ifFalse: [  ^ self ].
       
   142 
       
   143     codeGen codeRecordMatch: state retval priority: state priority.
       
   144 !
       
   145 
       
   146 generateFor: state
       
   147 "	(self isJoinPoint: state) ifTrue: [ 
       
   148         ^ codeGen codeComment: 'join point generation postponed...'
       
   149     ].
       
   150 "
       
   151     codeGen cachedValue: (codeGen idFor: state) ifPresent: [ :method | 
       
   152         "if state is already cached, it has multiple incomming links.
       
   153      	 In such a case, it is compiled as a method, thus return immediatelly"
       
   154         ^ codeGen codeAbsoluteReturn:  method call
       
   155     ].
       
   156 
       
   157     self generateStartMethod: state.
       
   158 "	(self isBacklinkDestination: state) ifTrue: [ 
       
   159         codeGen codeStartBlock.
       
   160     ].
       
   161 "
       
   162     self generateFinalFor: state.
       
   163     self generateNextFor: state.
       
   164     self generateTransitionsFor: state.
       
   165 
       
   166 "	(self isBacklinkDestination: state) ifTrue: [ 
       
   167         codeGen codeEndBlockWhileTrue.
       
   168     ].
       
   169 "
       
   170     self generateStopMethod: state.
       
   171 !
       
   172 
       
   173 generateForSingleTransition: t from: state.
       
   174     
       
   175     (self isJoinPoint: t destination) ifTrue: [ self removeJoinTransition: t ].
       
   176     
       
   177     codeGen codeAssertPeek: (t characterSet) orReturn: state priority.
       
   178 "	(self isBacklink: t) ifTrue: [ 
       
   179         codeGen add: 'true'
       
   180     ] ifFalse: [ 
       
   181         self generateFor: t destination.
       
   182     ]
       
   183 "
       
   184     self generateFor: t destination
       
   185 !
       
   186 
       
   187 generateForTransition: t from: state	
       
   188     (self isJoinPoint: t destination) ifTrue: [ self removeJoinTransition: t   ].
       
   189     
       
   190 "	(self isBacklink: t) ifTrue: [ 
       
   191         codeGen codeAssertPeek: (t characterSet) ifTrue: [ 
       
   192             codeGen add: 'true'
       
   193         ]
       
   194     ] ifFalse: [ 
       
   195         codeGen codeAssertPeek: (t characterSet) ifTrue: [.
       
   196             self generateFor: t destination.
       
   197         ].
       
   198     ].
       
   199 "
       
   200     codeGen codeAssertPeek: (t characterSet) ifTrue: [.
       
   201         self generateFor: t destination.
       
   202     ].
       
   203     codeGen codeIfFalse.
       
   204 !
       
   205 
       
   206 generateNextFor: state
       
   207     state transitions isEmpty ifTrue: [  ^ self ].
       
   208     codeGen codeNextChar.
       
   209 !
       
   210 
       
   211 generateReturnFor: state
       
   212     codeGen codeNlReturnResult: state priority.
       
   213 !
       
   214 
       
   215 generateStartMethod: state.
       
   216     id := codeGen idFor: state.
       
   217 
       
   218     codeGen codeComment: 'START - Generated from state: ', state asString.
       
   219 
       
   220     (self hasMultipleIncommings: state) ifTrue: [ 
       
   221         codeGen startMethod: id.
       
   222     ] ifFalse: [ 
       
   223         codeGen  startInline: id.
       
   224     ]
       
   225 !
       
   226 
       
   227 generateStopMethod: state
       
   228     |  |
       
   229     (self hasMultipleIncommings: state) ifTrue: [ 
       
   230         codeGen codeAbsoluteReturn: codeGen stopMethod call.
       
   231     ] ifFalse: [ 
       
   232         codeGen code: codeGen stopInline call.
       
   233     ].
       
   234     codeGen codeComment: 'STOP - Generated from state: ', state asString.
       
   235 !
       
   236 
       
   237 generateTransitionsFor: state
       
   238     (state transitions size = 0) ifTrue: [  
       
   239         self generateReturnFor: state.
       
   240         ^ self	
       
   241     ].
       
   242 
       
   243     (state transitions size = 1) ifTrue: [  
       
   244         self generateForSingleTransition: state transitions anyOne from: state.
       
   245         ^ self
       
   246     ].
       
   247 
       
   248 
       
   249     codeGen codeNl.
       
   250     state transitions do: [ :t |
       
   251         self generateForTransition: t from: state
       
   252     ].
       
   253 
       
   254     codeGen indent.
       
   255     self generateReturnFor: state.
       
   256     codeGen dedent.
       
   257     codeGen codeNl.
       
   258     state transitions size timesRepeat: [ codeGen addOnLine: ']' ].
       
   259     codeGen addOnLine: '.'.
       
   260     
       
   261 
       
   262 "	self closedJoinPoints isEmpty ifFalse: [ 
       
   263         | jp |
       
   264         self assert: self closedJoinPoints size == 1.
       
   265 
       
   266         jp := self closedJoinPoints anyOne.
       
   267         self removeJoinPoint: jp.
       
   268         self generateFor: jp.
       
   269     ]
       
   270 "
       
   271 ! !
       
   272 
       
   273 !PPCScannerCodeGenerator methodsFor:'compiling'!
       
   274 
       
   275 compileScannerClass
       
   276     | builder |
       
   277     builder := PPCClassBuilder new.
       
   278     
       
   279     builder compiledClassName: arguments scannerName.
       
   280     builder compiledSuperclass: PPCScanner.
       
   281     builder methodDictionary: codeGen methodDictionary.
       
   282     builder constants: codeGen constants.
       
   283 
       
   284     ^ builder compileClass.	
       
   285 ! !
       
   286 
       
   287 !PPCScannerCodeGenerator methodsFor:'initialization'!
       
   288 
       
   289 initialize
       
   290     super initialize.
       
   291     
       
   292     codeGen := PPCFSACodeGen new.
       
   293     arguments := PPCArguments default.
       
   294 ! !
       
   295 
       
   296 !PPCScannerCodeGenerator methodsFor:'support'!
       
   297 
       
   298 removeJoinPoint: state
       
   299     self assert: (joinPoints at: state) size = 0.
       
   300     joinPoints removeKey: state
       
   301 !
       
   302 
       
   303 removeJoinTransition: t
       
   304     (self joinTransitionsTo: t destination) remove: t ifAbsent: [ self error: 'this should not happen' ].
       
   305 ! !
       
   306