jonadab has asked for the wisdom of the Perl Monks concerning the following question:
I'm working on a simple bilingual program (code below),
and I'm looking for tips and pointers primarily in terms
of how to better work with the other language's syntax.
I can easily hide each language's code from the other,
since Inform uses a different comment char (!) than Perl,
but that really isn't good enough. What I have right
now is enough (if I'm careful about the order I declare
things in, and leave out the optional hardware short
names and parents on the object headers) to let Perl
print on startup the same things the Inform program
would, but the minute I want to add an additional
object that comes into play later (after the user
types something), I'm stuck. I really need a way
to declare objects in Inform syntax and have Perl
store the strings away, tied somehow to the name
of the object. At this point, maybe I should put
in the code I have, so you can get an idea of the
sort of syntax I need to deal with...
#ifdef Perl; "
"; !"; sub Constant ($) {}; sub Headline ($) { $x=$_[0]; $x =~ s/\^/\n
+/g; print $x; } sub Story ($) { print $_[0]; } #"
#endif;
Constant Story "Obfuscated Perl Competition";
Constant Headline "^An interactive adventure in source-code obscurity.
+^";
#Include "Parser"; Constant Code "Just Another Inform Hacker
";!"; sub with (@) { return @_; } "who really
!"; sub Object (@) { } "ought to
!"; sub EmptyRoom {} sub Desk {} "know better
!"; sub initial { print "\n$_[0]\n> "; } "than this.
!"; sub description { print "\n$_[1]\n$_[0]\n"; } "
!"; sub short_name {} sub has($) {};
Object EmptyRoom
with
description
"The walls are white.",
short_name "EMPTY ROOM",
has light;
Object Desk
EmptyRoom
with
initial
"This is the desk where you are supposed to be working on you
+r entry
for the Obfuscated Perl Competition. But your mind keeps slipping
back to that text adventure you were working on before...",
short_name "Desk",
has static;
#Include "VerbLib"; [ Initialise; location = EmptyRoom; ]; global win
+msg "You write an entry that compiles in both Perl and Inform.
";!";
#Include "Grammar"; [ FinishSub; deadflag=2; print_ret winmsg, "
"; ];
Verb 'write' 'entry' -> Finish;
Verb 'win' -> Finish;
Verb 'finish' -> Finish;
end;
";
$debug=0;
push @grammar, [['quit'], 'Quit'];
push @grammar, [['write', 'entry'], 'Finish'];
push @grammar, [['win'], 'Finish'];
# I could do more, but I do not have the gumption to reproduce
# the entire Inform standard library grammar here. Besides,
# my parser can't handle most of it, and the Perl object model
# is not up to the more advanced stuff. (Inform is very OO.)
%verb =
(
Quit => sub { exit 0; },
Finish => sub {
print "You write an entry that compiles in both Perl and Inform.\
+n\n *** You Have Won ***\n\n"; exit 0;
},
# I don't have the gumption to reproduce the entire Inform verb lib
+rary here, either.
);
sub gramerr {
my ($tok,$gram) = @_;
if ($tok>$besterr) {
$besterr=$tok; $bestgram=$gram;
}
}
while (<STDIN>) {
@token=split/\s+/,$_;
$besterr=0;
foreach $g (@grammar) {
last if ($besterr==999);
if ($debug>1) { print "Considering grammar line: @$g: "; }
@gramline = @$g;
$gramtoken= @{gramline[0]};
$gramverb = @gramline[1];
$mismatch=0;
$t=0;
while ($t<scalar @$gramtoken and $mismatch==0 and $besterr<999) {
if ($debug>2) { print " [token $t: $token[$t] vs $$gramtoken[$
+t]]"; }
if ((not defined $token[$t]) or ($token[$t] !~ $$gramtoken[$t]))
+ {
gramerr($t+1, $g); $mismatch++; if ($debug>2) {print "mismatch\n"
+;}}
if (not $mismatch) {
if ($debug>2) { print "matches so far\n";}
if ($t+1==scalar@$gramtoken) {
$bestgram=$g; $besterr=999;
if ($debug>2) { print "matches fully\n"; }}}
$t++; }}
if ($besterr==999) {
$g=$bestgram;
@gramline = @$g;
$gramtoken= @{gramline[0]};
$gramverb = @gramline[1];
if ($debug) { print "Calling routine for $gramverb\n"; }
&{$verb{$gramverb}};
} else {
# This is horrifically weak, but this is an exercise in
# merging two computer languages, not in natural language
# parsing, and anyway I'm not a genius like Graham Nelson.
if ($besterr<2) {
print "What do you mean by $token[0]"; }
else {
print "What do you want to";
$g=$bestgram;
@gramline = @$g;
$gramtoken= @{gramline[0]};
$gramverb = @gramline[1];
foreach (0..($besterr-1)) {
print " " . $token[$_];
}
}
print "?\n> ";
}
}
So, how can I better deal with syntax like that?
Is there something more advanced I can do with
templates, that will let me capture the bits that
follow and create a nested hash structure, something
like
$obj{objectname}{propertyname}=$propertyvalue
? Each object can have numerous properties, but if I
can just store the short_name and description that
will be a good start.
I think all I need is a shove in the right direction.
Pointers? Advice? Comments?
sub H{$_=shift;while($_){$c=0;while(s/^2//){$c++;}s/^4//;$
v.=(' ','|','_',"\n",'\\','/')[$c]}$v}sub A{$_=shift;while
($_){$d=hex chop;for(1..4){$pl.=($d%2)?4:2;$d>>=1}}$pl}$H=
"16f6da116f6db14b4b0906c4f324";print H(A($H)) # -- jonadab
Re: Pointers on working with another language's syntax
by CountZero (Bishop) on Feb 17, 2003 at 19:58 UTC
|
Is that the language in which the text adventures of Zork et al. were written? Fond memories of long nights spend in solving them, come back. But for a solution of your problem: I would put the Inform code after a __DATA__ statement and then read the Inform code into a hash-structure (or more likely a hash of hashes of ... (just guessing as I don't know anything about the Inform language so the exact structure/grammar/rules are totally opaque to me) Your Perl-Inform parser/interpreter can then manipulate this data structure in the "usual" way. CountZero "If you have four groups working on a compiler, you'll get a 4-pass compiler." - Conway's Law
| [reply] |
|
It's not the same language, no. But it compiles to the same virtual machine: the Z-machine. Inform was written to be a nice free compiler for the z-machine. It's actually a very nice OO language (well, as far as writing games goes).
If you've listened to Mr Sugalski, you may have heard him talk about how he'd love to have Parrot be able to run z-code. Which would be fun.
-- Iain, aka Koschei.
| [reply] |
|
$datum{$objectname}{$propertyname}=$propertyvalue;
$datum{$objectname}{$attributename}=(($attr)?1:0);
As an added bonus, this way of doing it will allow
me to give the Inform objects hardware short names,
declare their parents, and so on. Simply wonderful.
The only downside is, this prevents me from putting
a bunch of Perl code at the end as I was doing, but
I can live with that restriction.
sub H{$_=shift;while($_){$c=0;while(s/^2//){$c++;}s/^4//;$
v.=(' ','|','_',"\n",'\\','/')[$c]}$v}sub A{$_=shift;while
($_){$d=hex chop;for(1..4){$pl.=($d%2)?4:2;$d>>=1}}$pl}$H=
"16f6da116f6db14b4b0906c4f324";print H(A($H)) # -- jonadab
| [reply] [d/l] [select] |
|
You could get the same effect with "here" documents, i.e. "<<EOF" style. That way you could continue to mix perl and Inform code and gain more points for obfuscation.
| [reply] |
|
Is that the language in which the text adventures of Zork et al. were written?
Not Zork, but a great many of the modern classics
in the same genre: _Curses_, _The Meteor, the Stone,
and a Long Glass of Sherbet_, _Spider and Web_,
_Christminster_, _Delusions_, and so on and so forth.
There is also a clone of _Adventure_ (the cave game
that inspired Zork), though the original was written
in Fortran I think.
Zork itself (and the other Infocom games) were written
using a language and a compiler that AFAIK no longer
exist. It is said to have been similar to MDL.
Do a Google Groups search for the word "zil" in the
group rec.arts.int-fiction for more information.
You will have to wade through some repetition and
a lot of people asking questions to which there are
few answers, but there is also some real information
and a short code snippet or two.
However, when Activision went back and produced _Zork:
The Undiscovered Underground_ (to re-awaken interest
in the Zork series, since they were also doing a
graphical game set in the same universe), they used
Inform, since the language used for Zork had been lost.
And, as the other pointer mentioned, Inform can compile
to the virtual machine that Zork used, which is probably
the second-most widely portable format after ASCII;
the games can be played on anything from thirty-year-old
mainframes to certain brands of pocket calculators
(really). It is one of the few things that can be
objectively said to definitely be more portable Perl.
(Inform also compiles to another VM called glulx,
which is newer and has less historical significance.)
sub H{$_=shift;while($_){$c=0;while(s/^2//){$c++;}s/^4//;$
v.=(' ','|','_',"\n",'\\','/')[$c]}$v}sub A{$_=shift;while
($_){$d=hex chop;for(1..4){$pl.=($d%2)?4:2;$d>>=1}}$pl}$H=
"16f6da116f6db14b4b0906c4f324";print H(A($H)) # -- jonadab
| [reply] [d/l] |
Re: Pointers on working with another language's syntax
by jonadab (Parson) on Feb 17, 2003 at 14:19 UTC
|
It occurs to me that perhaps I should be more clear
about precisely what syntax is giving me trouble.
It is the Object declaration syntax, which in detail
runs thusly:
Classname objectid "Hardware Short Name" parent
class someclass anotherclass yetanotherclass,
with propertyname propertyvalue,
anotherproperty anothervalue,
propertythree list of values,
propertyfour [ localvar anotherlocal;
print "This is an embedded routine^";
anotherlocal=do_stuff(localvar);
"Result: ", anotherlocal;
],
has booleanattribute anotherattribute attrthree;
I don't need to handle all of that, though.
The hardware short name is optional, as is the
parent. (An object can be moved to another place
in the object tree in the Initialise routine if
need be.) The Classname can just be Object, and
I don't really need class clauses, since I'm not
doing anything sufficiently advanced to need more
classes. I would like to be able to ignore
an arbitrarily long list of boolean attributes
following has, but the Perl code doesn't need to
actually do anything with them. I don't
really need embedded routines either. (I'm not
doing anything full-fledged, just a small proof
of concept, really.) What I'm mostly after are
string (and maybe numeric) property values. I
want to be able to put in Inform code like the
object declarations in my earlier example and
have the strings stored away, like I described.
sub H{$_=shift;while($_){$c=0;while(s/^2//){$c++;}s/^4//;$
v.=(' ','|','_',"\n",'\\','/')[$c]}$v}sub A{$_=shift;while
($_){$d=hex chop;for(1..4){$pl.=($d%2)?4:2;$d>>=1}}$pl}$H=
"16f6da116f6db14b4b0906c4f324";print H(A($H)) # -- jonadab
| [reply] [d/l] [select] |
|
|