Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

Pointers on working with another language's syntax

by jonadab (Parson)
on Feb 17, 2003 at 04:02 UTC ( #235879=perlquestion: print w/replies, xml ) Need Help??

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

Replies are listed 'Best First'.
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

      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.

      I would put the Inform code after a __DATA__ statement and then read the Inform code

      Brilliant! Why didn't I think of that?

      into a hash-structure (or more likely a hash of hashes of

      Yes, it will need to be a nested structure. Something like

      $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
        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.
      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
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

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://235879]
Front-paged by broquaint
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others meditating upon the Monastery: (2)
As of 2023-09-26 03:14 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?