Home > front end >  What's wrong with this prolog program for a json parser?
What's wrong with this prolog program for a json parser?

Time:01-05

I was trying to create a prolog JSON parser that has a string and a variable for the result as a input and i wrote this program:

:- use_module(library(dcg/basics)).

jsonparse(String, Value) :-
    string_chars(String, Chars),
    phrase(json_value(Value), Chars).

json_value(Value) -->
    json_object(Value) ;
    json_array(Value) ;
    json_number(Value) ;
    json_string(Value) ;
    json_true(Value) ;
    json_false(Value) ;
    json_null(Value).

json_object(json(Members)) -->
    "{", white, json_members(Members), white, "}".

json_members([Member|Members]) -->
    json_pair(Member),
    (   ",", white,
        json_members(Members)
    ;   []
    ).

json_pair((Name,Value)) -->
    json_string(Name), white, ":", white, json_value(Value).

json_array(json(Elements)) -->
    "[", white, json_elements(Elements), white, "]".

json_elements([Element|Elements]) -->
    json_value(Element),
    (   ",", white,
        json_elements(Elements)
    ;   []
    ).

json_number(number(Number)) -->
    number(Number).

json_string(string(String)) -->
    "\"", string_chars(String), "\"".

json_true(true) -->
    "true".

json_false(false) -->
    "false".

json_null(null) -->
    "null".

number(Number) -->
    float(Number) ;
    integer(Number).

float(float(F)) -->
    integer(I), ".", integer(Fraction),
    { atom_number(I, Int),
      atom_number(Fraction, FractionInt),
      F is Int   FractionInt / (10 ^ length(Fraction))
    }.

integer(I) -->
    digit(D), integer(D, I).

integer(I, I) -->
    [].

integer(I0, I) -->
    digit(D),
    { atom_concat(I0, D, I1) },
    integer(I1, I).

digit(D) -->
    [D],
    { code_type(D, digit) }.

white -->
    [C], { code_type(C, white) }, white.
white -->
    [].

string_chars([]) -->
    [].

string_chars([C|Cs]) -->
    string_char(C),
    string_chars(Cs).

string_char(C) -->
    [C],
    { C \= '"' }.

I simply can't make it work, it returns always false no matter what I ask as input. Can anyone spot the problem? I just want the parsed string as a result. Also, if you find more elegant or efficient ways to resolve the problem, would be great as I'm not very familiar with prolog

CodePudding user response:

You should use a library for this.

?- atom_json_term('{ "name" : "foo"}', T, []).
T = json([name=foo]).

Here is the link, again: https://www.swi-prolog.org/pldoc/man?section=json

CodePudding user response:

I think your problem is a mismatch between "chars" (Prolog atoms) and "codes" (Unicode character codepoints (ASCII for basic US English text and symbols)).

Your definition with string_chars(String, Chars) needs to be string_codes(String, Chars) to match the way the DCG runs, but then you will need to convert the captured values back from codes to text:

?- jsonparse('{"name" : "foo"}', Result).

Result = json([(string([110, 97, 109, 101]),string([102, 111, 111]))|_1688])

It might be possible instead to change your grammar to work over a list of atoms, e.g. '{' instead of "{" but that needs changes all the way through, and might mean you cannot use dcg/basics, and I have not tried that. You might still need to convert lists of atoms back to strings if you do that.

  • Related