Search code examples
prologdcg

dcg parsing in random order


I have some text files which I would like to parse, however the order of for exemple stop and start could be different. Stop could appear first or last, this is a dummy exemple as there are multiple variables like stop,start ...

Exemple1.txt

stop: 1

start: 2

exemple2.txt

start: 9

stop: 4

I know how to parse start and stop when start is first and stop is second, however how would I do this when these are in random order.

parseStart(D) --> "start: " , integer(D).
parseStop(D) --> "stop: " , integer(D).

I recieve the to be parsed file from stdin , so I do
read_string to parse 1 line, turn that into char list and do phrase(parseStart(Startint),line1), same for line 2, however than I have to know the order which I don't.

Maybe I could do something like

parseBoth(StartInt,StopInt) --> parseStart(startInt) <|> parseStop(StopInt) 

And do that two times and check if both are unified ? However this seems like a hack and I am wondering if there is a better way to do this ?

Edit: stop, start are just one of the many exemples, I have many dcg expressions that are in random order, how would I do this since trying every order would mean that I have to write 6! predicates for the 6 possible stop,start,end,time ... expressions


Solution

  • Maybe something like:

    parse(start(Start), stop(Stop)) -->
        first(Token),
        rest(Token, Start, Stop).
    
    first(start) --> "start: ".
    first(stop)  --> "stop: ".
    
    rest(start, Start, Stop) -->
        integer(Start), stop(Stop).
    rest(stop, Start, Stop) -->
        integer(Stop), start(Start).
    
    start(Start) --> "start: " , integer(Start).
    stop(Stop)   --> "stop: " , integer(Stop).
    

    Update after the question edit.

    If all lines of your text files have the format "keyword: integer", you could use:

    parse_pairs([]) -->
        eos.
    parse_pairs([Pair| Pairs]) -->
        parse_pair(Pair),
        parse_pairs(Pairs).
    
    parse_pair(Key-Value) -->
        string(String), ": ", integer(Value), blanks,
        {atom_string(Key, String)}.
    

    Sample call:

    ?- phrase(parse_pairs(Pairs), "start: 1\nstop: 2").
    Pairs = [start-1, stop-2] .