@@ -15,8 +15,8 @@ open FSharp.Text.Lexing
15
15
let (| KeyValue |) ( kvp : KeyValuePair < _ , _ >) = kvp.Key, kvp.Value
16
16
17
17
18
- type Identifier = string
19
- type Code = string * Position
18
+ type Identifier = string * Range
19
+ type Code = string * Range
20
20
type Associativity = LeftAssoc | RightAssoc | NonAssoc
21
21
type Rule = Rule of Identifier list * Identifier option * Code option
22
22
@@ -29,16 +29,16 @@ type ParserSpec=
29
29
Rules : ( Identifier * Rule list ) list }
30
30
31
31
32
- type Terminal = string
33
- type NonTerminal = string
32
+ type Terminal = string * Range
33
+ type NonTerminal = string * Range
34
34
type Symbol = Terminal of Terminal | NonTerminal of NonTerminal
35
35
type Symbols = Symbol list
36
36
37
37
38
38
//---------------------------------------------------------------------
39
39
// Output Raw Parser Spec AST
40
40
41
- let StringOfSym sym = match sym with Terminal s -> " '" ^ s ^ " '" | NonTerminal s -> s
41
+ let StringOfSym sym = match sym with Terminal ( name , range ) -> " '" ^ name ^ " '" | NonTerminal ( name , range ) -> name
42
42
43
43
let OutputSym os sym = fprintf os " %s " ( StringOfSym sym)
44
44
@@ -77,14 +77,14 @@ let ProcessParserSpecAst (spec: ParserSpec) =
77
77
|> List.mapi ( fun n precSpecs -> precSpecs |> List.map ( fun ( precSym , assoc ) -> precSym, ExplicitPrec ( assoc, 9999 - n)))
78
78
|> List.concat
79
79
80
- for ( key,_) in explicitPrecInfo |> Seq.countBy fst |> Seq.filter ( fun ( _ , n ) -> n > 1 ) do
80
+ for (( key,_) ,_) in explicitPrecInfo |> Seq.countBy fst |> Seq.filter ( fun ( _ , n ) -> n > 1 ) do
81
81
failwithf " %s is given two associativities" key
82
82
83
83
let explicitPrecInfo =
84
84
explicitPrecInfo |> Map.ofList
85
85
86
86
let implicitSymPrecInfo = NoPrecedence
87
- let terminals = List.map fst spec.Tokens @ [ " error" ]
87
+ let terminals = List.map fst spec.Tokens @ [ " error" , Range.Empty ]
88
88
let terminalSet = Set.ofList terminals
89
89
let IsTerminal z = terminalSet.Contains( z)
90
90
let prec_of_terminal sym implicitPrecInfo =
@@ -96,7 +96,9 @@ let ProcessParserSpecAst (spec: ParserSpec) =
96
96
spec.Rules |> List.mapi ( fun i ( nonterm , rules ) ->
97
97
rules |> List.mapi ( fun j ( Rule ( syms , precsym , code )) ->
98
98
let precInfo =
99
- let precsym = List.foldBack ( fun x acc -> match acc with Some _ -> acc | None -> match x with z when IsTerminal z -> Some z | _ -> acc) syms precsym
99
+ let precsym =
100
+ ( syms, precsym)
101
+ ||> List.foldBack ( fun x acc -> match acc with Some _ -> acc | None -> match x with z when IsTerminal z -> Some z | _ -> acc)
100
102
let implicitPrecInfo = NoPrecedence
101
103
match precsym with
102
104
| None -> implicitPrecInfo
@@ -105,19 +107,19 @@ let ProcessParserSpecAst (spec: ParserSpec) =
105
107
|> List.concat
106
108
let nonTerminals = List.map fst spec.Rules
107
109
let nonTerminalSet = Set.ofList nonTerminals
108
- let checkNonTerminal nt =
109
- if nt <> " error" && not ( nonTerminalSet.Contains( nt)) then
110
- failwith ( sprintf " NonTerminal '%s ' has no productions" nt )
110
+ let checkNonTerminal (( name , range ) as nt ) =
111
+ if name <> " error" && not ( nonTerminalSet.Contains( nt)) then
112
+ failwith ( sprintf " NonTerminal '%s '( %d , %d )-( %d , %d ) has no productions" name range.startPos.Line range.startPos.Column range.endPos.Line range.endPos.Column )
111
113
112
114
for ( Production( nt,_, syms,_)) in prods do
113
115
for sym in syms do
114
116
match sym with
115
117
| NonTerminal nt ->
116
118
checkNonTerminal nt
117
- | Terminal t ->
118
- if not ( IsTerminal t) then failwith ( sprintf " token %s is not declared" t )
119
+ | Terminal ( name , range ) as t ->
120
+ if not ( IsTerminal t) then failwith ( sprintf " token %s is not declared" name )
119
121
120
- if spec.StartSymbols= [] then ( failwith " at least one % s tart declaration is required" );
122
+ if spec.StartSymbols = [] then ( failwith " at least one start declaration is required" );
121
123
122
124
for ( nt,_) in spec.Types do
123
125
checkNonTerminal nt;
@@ -242,7 +244,7 @@ type NonTerminalTable(nonTerminals:NonTerminal list) =
242
244
let nonterminalsWithIdxs = List.mapi ( fun ( i : NonTerminalIndex ) n -> ( i, n)) nonTerminals
243
245
let nonterminalIdxs = List.map fst nonterminalsWithIdxs
244
246
let a = Array.ofList nonTerminals
245
- let b = CreateDictionary [ for i, x in nonterminalsWithIdxs -> x , i ];
247
+ let b = CreateDictionary [ for i,( name , range ) in nonterminalsWithIdxs -> name , i ];
246
248
member table.OfIndex ( i ) = a.[ i]
247
249
member table.ToIndex ( i ) = b.[ i]
248
250
member table.Indexes = nonterminalIdxs
@@ -253,30 +255,30 @@ type TerminalTable(terminals:(Terminal * PrecedenceInfo) list) =
253
255
let terminalIdxs = List.map fst terminalsWithIdxs
254
256
let a = Array.ofList ( List.map fst terminals)
255
257
let b = Array.ofList ( List.map snd terminals)
256
- let c = CreateDictionary [ for i, x in terminalsWithIdxs -> x , i ]
258
+ let c = CreateDictionary [ for i, ( name , range ) in terminalsWithIdxs -> name , i ]
257
259
258
260
member table.OfIndex ( i ) = a.[ i]
259
261
member table.PrecInfoOfIndex ( i ) = b.[ i]
260
262
member table.ToIndex ( i ) = c.[ i]
261
263
member table.Indexes = terminalIdxs
262
264
263
265
/// Allocate indexes for each production
264
- type ProductionTable ( ntTab : NonTerminalTable , termTab : TerminalTable , nonTerminals : string list, prods : Production list ) =
266
+ type ProductionTable ( ntTab : NonTerminalTable, termTab : TerminalTable, nonTerminals : NonTerminal list, prods : Production list ) =
265
267
let prodsWithIdxs = List.mapi ( fun i n -> ( i, n)) prods
266
268
let a =
267
269
prodsWithIdxs
268
270
|> List.map( fun ( _ , Production ( _ , _ , syms , _ )) ->
269
271
syms
270
272
|> Array.ofList
271
273
|> Array.map ( function
272
- | Terminal t -> PTerminal ( termTab.ToIndex t )
273
- | NonTerminal nt -> PNonTerminal ( ntTab.ToIndex nt )) )
274
+ | Terminal ( name , _) -> PTerminal ( termTab.ToIndex name )
275
+ | NonTerminal ( name , _) -> PNonTerminal ( ntTab.ToIndex name )) )
274
276
|> Array.ofList
275
- let b = Array.ofList ( List.map ( fun ( _ , Production ( nt , _ , _ , _ )) -> ntTab.ToIndex nt ) prodsWithIdxs)
277
+ let b = Array.ofList ( List.map ( fun ( _ , Production (( name , _ ) ,_ , _ , _ )) -> ntTab.ToIndex name ) prodsWithIdxs)
276
278
let c = Array.ofList ( List.map ( fun ( _ , Production ( _ , prec , _ , _ )) -> prec) prodsWithIdxs)
277
279
let productions =
278
280
nonTerminals
279
- |> List.map( fun nt -> ( ntTab.ToIndex nt , List.choose ( fun ( i , Production ( nt2 , prec , syms , _ )) -> if nt2 = nt then Some i else None) prodsWithIdxs))
281
+ |> List.map( fun ( name1 , range1 ) -> ( ntTab.ToIndex name1 , List.choose ( fun ( i , Production (( name2 , range2 ), prec , syms , _ )) -> if name2 = name1 then Some i else None) prodsWithIdxs))
280
282
|> CreateDictionary
281
283
282
284
member prodTab.Symbols ( i ) = a.[ i]
@@ -357,7 +359,7 @@ type CompiledSpec =
357
359
gotoTable: int option [] []
358
360
endOfInputTerminalIdx: int
359
361
errorTerminalIdx: int
360
- nonTerminals: string list
362
+ nonTerminals: NonTerminal list
361
363
}
362
364
363
365
/// Compile a pre-processed LALR parser spec to tables following the Dragon book algorithm
@@ -367,21 +369,24 @@ let CompilerLalrParserSpec logf (spec : ProcessedParserSpec): CompiledSpec =
367
369
stopWatch.Start()
368
370
369
371
// Augment the grammar
370
- let fakeStartNonTerminals = spec.StartSymbols |> List.map( fun nt -> " _start" ^nt )
371
- let nonTerminals = fakeStartNonTerminals@ spec.NonTerminals
372
- let endOfInputTerminal = " $$"
373
- let dummyLookahead = " #"
372
+ let fakeStartNonTerminals = spec.StartSymbols |> List.map( fun ( name , r ) -> " _start" ^ name , r )
373
+ let nonTerminals = fakeStartNonTerminals @ spec.NonTerminals
374
+ let endOfInputTerminal = " $$" , Range.Empty
375
+ let dummyLookahead = " #" , Range.Empty
374
376
let dummyPrec = NoPrecedence
375
- let terminals = spec.Terminals @ [( dummyLookahead, dummyPrec); ( endOfInputTerminal, dummyPrec)]
376
- let prods = List.map2 ( fun a b -> Production( a, dummyPrec,[ NonTerminal b], None)) fakeStartNonTerminals spec.StartSymbols @ spec.Productions
377
+ let terminals =
378
+ spec.Terminals @ [( dummyLookahead, dummyPrec); ( endOfInputTerminal, dummyPrec)]
379
+ let prods =
380
+ List.map2 ( fun a b -> Production( a, dummyPrec, [ NonTerminal b], None)) fakeStartNonTerminals spec.StartSymbols
381
+ @ spec.Productions
377
382
let startNonTerminalIdx_to_prodIdx ( i : int ) = i
378
383
379
384
// Build indexed tables
380
385
let ntTab = NonTerminalTable( nonTerminals)
381
386
let termTab = TerminalTable( terminals)
382
- let prodTab = ProductionTable( ntTab, termTab, nonTerminals, prods)
383
- let dummyLookaheadIdx = termTab.ToIndex dummyLookahead
384
- let endOfInputTerminalIdx = termTab.ToIndex endOfInputTerminal
387
+ let prodTab = ProductionTable( ntTab, termTab, nonTerminals, prods)
388
+ let dummyLookaheadIdx = termTab.ToIndex ( fst dummyLookahead)
389
+ let endOfInputTerminalIdx = termTab.ToIndex ( fst endOfInputTerminal)
385
390
386
391
let errorTerminalIdx = termTab.ToIndex " error"
387
392
@@ -475,12 +480,13 @@ let CompilerLalrParserSpec logf (spec : ProcessedParserSpec): CompiledSpec =
475
480
let prodIdx = prodIdx_ of_ item0 item0
476
481
let dotIdx = dotIdx_ of_ item0 item0
477
482
mkItem0( prodIdx, dotIdx+ 1 )
478
- let fakeStartNonTerminalsSet = Set.ofList ( fakeStartNonTerminals |> List.map ntTab.ToIndex)
483
+
484
+ let fakeStartNonTerminalsSet = Set.ofList ( fakeStartNonTerminals |> List.map ( fst >> ntTab.ToIndex))
479
485
480
486
let IsStartItem item0 = fakeStartNonTerminalsSet.Contains( ntIdx_ of_ item0 item0)
481
487
let IsKernelItem item0 = ( IsStartItem item0 || dotIdx_ of_ item0 item0 <> 0 )
482
488
483
- let StringOfSym sym = match sym with PTerminal s -> " '" ^ termTab.OfIndex s ^ " '" | PNonTerminal s -> ntTab.OfIndex s
489
+ let StringOfSym sym = match sym with PTerminal s -> " '" ^ fst ( termTab.OfIndex s) ^ " '" | PNonTerminal s -> fst ( ntTab.OfIndex s)
484
490
485
491
let OutputSym os sym = fprintf os " %s " ( StringOfSym sym)
486
492
@@ -489,7 +495,7 @@ let CompilerLalrParserSpec logf (spec : ProcessedParserSpec): CompiledSpec =
489
495
490
496
// Print items and other stuff
491
497
let OutputItem0 os item0 =
492
- fprintf os " %s -> %a . %a " ( ntTab.OfIndex ( ntIdx_ of_ item0 item0)) (* outputPrecInfo precInfo *) OutputSyms ( lsyms_ of_ item0 item0) OutputSyms ( rsyms_ of_ item0 item0)
498
+ fprintf os " %s -> %a . %a " ( fst ( ntTab.OfIndex ( ntIdx_ of_ item0 item0) )) (* outputPrecInfo precInfo *) OutputSyms ( lsyms_ of_ item0 item0) OutputSyms ( rsyms_ of_ item0 item0)
493
499
494
500
let OutputItem0Set os s =
495
501
Set.iter ( fun item -> fprintfn os " %a " OutputItem0 item) s
@@ -503,12 +509,12 @@ let CompilerLalrParserSpec logf (spec : ProcessedParserSpec): CompiledSpec =
503
509
let OutputAction os m =
504
510
match m with
505
511
| Shift n -> fprintf os " shift %d " n
506
- | Reduce prodIdx -> fprintf os " reduce %s --> %a " ( ntTab.OfIndex ( prodTab.NonTerminal prodIdx)) OutputSyms ( prodTab.Symbols prodIdx)
512
+ | Reduce prodIdx -> fprintf os " reduce %s --> %a " ( fst ( ntTab.OfIndex ( prodTab.NonTerminal prodIdx) )) OutputSyms ( prodTab.Symbols prodIdx)
507
513
| Error -> fprintf os " error"
508
514
| Accept -> fprintf os " accept"
509
515
510
516
let OutputActions os m =
511
- Array.iteri ( fun i ( prec , action ) -> let term = termTab.OfIndex i in fprintfn os " action '%s ' (%a ): %a " term outputPrecInfo prec OutputAction action) m
517
+ Array.iteri ( fun i ( prec , action ) -> let ( name , range ) = termTab.OfIndex i in fprintfn os " action '%s ' (%a ): %a " name outputPrecInfo prec OutputAction action) m
512
518
513
519
let OutputActionTable os m =
514
520
Array.iteri ( fun i n -> fprintfn os " state %d :" i; fprintfn os " %a " OutputActions n) m
@@ -519,7 +525,7 @@ let CompilerLalrParserSpec logf (spec : ProcessedParserSpec): CompiledSpec =
519
525
| Some a -> OutputAction os a
520
526
521
527
let OutputGotos os m =
522
- Array.iteri ( fun ntIdx s -> let nonterm = ntTab.OfIndex ntIdx in match s with Some st -> fprintfn os " goto %s : %d " nonterm st | None -> ()) m
528
+ Array.iteri ( fun ntIdx s -> let ( name , range ) = ntTab.OfIndex ntIdx in match s with Some st -> fprintfn os " goto %s : %d " name st | None -> ()) m
523
529
524
530
let OutputCombined os m =
525
531
Array.iteri ( fun i ( a , b , c , d ) ->
@@ -760,7 +766,7 @@ let CompilerLalrParserSpec logf (spec : ProcessedParserSpec): CompiledSpec =
760
766
" reduce" , prodTab.Symbols x
761
767
|> Array.map StringOfSym
762
768
|> String.concat " "
763
- |> sprintf " reduce(%s :%s )" ( ntTab.OfIndex nt)
769
+ |> sprintf " reduce(%s :%s )" ( fst ( ntTab.OfIndex nt) )
764
770
| _ -> " " , " "
765
771
let pstr =
766
772
match p with
@@ -776,7 +782,7 @@ let CompilerLalrParserSpec logf (spec : ProcessedParserSpec): CompiledSpec =
776
782
an, " {" + pstr + " " + astr + " }"
777
783
let a1n , astr1 = reportAction x1
778
784
let a2n , astr2 = reportAction x2
779
- printfn " %s /%s error at state %d on terminal %s between %s and %s - assuming the former because %s " a1n a2n kernelIdx ( termTab.OfIndex termIdx) astr1 astr2 reason
785
+ printfn " %s /%s error at state %d on terminal %s between %s and %s - assuming the former because %s " a1n a2n kernelIdx ( fst ( termTab.OfIndex termIdx) ) astr1 astr2 reason
780
786
match itemSoFar, itemNew with
781
787
| (_, Shift s1),(_, Shift s2) ->
782
788
if actionSoFar <> actionNew then
@@ -904,11 +910,11 @@ let CompilerLalrParserSpec logf (spec : ProcessedParserSpec): CompiledSpec =
904
910
905
911
/// The final results
906
912
let states = kernels |> Array.ofList
907
- let prods = Array.ofList ( List.map ( fun ( Production ( nt , prec , syms , code )) -> ( nt, ntTab.ToIndex nt , syms, code)) prods)
913
+ let prods = Array.ofList ( List.map ( fun ( Production (( name , range ) as nt , prec , syms , code )) -> ( nt, ntTab.ToIndex name , syms, code)) prods)
908
914
909
915
logf ( fun logStream ->
910
916
printfn " writing tables to log" ; stdout.Flush();
911
- OutputLalrTables logStream ( prods, states, startKernelIdxs, actionTable, immediateActionTable, gotoTable, ( termTab.ToIndex endOfInputTerminal), errorTerminalIdx));
917
+ OutputLalrTables logStream ( prods, states, startKernelIdxs, actionTable, immediateActionTable, gotoTable, ( termTab.ToIndex ( fst endOfInputTerminal) ), errorTerminalIdx));
912
918
913
919
let states = states |> Array.map ( Set.toList >> List.map prodIdx_ of_ item0)
914
920
{ prods = prods
@@ -917,7 +923,7 @@ let CompilerLalrParserSpec logf (spec : ProcessedParserSpec): CompiledSpec =
917
923
actionTable = actionTable
918
924
immediateActionTable = immediateActionTable
919
925
gotoTable = gotoTable
920
- endOfInputTerminalIdx = termTab.ToIndex endOfInputTerminal
926
+ endOfInputTerminalIdx = termTab.ToIndex ( fst endOfInputTerminal)
921
927
errorTerminalIdx = errorTerminalIdx
922
928
nonTerminals = nonTerminals }
923
929
0 commit comments