skip to Main Content

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

2

Answers


  1. 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

    Login or Signup to reply.
  2. 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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search