val DEBUG1 = false val DEBUG2 = false
exception ParseError
exception ParseImpossible of int
structure Fifo :> FIFO = struct type'a queue = ('a list * 'a list) val empty = (nil,nil)
exception Empty fun get(a::x, y) = (a, (x,y))
| get(nil, nil) = raise Empty
| get(nil, y) = get(rev y, nil) fun put(a,(x,y)) = (x,a::y) end
type ('a,'b) elem = (state * ('a * 'b * 'b)) type ('a,'b) stack = ('a,'b) elem list type ('a,'b) lexv = ('a,'b) token type ('a,'b) lexpair = ('a,'b) lexv * (('a,'b) lexv Stream.stream) type ('a,'b) distanceParse =
('a,'b) lexpair *
('a,'b) stack *
(('a,'b) stack * ('a,'b) lexpair) Fifo.queue *
int ->
('a,'b) lexpair *
('a,'b) stack *
(('a,'b) stack * ('a,'b) lexpair) Fifo.queue *
int *
action option
type ('a,'b) ecRecord =
{is_keyword : term -> bool,
preferred_change : (term list * term list) list,
error : string * 'b * 'b -> unit,
errtermvalue : term -> 'a,
terms : term list,
showTerminal : term -> string,
noShift : term -> bool}
local valprint = fn s => TextIO.output(TextIO.stdOut,s) val println = fn s => (print s; print"\n") val showState = fn (STATE s) => "STATE " ^ (Int.toString s) in fun printStack(stack: ('a,'b) stack, n: int) = case stack of (state,_) :: rest =>
(print("\t" ^ Int.toString n ^ ": ");
println(showState state);
printStack(rest, n+1))
| nil => ()
fun prAction showTerminal
(stack as (state,_) :: _, next as (TOKEN (term,_),_), action) =
(println "Parse: state stack:";
printStack(stack, 0); print(" state="
^ showState state
^ " next="
^ showTerminal term
^ " action="
); case action of SHIFT state => println ("SHIFT " ^ (showState state))
| REDUCE i => println ("REDUCE " ^ (Int.toString i))
| ERROR => println "ERROR"
| ACCEPT => println "ACCEPT")
| prAction _ (_,_,action) = () end
(* ssParse: parser which maintains the queue of (state * lexvalues) in a steady-state.Ittakesatable,showTerminalfunction,saction function,andfixErrorfunction.ItparsesuntilanACCEPTis encountered,oranexceptionisraised.Whenanerrorisencountered, fixErroriscalledwiththeargumentsofparseStep(lexv,stack,and queue).Itreturnsthelexv,andanewstackandqueueadjustedso
that the lexv can be parsed *)
val ssParse =
fn (table,showTerminal,saction,fixError,arg) => letval prAction = prAction showTerminal val action = LrTable.action table val goto = LrTable.goto table fun parseStep(args as
(lexPair as (TOKEN (terminal, value as (_,leftPos,_)),
lexer
),
stack as (state,_) :: _,
queue)) = letval nextAction = action (state,terminal) val _ = if DEBUG1 then prAction(stack,lexPair,nextAction) else () incase nextAction of SHIFT s => letval newStack = (s,value) :: stack val newLexPair = Stream.get lexer val (_,newQueue) =Fifo.get(Fifo.put((newStack,newLexPair),
queue)) in parseStep(newLexPair,(s,value)::stack,newQueue) end
| REDUCE i =>
(case saction(i,leftPos,stack,arg) of (nonterm,value,stack as (state,_) :: _) =>
parseStep(lexPair,(goto(state,nonterm),value)::stack,
queue)
| _ => raise (ParseImpossible 197))
| ERROR => parseStep(fixError args)
| ACCEPT =>
(case stack of (_,(topvalue,_,_)) :: _ => letval (token,restLexer) = lexPair in (topvalue,Stream.cons(token,restLexer)) end
| _ => raise (ParseImpossible 202)) end
| parseStep _ = raise (ParseImpossible 204) in parseStep end
(* distanceParse: parse until n tokens are shifted, or accept or errorareencountered.Takesatable,showTerminalfunction,and semanticactionfunction.ReturnsaparserwhichtakesalexPair (lexresult*lexer),astatestack,aqueue,andadistance (mustbe>0)toparse.Theparserreturnsanewlex-value,astack withthenthtokenshiftedontop,aqueue,adistance,andaction
option. *)
val distanceParse =
fn (table,showTerminal,saction,arg) => letval prAction = prAction showTerminal val action = LrTable.action table val goto = LrTable.goto table fun parseStep(lexPair,stack,queue,0) = (lexPair,stack,queue,0,NONE)
| parseStep(lexPair as (TOKEN (terminal, value as (_,leftPos,_)),
lexer
),
stack as (state,_) :: _,
queue,distance) = letval nextAction = action(state,terminal) val _ = if DEBUG1 then prAction(stack,lexPair,nextAction) else () incase nextAction of SHIFT s => letval newStack = (s,value) :: stack val newLexPair = Stream.get lexer in parseStep(newLexPair,(s,value)::stack,
Fifo.put((newStack,newLexPair),queue),distance-1) end
| REDUCE i =>
(case saction(i,leftPos,stack,arg) of (nonterm,value,stack as (state,_) :: _) =>
parseStep(lexPair,(goto(state,nonterm),value)::stack,
queue,distance)
| _ => raise (ParseImpossible 240))
| ERROR => (lexPair,stack,queue,distance,SOME nextAction)
| ACCEPT => (lexPair,stack,queue,distance,SOME nextAction) end
| parseStep _ = raise (ParseImpossible 242) in parseStep : ('_a,'_b) distanceParse end
(* mkFixError: function to create fixError function which adjusts parser state
so that parse may continue in the presence of an error *)
(lexv as (TOKEN (term,value as (_,leftPos,_)),_),stack,queue) = letval _ = if DEBUG2 then
error("syntax error found at " ^ (showTerminal term),
leftPos,leftPos) else ()
fun tokAt(t,p) = TOKEN(t,(errtermvalue t,p,p))
val minDelta = 3
(* pull all the state * lexv elements from the queue *)
val stateList = letfun f q = letval (elem,newQueue) = Fifo.get q in elem :: (f newQueue) endhandle Fifo.Empty => nil in f queue end
(* now number elements of stateList, giving distance from
error token *)
val showTerms = concat o map (fn TOKEN(t,_) => " " ^ showTerminal t)
val printChange = fn c => letval CHANGE {distance,new,orig,pos,...} = c in (print ("{distance= " ^ (Int.toString distance)); print (",orig ="); print(showTerms orig); print (",new ="); print(showTerms new); print (",pos= " ^ (Int.toString pos)); print"}\n") end
val printChangeList = app printChange
(* parse: given a lexPair, a stack, and the distance from the error
token, return the distance past the error token that we are able to parse.*)
fun parse (lexPair,stack,queuePos : int) = case distanceParse(lexPair,stack,Fifo.empty,queuePos+maxAdvance+1) of (_,_,_,distance,SOME ACCEPT) => if maxAdvance-distance-1 >= 0 then maxAdvance else maxAdvance-distance-1
| (_,_,_,distance,_) => maxAdvance - distance - 1
(* catList: concatenate results of scanning list *)
fun catList l f = List.foldr (fn(a,r)=> f a @ r) [] l
fun keywordsDelta new = ifList.exists (fn(TOKEN(t,_))=>is_keyword t) new then minDelta else0
fun tryChange{lex,stack,pos,leftPos,rightPos,orig,new} = letval lex' = List.foldr (fn (t',p)=>(t',Stream.cons p)) lex new val distance = parse(lex',stack,pos+length new-length orig) inif distance >= minAdvance + keywordsDelta new then [CHANGE{pos=pos,leftPos=leftPos,rightPos=rightPos,
distance=distance,orig=orig,new=new}] else [] end
(* tryDelete: Try to delete n terminals. Returnsingle-element[success]ornil.
Do not delete unshiftable terminals. *)
fun tryDelete n ((stack,lexPair as (TOKEN(term,(_,l,r)),_)),qPos) = letfun del(0,accum,left,right,lexPair) =
tryChange{lex=lexPair,stack=stack,
pos=qPos,leftPos=left,rightPos=right,
orig=rev accum, new=[]}
| del(n,accum,left,right,(tok as TOKEN(term,(_,_,r)),lexer)) = if noShift term then [] else del(n-1,tok::accum,left,r,Stream.get lexer) in del(n,[],l,r,lexPair) end
(* tryInsert: try to insert tokens before the current terminal;
return a list of the successes *)
fun tryInsert((stack,lexPair as (TOKEN(_,(_,l,_)),_)),queuePos) =
catList terms (fn t =>
tryChange{lex=lexPair,stack=stack,
pos=queuePos,orig=[],new=[tokAt(t,l)],
leftPos=l,rightPos=l})
(* trySubst: try to substitute tokens for the current terminal;
return a list of the successes *)
fun trySubst ((stack,lexPair as (orig as TOKEN (term,(_,l,r)),lexer)),
queuePos) = if noShift term then [] else
catList terms (fn t =>
tryChange{lex=Stream.get lexer,stack=stack,
pos=queuePos,
leftPos=l,rightPos=r,orig=[orig],
new=[tokAt(t,r)]})
(* do_delete(toks,lexPair) tries to delete tokens "toks" from "lexPair". Ifitsucceeds,returnsSOME(toks',l,r,lp),where toks'istheactualtokens(withpositionsandvalues)deleted, (l,r)arethe(leftmost,rightmost)positionoftoks', lpiswhatremainsofthestreamafterdeletion
*) fun do_delete(nil,lp as (TOKEN(_,(_,l,_)),_)) = SOME(nil,l,l,lp)
| do_delete([t],(tok as TOKEN(t',(_,l,r)),lp')) = if eqT (t, t') then SOME([tok],l,r,Stream.get lp') else NONE
| do_delete(t::rest,(tok as TOKEN(t',(_,l,r)),lp')) = if eqT (t,t') thencase do_delete(rest,Stream.get lp') of SOME(deleted,l',r',lp'') =>
SOME(tok::deleted,l,r',lp'')
| NONE => NONE else NONE
fun tryPreferred((stack,lexPair),queuePos) =
catList preferred_change (fn (delete,insert) => ifList.exists noShift delete then [] (* should give warning at
parser-generation time *) elsecase do_delete(delete,lexPair) of SOME(deleted,l,r,lp) =>
tryChange{lex=lp,stack=stack,pos=queuePos,
leftPos=l,rightPos=r,orig=deleted,
new=map (fn t=>(tokAt(t,r))) insert}
| NONE => [])
val findMaxDist = fn l =>
foldr (fn (CHANGE {distance,...},high) => Int.max(distance,high)) 0 l
(* maxDist: max distance past error taken that we could parse *)
val maxDist = findMaxDist changes
(* remove changes which did not parse maxDist tokens past the error token *)
val changes = catList changes
(fn(c as CHANGE{distance,...}) => if distance=maxDist then [c] else [])
incase changes of (l as change :: _) => letfun print_msg (CHANGE {new,orig,leftPos,rightPos,...}) = letval s = case (orig,new) of (_::_,[]) => "deleting " ^ (showTerms orig)
| ([],_::_) => "inserting " ^ (showTerms new)
| _ => "replacing " ^ (showTerms orig) ^ " with " ^ (showTerms new) in error ("syntax error: " ^ s,leftPos,rightPos) end
val _ =
(if length l > 1 andalso DEBUG2 then
(print"multiple fixes possible; could fix it by:\n"; app print_msg l; print"chosen correction:\n") else ();
print_msg change)
(* findNth: find nth queue entry from the error entry.ReturnstheNthqueueentryandtheportionof thequeuefromthebeginningtothenth-1entry.The errorentryisattheendofthequeue.
Examples:
queue=abcde findNth0=(e,abcd) findNth1=(d,abc)
*)
val findNth = fn n => letfun f (h::t,0) = (h,rev t)
| f (h::t,n) = f(t,n-1)
| f (nil,_) = let exception FindNth inraise FindNth end in f (rev stateList,n) end
val CHANGE {pos,orig,new,...} = change val (last,queueFront) = findNth pos val (stack,lexPair) = last
val lp1 = foldl(fn (_,(_,r)) => Stream.get r) lexPair orig val lp2 = foldr(fn(t,r)=>(t,Stream.cons r)) lp1 new
val restQueue =
Fifo.put((stack,lp2),
foldl Fifo.put Fifo.empty queueFront)
val (lexPair,stack,queue,_,_) =
distanceParse(lp2,stack,restQueue,pos)
in (lexPair,stack,queue) end
| nil => (error("syntax error found at " ^ (showTerminal term),
leftPos,leftPos); raise ParseError) end
val parse = fn {arg,table,lexer,saction,void,lookahead,
ec=ec as {showTerminal,...} : ('_a,'_b) ecRecord} => letval distance = 15(* defer distance tokens *) val minAdvance = 1(* must parse at least 1 token past error *) val maxAdvance = Int.max(lookahead,0)(* max distance for parse check *) val lexPair = Stream.get lexer val (TOKEN (_,(_,leftPos,_)),_) = lexPair val startStack = [(initialState table,(void,leftPos,leftPos))] val startQueue = Fifo.put((startStack,lexPair),Fifo.empty) val distanceParse = distanceParse(table,showTerminal,saction,arg) val fixError = mkFixError(ec,distanceParse,minAdvance,maxAdvance) val ssParse = ssParse(table,showTerminal,saction,fixError,arg) fun loop (lexPair,stack,queue,_,SOME ACCEPT) =
ssParse(lexPair,stack,queue)
| loop (lexPair,stack,queue,0,_) = ssParse(lexPair,stack,queue)
| loop (lexPair,stack,queue,distance,SOME ERROR) = letval (lexPair,stack,queue) = fixError(lexPair,stack,queue) in loop (distanceParse(lexPair,stack,queue,distance)) end
| loop _ = let exception ParseInternal inraise ParseInternal end in loop (distanceParse(lexPair,startStack,startQueue,distance)) end end;
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.15 Sekunden
(vorverarbeitet am 2026-07-03)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.