Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

A strange syntactic loophole available in xpost (gs doesn't do it).

21 views
Skip to first unread message

luser- -droog

unread,
Feb 26, 2015, 1:57:15 AM2/26/15
to
While cleaning up a bug in my scanner which was preventing me from
placing a closing curly-brace in a string in a procedure, eg. this

{ (}) }

was giving me an undefined error. This was because it builds the
array on the stack, essentially doing the manual method:

[ object object object ] cvx

But it was using "dictionary" semantics to detect the closing brace.
That is, the scanner calls itself recursively in a loop until the
top of stack compares equal to the closing curly, "}".

So that's why it was blowing up on the string in the proc, but the
real story is that } is a name, an executable name. It's hard to
get at, and mean to use, but in xpost at least. It's a 1-character
self-delimiting token. So you *could* (if you're sufficiently
perverse), define a procedure.

(}) { some crazy shit }

Which can *only* be executed from the top level. Because it's painful
to get it into a proc. You can't use //immediately-loaded names,
because that happens in the "child call" of the scanner, and so a
resulting } will terminate the proc. You'd have to hard-patch it,
and that's going to lose you any golfing gains. Oh, yeah. This is
only potentially useful for golfers. Rest of ya'lls just wasted some
time! haha.

tlvp

unread,
Feb 26, 2015, 4:33:14 PM2/26/15
to
No way to "escape" it? or "quote" it? That's a real drag :-{ . -- tlvp
--
Avant de repondre, jeter la poubelle, SVP.

luser- -droog

unread,
Feb 27, 2015, 2:02:14 AM2/27/15
to
Hm. I can't think of any way. It's an implementation detail whether it
even exists as an independent object, depending on the details of the
scanner code.

Here's my current version.

case '{': { // This is the one part that makes it a recursive-descent parser
int ret;
Xpost_Object tail;
tail = xpost_name_cons(ctx, "}");
xpost_stack_push(ctx->lo, ctx->os, mark);
while (1) {
Xpost_Object t;
ret = toke(ctx, src, next, back, &t);
//printf("grok: x?%d", xpost_object_is_exe(t));
if (ret)
return ret;
if ((xpost_object_get_type(t) == nametype)
&& (xpost_dict_compare_objects(ctx, t, tail) == 0))
break;
xpost_stack_push(ctx->lo, ctx->os, t);
}
ret = xpost_op_array_to_mark(ctx); // ie. the /] operator
if (ret)
return ret;
//return xpost_object_cvx(xpost_stack_pop(ctx->lo, ctx->os));
*retval = xpost_object_cvx(xpost_stack_pop(ctx->lo, ctx->os));
return 0;
}

which you may snip in replies in favor of this pseudocode:

object tail = name("}")
push(mark)
while(1)
object t = token() ;;< recursive call to scanner
if (t.type == nametype) and (compare(t,tail)==0)
break
push(t)
counttomark array astore cvx

This produces the correct behavior for correct constructs,
but for a bare right-curly }
it will yield the executable name `}`
which the interpreter will then execute.

If you choose not to abuse it, the only difference apparent
to the user is that ghostscript signals a syntaxerror and
xpost signals an undefined error.

Ghostscript scanning is much more complicated, but does
a superior job of dealing with the spectrum of line-termination
conventions than xpost. I fear I will have to learn more
details from gs before I'm through.

--
s/fear/hope
s/have/get
0 new messages