"{ Package: 'stx:goodies/petitparser/compiler' }"
"{ NameSpace: Smalltalk }"
PPCConfiguration subclass:#PPCTokenizingConfiguration
instanceVariableNames:'scannerClazz parserClazz idGen'
classVariableNames:''
poolDictionaries:''
category:'PetitCompiler-Core'
!
!PPCTokenizingConfiguration methodsFor:'compiling'!
arguments: args
super arguments: args.
!
buildClass: clazz
| builder |
builder := PPCClassBuilder new.
builder compiledClassName: clazz name.
builder compiledSuperclass: clazz superclass.
builder methodDictionary: clazz methodDictionary.
builder constants: clazz constants.
^ builder compileClass.
!
invokePhases
self toPPCIr.
self createTokens.
self cacheFirstFollow.
self createLL1Choices.
self tokenize.
self merge.
self specialize.
self createRecognizingComponents.
self specialize.
self inline.
self merge.
self check.
self cacheFirstFollow.
self buildParserClazz.
self unmarkConsumeTokensForInline.
self createFSAs.
self buildScannerTokens.
self buildScannerScans.
self generateScanner.
self generateParser.
! !
!PPCTokenizingConfiguration methodsFor:'initialization'!
fillInClazzes
parserClazz name: arguments parserName.
parserClazz superclass: PPTokenizingCompiledParser.
scannerClazz name: arguments scannerName.
scannerClazz superclass: arguments scannerSuperclass.
!
initialize
super initialize.
parserClazz := PPCClass new.
scannerClazz := PPCClass new.
idGen := PPCIdGenerator new.
"The parser and scanner share the same id generator in order
to use same names for tokens.
"
parserClazz idGen: idGen.
scannerClazz idGen: idGen.
! !
!PPCTokenizingConfiguration methodsFor:'phases'!
buildParserClazz
| rootMethod |
rootMethod := PPCTokenizingCodeGenerator new
clazz: parserClazz;
arguments: arguments;
visit: ir.
parserClazz propertyAt: #rootMethod put: rootMethod
!
buildScannerScans
| fsas generator |
"TODO JK: Perhpas write separate visitor for this?"
fsas := IdentitySet new.
fsas addAll: (ir allNodes select: [ :node | node hasFsa ] thenCollect: [:node | node fsa]).
fsas addAll: (ir allNodes select: [ :node | node hasNextFsa ] thenCollect: [:node | node nextFsa]).
fsas := fsas reject: [ :fsa | fsa hasDistinctRetvals not ].
generator := PPCScannerCodeGenerator new
clazz: scannerClazz;
arguments: arguments;
yourself.
fsas do: [ :fsa | generator generate: fsa ].
!
buildScannerTokens
| generator |
generator := PPCTokenCodeGenerator new
clazz: scannerClazz;
arguments: arguments;
yourself.
generator visit: ir.
!
createFSAs
ir := PPCFSAVisitor new
idGen: idGen;
visit: ir.
self remember: (self copyTree: ir) as: #withFSAs
!
createLL1Choices
self flag: 'This phase needs revisit and update'.
ir := PPCLL1Visitor new
arguments: arguments;
visit: ir.
self remember: (self copyTree: ir) as: #LL1
!
generateParser
| parserClass rootMethod |
arguments generate ifFalse: [ ^ self ].
rootMethod := parserClazz propertyAt: #rootMethod.
parserClazz name: arguments parserName.
parserClazz superclass: arguments parserSuperclass.
parserClass := self buildClass: parserClazz.
parserClass startSymbol: rootMethod methodName.
self remember: parserClass as: #parser.
ir := parserClass new
!
generateScanner
| scanner |
arguments generate ifFalse: [ ^ self ].
scannerClazz name: arguments scannerName.
scannerClazz superclass: arguments scannerSuperclass.
scanner := (self buildClass: scannerClazz).
parserClazz addConstant: scanner as: #scannerClass.
ir := scanner.
self remember: scanner as: #scanner
!
tokenize
"
This will try transform the parser into the tokenizing parser
"
arguments tokenize ifFalse: [ ^ self ] .
ir := PPCTokenizingVisitor new
arguments: arguments;
visit: ir.
self remember: (self copyTree: ir) as: #tokenize
!
unmarkConsumeTokensForInline
"TODO JK: Hack alert, use visitor, or at leas isTokenConsume"
ir allNodesDo: [ :node |
node class == PPCTokenConsumeNode ifTrue: [
node unmarkForInline
]
]
! !