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
You should use a library for this.
Here is the link, again: https://www.swi-prolog.org/pldoc/man?section=json
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 bestring_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: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.