Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.postscript > #3440 > unrolled thread
| Started by | news@zzo38computer.org.invalid |
|---|---|
| First post | 2019-09-04 01:19 +0000 |
| Last post | 2019-09-13 19:53 -0700 |
| Articles | 8 — 2 participants |
Back to article view | Back to comp.lang.postscript
JSON reader/writer in PostScript news@zzo38computer.org.invalid - 2019-09-04 01:19 +0000
Re: JSON reader/writer in PostScript luser droog <luser.droog@gmail.com> - 2019-09-05 23:05 -0700
Re: JSON reader/writer in PostScript luser droog <luser.droog@gmail.com> - 2019-09-06 22:06 -0700
JSON reader/writer in PostScript (second version) news@zzo38computer.org.invalid - 2019-09-08 21:32 +0000
Re: JSON reader/writer in PostScript (second version) luser droog <luser.droog@gmail.com> - 2019-09-12 19:11 -0700
Re: JSON reader/writer in PostScript (second version) luser droog <luser.droog@gmail.com> - 2019-09-14 19:50 -0700
Re: JSON reader/writer in PostScript (second version) news@zzo38computer.org.invalid - 2019-09-15 18:34 +0000
Re: JSON reader/writer in PostScript (second version) luser droog <luser.droog@gmail.com> - 2019-09-13 19:53 -0700
| From | news@zzo38computer.org.invalid |
|---|---|
| Date | 2019-09-04 01:19 +0000 |
| Subject | JSON reader/writer in PostScript |
| Message-ID | <1567559086.bystand@zzo38computer.org> |
I wrote a program in PostScript for reading/writing JSON data. You can use
the following functions:
* JSON.read ( file -- object ) Read JSON data from the file. An object will
become a dictionary, with names (rather than strings) as keys. See also
JSON.utf8 below.
* JSON.write ( file object -- ) Write JSON data to the file. The object
must be a null, boolean, string, name, integer, real, array, or dictionary.
The JSON.utf8 option is unused; characters outside of the ASCII range are
always written exactly as in the string. (ASCII control characters, and any
character not allowed unescaped, will be escaped, though.)
* JSON.utf8 - You can redefine this (like "/JSON.utf8 true def"); it is
set to false by default. If false, only the low 8-bits of any character
code specified by \u escapes are used. If true, then \u escapes will be
converted into UTF-8. Bytes that are not escaped will just be passed
through as is, regardless of this setting.
Currently, the JSON.utf8 option is not implemented, so it must always be
false, and it will not work if true. If I fix that later, then I will post
a follow-up with the corrected program.
You can also write a follow-up message if you have a comment of it, please.
The below (between "===BEGIN CODE===" and "===END CODE===") is the
PostScript program.
===BEGIN CODE===
% JSON implementation in PostScript
% (public domain)
currentpacking true setpacking
/JSON.utf8 false def
/.JSON.file null def
/.JSON.str 65535 string def
/.JSON.hex (16#????) def
/.JSON.backchar 0 def
/.JSON.char 0 def
/.JSON.namech 256 string def
.JSON.namech 43 1 put %+
JSON.namech 45 1 put %-
.JSON.namech 46 1 put %.
8 1 57 {.JSON.namech exch 1 put} for %0-9
.JSON.namech 69 1 put %E
7 1 122 {.JSON.namech exch 1 put} for %a-z
/.JSON.escape 256 string def
0 1 255 {.JSON.escape exch dup put} for
.JSON.escape 98 8 put
JSON.escape 102 12 put
.JSON.escape 110 10 put
JSON.escape 114 13 put
.JSON.escape 116 9 put
JSON.escape 117 0 put
/.JSON.readnum {
.JSON.str 0 .JSON.char put
1
{.JSON.file read {
.JSON.namech 1 index get 0 eq {
/.JSON.backchar exch store
.JSON.str exch 0 exch getinterval cvr
exit
} {
.JSON.str exch 2 index exch put
1 add
} ifelse
} {JSON.badinput} ifelse} loop
} bind def
/.JSON.readword {
{.JSON.file read {
.JSON.namech 1 index get 0 eq {
/.JSON.backchar exch store
exit
} {pop} ifelse
} {JSON.badinput} ifelse} loop
} bind def
/.JSON.readstring {
0 {
.JSON.file read pop
dup 34 eq {
% End of string
pop dup string dup 2 index
.JSON.str exch 0 exch getinterval
0 exch putinterval exch pop
exit
} {
% Character
.JSON.str 2 index 2 index put
92 eq {
.JSON.str 1 index .JSON.escape .JSON.file read pop get put
.JSON.str 1 index get 0 eq {
.JSON.file .JSON.hex 3 4 getinterval readstring pop pop
/.JSON.char .JSON.hex cvi store
.JSON.char 127 gt JSON.utf8 and {
% Not yet implemented
} {
.JSON.str 1 index .JSON.char 255 and put
} ifelse
} if
} if
1 add
} ifelse
} loop
} bind def
/.JSON.parsech 256 array def
33 1 255 {.JSON.parsech exch /JSON.badinput cvx put} for
0 1 32 {.JSON.parsech exch null cvx put} for %spaces
.JSON.parsech 34 /.JSON.readstring load put %"
JSON.parsech 43 /.JSON.readnum load put %+
.JSON.parsech 44 null cvx put %,
JSON.parsech 45 /.JSON.readnum load put %-
48 1 57 {.JSON.parsech exch /.JSON.readnum load put} for %numbers
.JSON.parsech 58 /cvn load put %:
JSON.parsech 91 mark put %[
.JSON.parsech 93 (]) cvn load put %]
JSON.parsech 102 {false .JSON.readword} put %f
.JSON.parsech 110 {null .JSON.readword} put %n
JSON.parsech 116 {true .JSON.readword} put %t
.JSON.parsech 123 mark put %{
JSON.parsech 125 (>>) cvn load put %}
/.JSON.parse { % ( -- object )
.JSON.backchar 0 eq {
.JSON.file read
} {
.JSON.backchar /.JSON.backchar 0 store true
} ifelse {
/.JSON.char exch store
.JSON.parsech .JSON.char get exec
.JSON.parse
} if
} bind def
/.JSON.charx [32 {true} repeat 224 {false} repeat] def
.JSON.charx 34 true put
JSON.charx 92 true put
/.JSON.writechar {
.JSON.charx 1 index get {
.JSON.file (\\u00) writestring
dup 16 lt {.JSON.file 48 write} if
16 .JSON.str cvrs .JSON.file exch writestring
} {
.JSON.file exch write
} ifelse
} def
/.JSON.writedict <<
/arraytype {.JSON.file 91 write false exch {exch {.JSON.file 44 write} if .JSON.write true} forall pop .JSON.file 93 write}
/booleantype {.JSON.str cvs .JSON.file exch writestring}
/dicttype {.JSON.file 123 write false exch {3 -1 roll {.JSON.file 44 write} if exch .JSON.write .JSON.file 58 write .JSON.write true} forall pop .JSON.file 125 write}
/integertype {.JSON.str cvs .JSON.file exch writestring}
/nametype {.JSON.str cvs .JSON.write}
/nulltype {.JSON.file (null) writestring}
/realtype {.JSON.str cvs .JSON.file exch writestring}
/stringtype {.JSON.file 34 write {.JSON.writechar} forall .JSON.file 34 write}
>> def
/JSON.read {/.JSON.file exch store .JSON.parse} bind def
/.JSON.write {dup type .JSON.writedict exch get exec} bind def
/JSON.write {exch /.JSON.file exch store .JSON.write .JSON.file 10 write} bind def
setpacking
===END CODE===
--
Note: I am not always able to read/post messages during Monday-Friday.
[toc] | [next] | [standalone]
| From | luser droog <luser.droog@gmail.com> |
|---|---|
| Date | 2019-09-05 23:05 -0700 |
| Message-ID | <0ae78b2f-89f4-4b6b-9c5e-75fd39ca7f69@googlegroups.com> |
| In reply to | #3440 |
On Tuesday, September 3, 2019 at 8:20:26 PM UTC-5, ne...@zzo38computer.org.invalid wrote: > I wrote a program in PostScript for reading/writing JSON data. You can use > the following functions: > /.JSON.namech 256 string def > .JSON.namech 43 1 put %+ > JSON.namech 45 1 put %- > .JSON.namech 46 1 put %. I'd be tempted to write '(+) 0 get' instead of '43'. A little less efficient perhaps, but this part is one-time setup code so not critical. But using a string makes the comments unnecessary.
[toc] | [prev] | [next] | [standalone]
| From | luser droog <luser.droog@gmail.com> |
|---|---|
| Date | 2019-09-06 22:06 -0700 |
| Message-ID | <ec2e85e9-5302-4b59-a2dc-2e50651061da@googlegroups.com> |
| In reply to | #3441 |
On Friday, September 6, 2019 at 1:05:51 AM UTC-5, luser droog wrote:
> On Tuesday, September 3, 2019 at 8:20:26 PM UTC-5, ne...@zzo38computer.org.invalid wrote:
> > I wrote a program in PostScript for reading/writing JSON data. You can use
> > the following functions:
> > /.JSON.namech 256 string def
> > .JSON.namech 43 1 put %+
> > JSON.namech 45 1 put %-
> > .JSON.namech 46 1 put %.
>
> I'd be tempted to write '(+) 0 get' instead of '43'. A little less
> efficient perhaps, but this part is one-time setup code so not
> critical. But using a string makes the comments unnecessary.
And you could put them all in a single string and loop through it.
/.JSON.namech 256 string def
(+-.) { .JSON.namech exch 1 put } forall
[toc] | [prev] | [next] | [standalone]
| From | news@zzo38computer.org.invalid |
|---|---|
| Date | 2019-09-08 21:32 +0000 |
| Subject | JSON reader/writer in PostScript (second version) |
| Message-ID | <1567977875.bystand@zzo38computer.org> |
| In reply to | #3440 |
JSON.utf8 is now implemented (although it doesn't currently convert
surrogate pairs into a single UTF-8 codepoint), and another change as
suggested by some of the other follow-up messages to my first message
have also been implemented. Also, the "dot stuffing" of this message is
(hopefully) correct now; it was a bug in the NNTP software I was using,
but I have now corrected that bug (hopefully).
Also, I would like to know if you have any use for this, and especially if
you have found any bugs in it. (This is not mandatory though; it is public
domain, so you are allowed to do whatever you want with it.)
The below (between "===BEGIN CODE===" and "===END CODE===") is the
PostScript program.
===BEGIN CODE===
% JSON implementation in PostScript
% (public domain)
currentpacking true setpacking
/JSON.utf8 false def
/.JSON.file null def
/.JSON.str 65535 string def
/.JSON.hex (16#????) def
/.JSON.backchar 0 def
/.JSON.char 0 def
/.JSON.namech 256 string def
48 1 57 {.JSON.namech exch 1 put} for %0-9
97 1 122 {.JSON.namech exch 1 put} for %a-z
(+-.E) {.JSON.namech exch 1 put} forall
/.JSON.escape 256 string def
0 1 255 {.JSON.escape exch dup put} for
.JSON.escape 98 8 put
.JSON.escape 102 12 put
.JSON.escape 110 10 put
.JSON.escape 114 13 put
.JSON.escape 116 9 put
.JSON.escape 117 0 put
/.JSON.readnum {
.JSON.str 0 .JSON.char put
1
{.JSON.file read {
.JSON.namech 1 index get 0 eq {
/.JSON.backchar exch store
.JSON.str exch 0 exch getinterval cvr
exit
} {
.JSON.str exch 2 index exch put
1 add
} ifelse
} {JSON.badinput} ifelse} loop
} bind def
/.JSON.readword {
{.JSON.file read {
.JSON.namech 1 index get 0 eq {
/.JSON.backchar exch store
exit
} {pop} ifelse
} {JSON.badinput} ifelse} loop
} bind def
/.JSON.readstring {
0 {
.JSON.file read pop
dup 34 eq {
% End of string
pop dup string dup 2 index
.JSON.str exch 0 exch getinterval
0 exch putinterval exch pop
exit
} {
% Character
.JSON.str 2 index 2 index put
92 eq {
.JSON.str 1 index .JSON.escape .JSON.file read pop get put
.JSON.str 1 index get 0 eq {
.JSON.file .JSON.hex 3 4 getinterval readstring pop pop
/.JSON.char .JSON.hex cvi store
.JSON.char 127 gt JSON.utf8 and {
.JSON.char 16#0800 lt {
% Two byte UTF-8
.JSON.str 1 index .JSON.char -6 bitshift 16#C0 or put
1 add
.JSON.str 1 index .JSON.char 16#3F and 16#80 or put
} {
% Three byte UTF-8
.JSON.str 1 index .JSON.char -12 bitshift 16#E0 or put
1 add
.JSON.str 1 index .JSON.char -6 bitshift 16#3F and 16#80 or put
1 add
.JSON.str 1 index .JSON.char 16#3F and 16#80 or put
} ifelse
} {
.JSON.str 1 index .JSON.char 255 and put
} ifelse
} if
} if
1 add
} ifelse
} loop
} bind def
/.JSON.parsech 256 array def
33 1 255 {.JSON.parsech exch /JSON.badinput cvx put} for
0 1 32 {.JSON.parsech exch null cvx put} for %spaces
.JSON.parsech 34 /.JSON.readstring load put %"
.JSON.parsech 43 /.JSON.readnum load put %+
.JSON.parsech 44 null cvx put %,
.JSON.parsech 45 /.JSON.readnum load put %-
48 1 57 {.JSON.parsech exch /.JSON.readnum load put} for %numbers
.JSON.parsech 58 /cvn load put %:
.JSON.parsech 91 mark put %[
.JSON.parsech 93 (]) cvn load put %]
.JSON.parsech 102 {false .JSON.readword} put %f
.JSON.parsech 110 {null .JSON.readword} put %n
.JSON.parsech 116 {true .JSON.readword} put %t
.JSON.parsech 123 mark put %{
.JSON.parsech 125 (>>) cvn load put %}
/.JSON.parse { % ( -- object )
.JSON.backchar 0 eq {
.JSON.file read
} {
.JSON.backchar /.JSON.backchar 0 store true
} ifelse {
/.JSON.char exch store
.JSON.parsech .JSON.char get exec
.JSON.parse
} if
} bind def
/.JSON.charx [32 {true} repeat 224 {false} repeat] def
.JSON.charx 34 true put
.JSON.charx 92 true put
/.JSON.writechar {
.JSON.charx 1 index get {
.JSON.file (\\u00) writestring
dup 16 lt {.JSON.file 48 write} if
16 .JSON.str cvrs .JSON.file exch writestring
} {
.JSON.file exch write
} ifelse
} def
/.JSON.writedict <<
/arraytype {.JSON.file 91 write false exch {exch {.JSON.file 44 write} if .JSON.write true} forall pop .JSON.file 93 write}
/booleantype {.JSON.str cvs .JSON.file exch writestring}
/dicttype {.JSON.file 123 write false exch {3 -1 roll {.JSON.file 44 write} if exch .JSON.write .JSON.file 58 write .JSON.write true} forall pop .JSON.file 125 write}
/integertype {.JSON.str cvs .JSON.file exch writestring}
/nametype {.JSON.str cvs .JSON.write}
/nulltype {.JSON.file (null) writestring}
/realtype {.JSON.str cvs .JSON.file exch writestring}
/stringtype {.JSON.file 34 write {.JSON.writechar} forall .JSON.file 34 write}
>> def
/JSON.read {/.JSON.file exch store .JSON.parse} bind def
/.JSON.write {dup type .JSON.writedict exch get exec} bind def
/JSON.write {exch /.JSON.file exch store .JSON.write .JSON.file 10 write} bind def
setpacking
===END CODE===
--
Note: I am not always able to read/post messages during Monday-Friday.
[toc] | [prev] | [next] | [standalone]
| From | luser droog <luser.droog@gmail.com> |
|---|---|
| Date | 2019-09-12 19:11 -0700 |
| Subject | Re: JSON reader/writer in PostScript (second version) |
| Message-ID | <1ac2aa42-301c-4343-99de-2943b33fe7b0@googlegroups.com> |
| In reply to | #3443 |
On Sunday, September 8, 2019 at 4:33:23 PM UTC-5, ne...@zzo38computer.org.invalid wrote:
> JSON.utf8 is now implemented (although it doesn't currently convert
> surrogate pairs into a single UTF-8 codepoint), and another change as
> suggested by some of the other follow-up messages to my first message
> have also been implemented. Also, the "dot stuffing" of this message is
> (hopefully) correct now; it was a bug in the NNTP software I was using,
> but I have now corrected that bug (hopefully).
>
> Also, I would like to know if you have any use for this, and especially if
> you have found any bugs in it. (This is not mandatory though; it is public
> domain, so you are allowed to do whatever you want with it.)
>
I'm not sure how useful it is. Whenever I've needed to send data to postscript,
it has always been fairly easy to output valid postscript code. But I think
this *is* a fun little exercise. I spent this afternoon/evening writing my
own using the parser combinators. Probably some bugs in edge cases I haven't
considered. But simple tests appear to be working! It doesn't do any utf
conversion. It doesn't remove whitespace characters.
I'd be curious to see a speed comparison between our two programs (if only
to see how much slower mine probably is). But I'm not quite curious enough
to do it myself.
Additional files at:
https://github.com/luser-dr00g/pcomb/tree/369a1a508ab16aaa0a707f0a10f8391303f61397/ps
%!
%cf. https://tools.ietf.org/html/rfc7159
(pc9re2.ps)run
%errordict/typecheck{/typecheck = pstack / = countexecstack array execstack == quit}put
/SEQ {{seq}reduce} def
/PLUS {{plus}reduce} def
/str {{lit}map SEQ} def
/snip-ends { 1 1 index length 2 sub getinterval } def
/ws ( \t\n\r) anyof many def
/begin-array [ //ws ([) char //ws ] SEQ def
/begin-object [ //ws ({) char //ws ] SEQ def
/end-array [ //ws (]) char //ws ] SEQ def
/end-object [ //ws (}) char //ws ] SEQ def
/name-separator [ //ws (:) char //ws ] SEQ def
/value-separator [ //ws (,) char //ws ] SEQ def
/value {-777 exec} def
/decimal-point (.) char def
/digit1-9 (19) spill range def
/digit (09) spill range def
/Jzero (0) char def
/e (eE) anyof def
/Jplus (+) char def
/minus (-) char def
/expn [ //e //minus //Jplus plus maybe //digit some ] SEQ def
/frac [ //decimal-point //digit some ] SEQ def
/int //Jzero //digit1-9 //digit many seq plus def
/number [ //minus maybe //int //frac maybe //expn maybe ] SEQ
{
to-string
dup (.) search { pop pop pop cvr }{
pop dup (e) search { pop pop pop cvr }{
pop dup (E) search { pop pop pop cvr }{ pop cvi } ifelse
} ifelse
} ifelse
} using def
/quotation-mark (") char def
/unescaped [ 16#20 16#21 range 16#23 16#5B range 16#5D 16#10FFFF range ] PLUS def
/escape (\\) char def
/4hexdig (u) char //digit (AF) spill range plus 3{dup seq}repeat seq def
/escape-sequence //escape [ ("\\/bfnrt) anyof //4hexdig ] PLUS seq def
/Jchar //unescaped //escape-sequence plus def
/Jstring [ //quotation-mark //Jchar many //quotation-mark ] SEQ
{ to-string snip-ends } using def
/member [ //Jstring //name-separator //value ] SEQ def
/Jobject [ //begin-object
//member //value-separator //member seq many seq maybe
//end-object ] SEQ
{
1 dict begin
flatten snip-ends
3 { spill exch pop def } fortuple
currentdict end
} using def
/Jarray [ //begin-array
//value //value-separator //value seq many seq maybe
//end-array ] SEQ
{ flatten snip-ends } using def
//value 0 [ (false) str (null) str (true) str
//Jobject //Jarray //number //Jstring ] PLUS put
/JSON-text [ //ws //value //ws ] SEQ def
/JSON-parse { JSON-text first first second } def
(4) string-input JSON-parse pc
(4.0) string-input JSON-parse pc
(4e3) string-input JSON-parse pc
("4") string-input JSON-parse pc
([4]) string-input JSON-parse pc
({"a":4}) string-input JSON-parse ps ===
quit
Output:
$ make
gsnd -dNOSAFER pc9json.ps
GPL Ghostscript 9.27 (2019-04-04)
Copyright (C) 2018 Artifex Software, Inc. All rights reserved.
This software is supplied under the GNU AGPLv3 and comes with NO WARRANTY:
see the file COPYING for details.
stack:
4
stack:
4.0
stack:
4000.0
stack:
(4)
stack:
[4]
stack:
-dict-
<< /a 4 >>
[toc] | [prev] | [next] | [standalone]
| From | luser droog <luser.droog@gmail.com> |
|---|---|
| Date | 2019-09-14 19:50 -0700 |
| Subject | Re: JSON reader/writer in PostScript (second version) |
| Message-ID | <a148ab80-3ae6-4bd4-aa86-9c6e8533d8eb@googlegroups.com> |
| In reply to | #3449 |
On Thursday, September 12, 2019 at 9:11:03 PM UTC-5, luser droog wrote:
> On Sunday, September 8, 2019 at 4:33:23 PM UTC-5, ne...@zzo38computer.org.invalid wrote:
> > JSON.utf8 is now implemented (although it doesn't currently convert
> > surrogate pairs into a single UTF-8 codepoint), and another change as
> > suggested by some of the other follow-up messages to my first message
> > have also been implemented. Also, the "dot stuffing" of this message is
> > (hopefully) correct now; it was a bug in the NNTP software I was using,
> > but I have now corrected that bug (hopefully).
> >
> > Also, I would like to know if you have any use for this, and especially if
> > you have found any bugs in it. (This is not mandatory though; it is public
> > domain, so you are allowed to do whatever you want with it.)
> >
>
> I'm not sure how useful it is. Whenever I've needed to send data to postscript,
> it has always been fairly easy to output valid postscript code. But I think
> this *is* a fun little exercise. I spent this afternoon/evening writing my
> own using the parser combinators. Probably some bugs in edge cases I haven't
> considered. But simple tests appear to be working! It doesn't do any utf
> conversion. It doesn't remove whitespace characters.
>
> I'd be curious to see a speed comparison between our two programs (if only
> to see how much slower mine probably is). But I'm not quite curious enough
> to do it myself.
>
<snip>
Improved my code to handle spaces and nested structures. I had to
debug and modify part of the parser combinator library to get it
to work.
The problem I was having was the result from a parser
produced by the 'maybe' combinator. A maybe parser has to succeed
regardless of the success or failure of its child parser. So in the
case where the child parser fails, 'maybe' has to return *something*.
Earlier I had it set up to return an empty array [], but the problem
now was that some other part of the machinery (haven't tracked it
down precisely yet) was interpreting that as failure instead of
success with an empty result.
I changed it now to return the name /0. Since I'm not using names
anywhere in the data (relying on the automatic behavior of 'def')
I can detect these as part of the scaffolding of the parse tree.
I can't use 'null' because json data may contain the keyword null.
This version doesn't actually convert null (or true or false) but
it's a trivial change.
The next issue is: I don't understand what to do with unicode
characters if they are discovered. It appears that OP's code
reads in the multibyte sequences, constructs the codepoint in
an int, and then truncates that to 8 bits and stores it in a
string. That doesn't seem right, but I can't really think of
anything better. Maybe an option either to leave the utf8 alone,
or convert to arrays of integers? It's not clear to me what
a PostScript program could hope to do with unicode data.
So I haven't written any utf8 handling. If I do add it, I think
it should be added to the parser library itself as an input
filter. The C version has these already.
Additional referenced files at latest commit:
https://github.com/luser-dr00g/pcomb/tree/d4cc78d862c84873fb05a593df2ea5d878988b81/ps
%!
%cf. https://tools.ietf.org/html/rfc7159
(pc9re2.ps)run
%errordict/typecheck{/typecheck = pstack / = countexecstack array execstack == quit}put
%errordict/rangecheck{/rangecheck = pstack / = countexecstack array execstack == quit}put
/SEQ {{seq}reduce} def
/PLUS {{plus}reduce} def
/str {{lit}map SEQ} def
/filter-zeros { { dup /0 eq {pop} if } map } def
/snip-ends { 1 1 index length 2 sub getinterval } def
/! { { dup /0 eq { pop [] } if } using } def
/maybe! { maybe ! } def
/many! { many ! } def
/dump { dup first exch
second dup type /nametype eq 1 index /0 eq and { pop }{ dump } ifelse } def
/to-array { dup type /arraytype ne { one }{ [ exch dump ] } ifelse } def
/to-pairs {
dup length 1 eq { first pairs }{
[ exch dup first exch second dump ]
{spill spill} map pairs
} ifelse
} def
/ws ( \t\n\r) anyof many def
/begin-array //ws ([) char xthen //ws thenx def
/begin-object //ws ({) char xthen //ws thenx def
/end-array //ws (]) char xthen //ws thenx def
/end-object //ws (}) char xthen //ws thenx def
/name-separator //ws (:) char xthen //ws thenx def
/value-separator //ws (,) char xthen //ws thenx def
/value {-777 exec} def
/decimal-point (.) char def
/digit1-9 (19) spill range def
/digit (09) spill range def
/Jzero (0) char def
/e (eE) anyof def
/Jplus (+) char def
/minus (-) char def
/frac //decimal-point //digit some seq def
/expn [ //e //minus //Jplus plus maybe! //digit some ] SEQ def
/int //Jzero //digit1-9 //digit many seq plus def
/number [ //minus maybe! //int //frac maybe! //expn maybe! ] SEQ
{
flatten filter-zeros to-string
dup (.) search { pop pop pop cvr }{
pop dup (e) search { pop pop pop cvr }{
pop dup (E) search { pop pop pop cvr }{ pop cvi } ifelse
} ifelse
} ifelse
} using
def
/quotation-mark (") char def
/unescaped [ 16#20 16#21 range 16#23 16#5B range 16#5D 16#10FFFF range ] PLUS def
/escape (\\) char def
/4hexdig (u) char //digit (AF) spill range plus 3{dup seq}repeat seq def
/escape-sequence //escape [ ("\\/bfnrt) anyof //4hexdig ] PLUS seq def
/Jchar //unescaped //escape-sequence plus def
/Jstring [ //quotation-mark //Jchar many! //quotation-mark ] SEQ
{ flatten filter-zeros snip-ends to-string } using
def
/member //Jstring //name-separator thenx //value seq
{ one } using
def
/Jobject //begin-object
//member xthen
//value-separator //member xthen many! seq maybe!
//end-object thenx
{ to-pairs } using
def
/Jarray //begin-array
//value xthen
//value-separator //value xthen many! seq maybe!
//end-array thenx
{ to-array } using
def
//value 0 [ (false) str (null) str (true) str
//Jobject //Jarray //number //Jstring ] PLUS put
/JSON-text //ws //value xthen //ws thenx def
/JSON-parse {
JSON-text first first
} def
%(4) dup string-input JSON-parse pc
%( 4) dup string-input JSON-parse pc
%(4 ) dup string-input JSON-parse pc
%( 4 ) dup string-input JSON-parse pc
%( 4.0 ) dup string-input JSON-parse pc
( 4e3 ) dup string-input JSON-parse pc
( "4" ) dup string-input JSON-parse pc
( [ 4 ] ) dup string-input JSON-parse pc
( [ 4, 5 ] ) dup string-input JSON-parse pc
( [ 3, [ 4, [ 5 ] ] ] ) dup string-input JSON-parse pc
( {"a":4,"b":5} ) dup string-input JSON-parse ps === clear
( { "a" : 4 , "b" : 5 } ) dup string-input JSON-parse ps === clear
( [ {"a":4,"b":5}, 6, {"c":"7"}] ) dup string-input JSON-parse ps === clear
quit
Output:
$ make
gsnd -dNOSAFER pc9json.ps
GPL Ghostscript 9.27 (2019-04-04)
Copyright (C) 2018 Artifex Software, Inc. All rights reserved.
This software is supplied under the GNU AGPLv3 and comes with NO WARRANTY:
see the file COPYING for details.
stack:
4000.0
( 4e3 )
stack:
(4)
( "4" )
stack:
[4]
( [ 4 ] )
stack:
[4 5]
( [ 4, 5 ] )
stack:
[3 [4 [5]]]
( [ 3, [ 4, [ 5 ] ] ] )
stack:
-dict-
( {"a":4,"b":5} )
<< /a 4 /b 5 >>
stack:
-dict-
( { "a" : 4 , "b" : 5 } )
<< /a 4 /b 5 >>
stack:
[-dict- 6 -dict-]
( [ {"a":4,"b":5}, 6, {"c":"7"}] )
[<< /a 4 /b 5 >> 6 << /c (7) >>]
[toc] | [prev] | [next] | [standalone]
| From | news@zzo38computer.org.invalid |
|---|---|
| Date | 2019-09-15 18:34 +0000 |
| Subject | Re: JSON reader/writer in PostScript (second version) |
| Message-ID | <1568569984.bystand@zzo38computer.org> |
| In reply to | #3451 |
luser droog <luser.droog@gmail.com> wrote: > > The next issue is: I don't understand what to do with unicode > characters if they are discovered. It appears that OP's code > reads in the multibyte sequences, constructs the codepoint in > an int, and then truncates that to 8 bits and stores it in a > string. That doesn't seem right, but I can't really think of > anything better. Maybe an option either to leave the utf8 alone, > or convert to arrays of integers? It's not clear to me what > a PostScript program could hope to do with unicode data. > > So I haven't written any utf8 handling. If I do add it, I think > it should be added to the parser library itself as an input > filter. The C version has these already. The first version of my program will treat \u escapes in the way you mention; only the low 8 bits of the codepoints are used. The second version of my program has an option to instead convert any \u escapes into UTF-8 encoding. (However, it will not convert surrogate pairs into astral characters.) Regardless of the version and of the option, if it reads any unescaped non-ASCII characters, they will be passed through as is; it will not interpret UTF-8 input at all, but just passes it through. You might be able to write UTF-8 text on the page with codespace ranges, so maybe there is the possibility to use Unicode data in that way. If you want to add UTF-8 handling in your own program though, you can do it whichever way you think is good, I think. -- Note: I am not always able to read/post messages during Monday-Friday.
[toc] | [prev] | [next] | [standalone]
| From | luser droog <luser.droog@gmail.com> |
|---|---|
| Date | 2019-09-13 19:53 -0700 |
| Subject | Re: JSON reader/writer in PostScript (second version) |
| Message-ID | <9732a128-781e-4846-ab0b-62c89a0ce158@googlegroups.com> |
| In reply to | #3443 |
On Sunday, September 8, 2019 at 4:33:23 PM UTC-5, ne...@zzo38computer.org.invalid wrote: > JSON.utf8 is now implemented (although it doesn't currently convert > surrogate pairs into a single UTF-8 codepoint), and another change as > suggested by some of the other follow-up messages to my first message > have also been implemented. Also, the "dot stuffing" of this message is > (hopefully) correct now; it was a bug in the NNTP software I was using, > but I have now corrected that bug (hopefully). > > Also, I would like to know if you have any use for this, and especially if > you have found any bugs in it. (This is not mandatory though; it is public > domain, so you are allowed to do whatever you want with it.) No bugs found (in your code, mine's another story) but I do have a few comments. > The below (between "===BEGIN CODE===" and "===END CODE===") is the > PostScript program. > > ===BEGIN CODE=== [snip] > .JSON.parsech 43 /.JSON.readnum load put %+ This is probably a good idea. But the spec I read actually only specifies an optional minus sign. Apparently numbers ought not to begin with a plus sign. But I'll bet tons of code(rs) out there expect this work. [snip] > .JSON.parsech 125 (>>) cvn load put %} The 'cvn' here is not strictly necessary. Strings will automatically be converted into names when used as dict keys.
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.postscript
csiph-web