Problem with number//1

Hello,
I’m using: SWI-Prolog version 8.2.4 on Win10

I want to parse a sequence of numbers (floats and integers) and words (some are keywords, some just identifiers), separated by whitespace, like " -4 2.1 add"
I use this dcg code

eval(List, DataStack, DataStack2) :-
		phrase(words(DataStack, DataStack2), List, _).

	words(DS, DS3) --> 		ws, 
							word(W), 
							ws, !,
							{ 	format("Current Word  ~w ~n", [W]),
								( is_keyword(W) ->
									execute(W, DS, DS2)
								;
									% if word no keyword put it onto data stack
									append([W], DS, DS2)
								)	
							},
						words(DS2, DS3).
	words(DS, DS) --> [].	

	word(N) --> number(N) , { format("Number ~w ~n", [N]) }.
	% longest possible match
	word(W) --> identifier(CS), {	length(CS, N), 
									N > 1,
									atom_chars(W, CS),
									format("Word ~w ~n", [W])}.

	% Wenn es eine Adresse ist lege sie auf den Datastack
	word(W) --> identifier(CS), { 	[C] = CS, 
									atom_string(W, C), 
									is_adress(W)}.

	

	% parse Identifier
	identifier([C|S]) --> character(C),
						characters(S).		
	characters([C|S]) --> character(C),	
						characters(S).
	characters([]) --> [].

	character(C) --> 	[C], {char_type(C, csym)}.
	character(C) --> 	[C], {char_code(C, 42)}.

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

The problem is, only positive intergers will be detected correctly, negative numbers and floats don’t work? Where is my fault? I don’t see it, according documentation number//1 should work. BTW, it is some kind of simple Forth interpreter.

Cheers and thanks

Hans

Huh, I’m not able to reproduce this locally or on Swish. Can you post an example query and its response?

Running the code given (after defining is_keyword/1 to do nothing) seems to work fine:

?- phrase(words([], D), `-4 2.1 add`).
Number -4 
Current Word  -4 
Number 2.1 
Current Word  2.1 
Word add 
Current Word  add 
D = [add, 2.1, -4].

What is the List argument you’re passing in?

Hmm, that looks fine indeed. The List is given here:

atom_json_dict(Message.data, Body, []),
atom_chars(Body.data, Charlist),
 evalLoop::eval(Charlist, [], DataStack2),

where the Message.data is a dict received from websocket (related to :: syntax I use Logtalk )

Cheers

Hans

This is one query :

ᘀ?- Decoding message {"from":"D","to":"L","cmd":"result","data":"1.0 2 2000 direction L U pack ","seq":1} 
Jetzt gehts los [1,.,0, ,2, ,2,0,0,0, ,d,i,r,e,c,t,i,o,n, ,L, ,U, ,p,a,c,k, ] 
Nummer erkannt 1 
Current Word  1 
Return message 1

The first line you can see whats comming from the websocket. It treats 1.0 as 1 and then goes a wrong path (due to a false predicate I think)

Not sure if this helps

Cheers

Hans

For a few weeks I was writing a PostScript interpreter in SWI-Prolog (ref) for use with PDFs and found that using EDGCs was more advantageous as the state being passed around was getting rather complex.

I did get it to the point it could interpret some simple postscript but not the full language. Then I found a better way to solve my problem so abandoned that part of the project.


EDIT

FYI for those looking to use EDCGs.

From my personal experience in using them I learned that they take the idea of DCGs and show one how they can step up to higher levels for processing data in complex streams. But also learned that EDCGs as implemented for the Aquarius compiler were very specific for that need. In other words, if it seems you are shoe-horning the logic to work with the existing syntax for EDCG, then consider rolling your own. e.g.

Aquarius has syntax such as

X/Acc
Acc/X
X/Acc/Y

but with stack based languages, the idea of pop and push make more sense.

If I knew and felt comfortable with Conditional compilation and program transformation better I would probably have used that with EDCGs.

If you have any questions about EDCGs, feel free to ask! (I’ve used them a lot, and have trouble going back to regular DCGs).

2 Likes

Oh, I think that’s because you’re converting the message into chars, which is a list of single-character atoms, while the DCG expects codes – numeric values of the Unicode values. Try using atom_codes/2 instead of atom_chars/2?

2 Likes

Do they work with modules?

I guess no, from inspecting the package, ECDGs are not module aware.

Even SWI-Prolog does show me something strange with ordinary DCG:

?- [user].
foo:bar --> jack:jill.

When I do listing I get:

?- listing(foo:bar/2).
bar(A, B) :-
    user:jack:jill(A, B).

Whats the user: prefix doing? Is the user: needed?

Setting the calling context for the module. Try writing a more complex rule; user: is prefixed to the entire thing.

No. I think when the original code was written (by Peter van Roy) there weren’t any Prologs with modules. :wink:

There was some discussion a while back about how to make them work with modules. (Paul Moura had some suggestions, IIRC)

One of the problems is that EDCGs, unlike DCGs, require declaring each expanded predicate, to give the “accumulators” that it uses. This could probably be made module aware using context_module/1 and prolog_load_context/2, and changing how the declaration lookup is done. But I haven’t thought very deeply about this.

Is there a generic “best practices” for doing module-aware term expansion?

Aquarius Prolog is from the 90’s, late 80’s, modules were known already for a while.
Prolog II by Colmerauer had modules, a Prolog system from the early 80’s.
You can check yourself. There is a download link of an old manual:

http://prolog-heritage.org/en/ph20.html

(Me thinks Aquarius Prolog does also not have garbage collection? At least the
PhD thesis doesn’t show garbage collection. But there is a paper from Herve
Touati about garbage collection for Aquarius from late 80’s. Same Aquarius?)

Yes, indeed, that is the solution, doing all with codes, not chars. From the documentation this was not clear to me that using dcg with chars or codes is not really equivalent :slight_smile:

Thank you all very much for the quick answers and kindly help!

Cheers

Hans

2 Likes

Thank you very much for the hint about EDCGs. At the moment I’m in prototype phase, but later this may be of great value :slight_smile: !

Thanks!

Cheers

Hans

My understanding is that “chars” is mostly a legacy thing now: In an ASCII-only world, they made sense since you could just pre-allocate 255 atoms for each character, but with Unicode, that’s clearly impractical, meaning that now you’d have to create atoms for characters as they come in, which in turn causes more allocations & GC work.