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

Writing my own IF engine.

12 views
Skip to first unread message

MeshGear

unread,
Feb 1, 2006, 8:01:15 PM2/1/06
to
Well, I had some C++ knowledge, so I figured why not (reinvent the wheel no
matter how unecessary it was to do so, especially considering the
pre-existing wheels are pretty fine)? So, three weeks later, I think I
actually legitimately know C++ now. And, er, I have a basic script
interpretor. Whoot.

Anyway, I can imagine that others would've tried this, so I guess I'm
looking for advice (other than stop before I go crazy. It's a LITTLE late
for that now). Not so much CODING advice, because I think I can do that, but
mostly stuff on, er, the usual pitfalls of amateur IF engines. So that,
like, I can avoid these pitfalls.

Oh, er, to describe it, the system's basically an interpretor for a rather
spartan (but hopefully, eventually, turing complete) scripting language,
along with this other setup which uses the same, er, syntax, and is sort of
similar to XML. This basically allows for arbitrary creation of, er,
objects, which are stored in text files. Each text file is sort of a class,
although it's really an organizational method. The general goal, for me, is
to see how non-specific and open I can get the system. My major concern is
slowdown, given that it's purely interpreted, although the search function
can index through a 70000 entry vector in about five seconds. Which I guess
is actually pretty slow, although I'm not sure how big the scriptfiles will
end up getting so maybe it won't matter.


Neil Cerutti

unread,
Feb 2, 2006, 9:30:02 AM2/2/06
to
On 2006-02-02, MeshGear <amcco...@bright.net> wrote:
> Well, I had some C++ knowledge, so I figured why not (reinvent
> the wheel no matter how unecessary it was to do so, especially
> considering the pre-existing wheels are pretty fine)? So, three
> weeks later, I think I actually legitimately know C++ now. And,
> er, I have a basic script interpretor. Whoot.
>
> Anyway, I can imagine that others would've tried this, so I
> guess I'm looking for advice (other than stop before I go
> crazy. It's a LITTLE late for that now). Not so much CODING
> advice, because I think I can do that, but mostly stuff on, er,
> the usual pitfalls of amateur IF engines. So that, like, I can
> avoid these pitfalls.

Pay attention to text presentation. Line-wrapping and newlines
must be consistent and logical, or your work will look shoddy.

Consider using an existing line-reading library for getting input
from the player. Standard ostreams are not going to cut it. Nice
editing commands and command history are ideal.

It's a good idea to design and code a complete game in your
system, and continue updating that code as you add features. If
you don't want to design an original game, then port
Adventure/Collosal Cave.

After you complete your interpreter, and it's reasonably
complete, consider redesigning and starting over from scratch
using the information you learned along the way.

--
Neil Cerutti
Not only is he ambidextrous, he can throw with either hand.
--Duff Daugherty

MeshGear

unread,
Feb 2, 2006, 3:30:06 PM2/2/06
to

> Pay attention to text presentation. Line-wrapping and newlines
> must be consistent and logical, or your work will look shoddy.

I've got a set of escape sequences implemented, so hopefully this isn't
really an engine dependenct thing. However, I'm not really sure how
consistent line-length is between command consoles, dos boxes, and... er,
the linux and mac equivalents thereof are.

> Consider using an existing line-reading library for getting input
> from the player. Standard ostreams are not going to cut it. Nice
> editing commands and command history are ideal.

Definitely worth checking into, yes. Or I might try my hand at writing my
own ('cause I'm a bit of a nutter ^^). thanks for the heads up, here.

> It's a good idea to design and code a complete game in your
> system, and continue updating that code as you add features. If
> you don't want to design an original game, then port
> Adventure/Collosal Cave.

I sort of AM doing this. Although, the game I had in mind isn't terrribly
normal, so yes, doing a partial port of Adventure is probably a good idea.

> After you complete your interpreter, and it's reasonably
> complete, consider redesigning and starting over from scratch
> using the information you learned along the way.

My design goal is to have each function be independant enough that, if I
completely rewrite a function, it should have a minimal effect on the rest
of the code. Also ideally, if/when I DO rewrite the main workings, the
functions will be concrete and independant that they can be safely re-used,
re-arranged, and what have you without having to gut everything.


peersc...@gmx.net

unread,
Feb 2, 2006, 3:51:26 PM2/2/06
to
MeshGear wrote:
> Well, I had some C++ knowledge, so I figured why not (reinvent the wheel no
> matter how unecessary it was to do so, especially considering the
[snip]

In a shameless attempt of self-advertising I would like to point at my
"Interactive Fiction Authoring System Developer's Guide" at
http://www.wolldingwacht.de/if/if-auth-dev-guide.html

Peer

ChicagoDave

unread,
Feb 2, 2006, 4:35:52 PM2/2/06
to
Very nice. I'd like to see the Parser and World Model sections expanded
with some of the debates we've had over the years.

David C.

MeshGear

unread,
Feb 3, 2006, 4:18:28 PM2/3/06
to
OKay, this is a sort of document on what I've done so far. Trigger isn't
properly implemented yet, and I'm still working on streamlining the way the
built in variables and data levels are handled. Currently, the source code
only uses the vector class. I'm proud of that for SOME reason.

1) All functions/objects start with <(|NAME). The | is for disambiguation.
2) All functions/objects end with >(stop);
3) All lines must end in a semi-colon.
4) There are three classes, at present. The classes are largely illusory.
Objects of these classes can generally be anything. There's no limit on
number of members. Also, each object can be entirely different.
5) Comments can be written in the form of either empty functions (not
recommended) or by just putting text outside
6) Parameters in commands are delimited by space. Extra white space probably
isn't a problem.
7) If a command is embedded in a label or another command, don't use
parentheses with it.

File Setup:

Generally, a function is executed sequentially, and most contain commands.
An object is more or less a data table. It contains labels, written in the
form of label(something). Something is typically a function call, a command
with parameters

A. Commands.

<(|NAME); - Declares the start of a function/object.

call(Data Level, Function Name) - Calls a function.

if(Variable to test, operator code, value to test, command to do if true)

pop_stack(|4) - Pops the parser stack. This is used when changing which
input string is being focused on.

print(String of stuff to print) - Prints whatever's in the parentheses. Also
currently has capability of printing something at data level, object, label.
This functionality maybe removed.

makevar(variable name, initiali value) - Makes a variable. It's probably
best to start all values in the startscript.txt, to, er, stop them from
being progressively remade. Which would break things.

setvar(variable, value) - Sets variable to value.

trigger(Data Level, Object Name, Label Name, [/$ Error Message], [/? Next
command to call) - Calls command at label in object.


>(stop); - Declares end of a function or object.

B. Escape sequences.

Escape sequences are written in the form of _ "sequence."

_ variable_name - Prints the value of a variable. Also used when embedding
variables within commands.
_ cret - Newline
_ 3tab - three-space tab.
_ 5tab - Five-space tab.
_ nsp - Backspace.
_ psp - Put space.
_ fpar - (
_ bpar - )
|| - Use if an escape sequence would normally end the string.

C. Data Levels.

There are six of these. They refer to the three classes, scripts, and the
parser stack.

0 - Room
1 - Verbs
2 - Objects
3 - Actors
4 - Parser tokens
5 - Scripts

D. Operator Codes.

The if statement takes these for comparison operations.

1 - ==
2 - !=
3 - >>
4 - <<
5 - >=
6 - <=
7 - !>
8 - !<
9 - !>=
10 - !<=

Only the first six are implemented, currently. The last four seem sort of

odd and useless.


Samwyse

unread,
Feb 3, 2006, 7:29:27 PM2/3/06
to
MeshGear wrote:
>>It's a good idea to design and code a complete game in your
>>system, and continue updating that code as you add features. If
>>you don't want to design an original game, then port
>>Adventure/Collosal Cave.
>
> I sort of AM doing this. Although, the game I had in mind isn't terrribly
> normal, so yes, doing a partial port of Adventure is probably a good idea.

Code your own game, of course, then Cloak of Darkness (small but it's a
standard for comparing authoring systems), and then code Adventure (as
big as anything anyone is likely to want to build, plus one or two
instances of every classic puzzle known to I-F).

Samwyse

unread,
Feb 3, 2006, 8:11:48 PM2/3/06
to
MeshGear wrote:
> OKay, this is a sort of document on what I've done so far. Trigger isn't
> properly implemented yet, and I'm still working on streamlining the way the
> built in variables and data levels are handled. Currently, the source code
> only uses the vector class. I'm proud of that for SOME reason.
>
> 1) All functions/objects start with <(|NAME). The | is for disambiguation.

OK, I pretty much stopped reading here. I'm a professional programmer
who occasionally deludes himself into thinking he can write, but most IF
authors are people who can write and delude themselves into thinking
they can program. If you want to create a system that other people will
use, make sure that it can be understood by liberal arts majors, not
engineers.

Most of a work of I-F consists of data structures, not code. An
authoring tool should concentrate on making that both easy and
comprehensible for a complete newbie. (TADS-3 aims toward the former,
Inform 7 the latter.)

Although I'm continually disappointed that no one uses it, I'm quite
proud of my program for converting I-F transcripts into Inform code. (I
suspect that it would be more successful if it were a standalone
executable, not a Perl script.) I'm also working on a conversation
editor; I'm slowly concluding that it will have to provide a web-based
interface that uses a data-mining/data-cube approach, so the author can
not only easily group together all of an NPC's utterances, but also all
NPC's utterances on a given topic. Only later will I work on actual
coding, and there I'm planning on using the Interactive Fiction
Modeler's language instead of inventing my own.

MeshGear

unread,
Feb 6, 2006, 1:23:35 AM2/6/06
to
Kay. Took some of what you said into account and worked on coming up with a
more unified syntax. Also, I'd like to note that the description I gave
really wasn't made to be a help file like thing. Just... I dunno. A
description.

Anyway, syntax is basically:

command(data);. Sort of C-styled, although not EXACTLY. Individually, sytanx
sort of follows this "grammar."

command(variable # value);. The # indicates what, exactly, the value is. #
means that value is a number. _ means that value is another variable. $
means that it's a string. This is sort of the equivalent of putting strings
in quotes in C++, I guess, only it doesn't look nearly as good. $ looks like
S, so that makes sense, and # means number. _ is sort of weird for
variables. I thought about a ^ (upside down v?)

There's also this variant:

command@(data);. The @ just means that the command is using data
stored -at- some position in a class.

So, yeah. The syntax is still a little weird looking, but it's generally
standardized now. This also helps me. Hopefully, I can get a working version
of Cloak of Darkness sometime this week. In the meantime, I fully plan on
playing the heck out of a lot of TADS and inform games to figure out how
exactly they handle parsing and world models.


Uli Kusterer

unread,
Feb 6, 2006, 2:08:06 PM2/6/06
to
In article <zIudnelYsID3dnve...@bright.net>,
"MeshGear" <amcco...@bright.net> wrote:

> command(data);. Sort of C-styled, although not EXACTLY. Individually, sytanx
> sort of follows this "grammar."
>
> command(variable # value);. The # indicates what, exactly, the value is. #
> means that value is a number. _ means that value is another variable. $
> means that it's a string. This is sort of the equivalent of putting strings
> in quotes in C++, I guess, only it doesn't look nearly as good. $ looks like
> S, so that makes sense, and # means number. _ is sort of weird for
> variables. I thought about a ^ (upside down v?)

Why do that? I suspect you haven't written a real parser and tokenizer.
You really want to do that to be much less restricted with regard to
what your language can look like. Use less fancy symbols and more words,
your users will more easily remember them.

Forget about variable markers and data type markers. As someone else so
eloquently said, write for liberal arts majors. Data types should be an
internal detail as much as possible, code should be verbose or at least
use a standardised notation people very likely already know (like C,
which is mostly based on stuff you know from maths class).

Also, have objects and files independent. If every file is implicitly a
class or an object, that's very restricting to your users. Let them
decide whether to group those fifteen objects in one file or give that
huge object its own file.

People are relatively used to having spoken text in quotes, so that's
something you can build on. Though in the case of IF I suggest you offer
an alternative type of quotation mark because you actually use quotes in
text. In one of my attempts I used

output <<"Hello," said Pete, "what can I do for you?">>

Because << and >> looks like guillemets and thus is pretty readable for
people, though I'm not too happy about it. It just avoids the whole mess
of remembering to write

output "\"Hello\", said Pete."

Just my $0.02.

Cheers,
-- Uli
http://www.zathras.de

David Fisher

unread,
Feb 6, 2006, 5:52:15 PM2/6/06
to
"Uli Kusterer" <wit...@t-online.de> wrote in message
news:witness-A77F88...@news.t-online.com...

>
> Forget about variable markers and data type markers. As someone else so
> eloquently said, write for liberal arts majors. Data types should be an
> internal detail as much as possible

On and off, I have been going through the Inform library code, and one of
the greatest hindrances to understanding it is the fact that there are no
type declarations in the Inform language.

In reality, every variable does have a type. Some examples are: number,
character, string, object, routine, property, bitmask, boolean, subrange
(eg. 0 to 9), numeric code (similar to a C "enum").

To figure out the actual type of some variables in the Inform library, I
have had to trace through quite a few levels of routine calls to see how the
variable is used and what values it is expected to have.

Granted, more comments in the code could have fixed this problem, but a huge
advantage of declaring the type of a variable is that the compiler can
automatically check if it is being used correctly. If you say "x = 4" when x
is meant to be a string, the compiler can point out the error straight away.

Another advantage of declaring types is that the compiler can do things like
printing a variable correctly, instead of the programmer having to say
(string) x or (char) x, etc.

So - what about the liberal arts majors ? My view is that since there really
are types in the language, they will have to come to grips with that fact
sooner or later - so you might as well make them explicit in the language
(or at the very least, *allow* the programmer to be explicit about them).

David Fisher


REH

unread,
Feb 6, 2006, 6:17:42 PM2/6/06
to

You will give yourself a lot less headaches if you design your langauge
before you try and code it. I would begin by deciding on the scope of
the language, the complexity of it, its "features." Decide what will
and will not be include in your first release. The will help you
define boundaries for you project, or you will never be done. Define
your grammer, explicitly. Map it out in some exact meta-language, like
BNF. If you are not familar with parsing, study up on it. Parsing can
be quite easy, and elegant, and fun to code if you know how. The bible
for this is the so-called "Dragon Book" ("Compilers: Principles,
Techniques and Tools," by Aho, et. al). Before reading that book, I
had thought implementing parsers to be hard, and I wrote ugly, ugly,
parsers. The book will also give you insight into writing your
language so it is easier to parse.

You may also want to look at compiler compilers, which will generate
the parser for you from a description of the language. The advantage
of these is that it makes your parser more maintainable. It is easier
to read and modify a description of your language, then the code that
parses your language. There are some really good (and free!) ones.
The mose popular is probably Lex and Yacc (or GNU's Bison) which create
your lexer and parser, respectively. I love Antlr, which is also free.
It is easy to use and very powerful (allows infinite lookahead). It
is written in Java and will generate Java, C++, or C# (and maybe a
couple other languages) code. I think someone also did a C++
translation if you don't want to use a Java tool.

You should also think about your testing strategy. It should be part
of your design, not an after thought. If you start testing from the
start, it will save you countless hours in the long run. By having
thorough, automated tests it will be easy to know if additions or
changes you make later break something.

I think the main thing is to start small. It's easy at the beginning
to get sweeped up in the "do everything" mentality. I say start small
and make it solid. Placing the importants on making it easy to
understand, maintain, and modify.

REH

MeshGear

unread,
Feb 6, 2006, 6:24:45 PM2/6/06
to
Well, realistically, I'm writing this for myself. If someone else feels like
figuring it out, more power to them. I'm not really going for wide-spread
appeal, here. If I wanted that, then... well, there's TADS and Inform. I
don't really feel the need to compete with them. There's nothing WRONG with
them. I just like programming this stuff.

Anyway, the main reason I don't do type declarations is because I'd have to
store type information somewhere in the program, and, erm, it'd probably
require code more complicated than a switch/case statement that ran through
#, _, or $. As such, maybe performance would take a hit. That'd be pretty
bad :(. So, while, they're basically typeless (actually, strings. All of
them) either context or the little identifier thing will give a clue as to
how they're functioning, at least.

As for classes being tied to files... Realistically, it'd take another...
five to ten lines of code to have any number of files being loaded in at
startup. Given the setup I have now, though, it'd either involve having a
vector of vectors (which I don't really feel like messing around with) or
loading each file as it comes up, reading from it, and closing it (which
sounds inefficient). If it gets problematic when wokring through it myself,
I'll change it, although it looks okay for the time being. An easy solution
would be to build in 10-20 wildcard object and scriptfile spaces. This'd
boil down to about 30 or so possible source files for use when all is said
and done, which should satisfy most requirements.


Fish

unread,
Feb 7, 2006, 1:57:24 AM2/7/06
to
David Fisher wrote:
> So - what about the liberal arts majors ? My view is that since there really
> are types in the language, they will have to come to grips with that fact
> sooner or later - so you might as well make them explicit in the language
> (or at the very least, *allow* the programmer to be explicit about them).

There is a rule in business that applies here. "You can't train your
customers to be more convenient for YOU. You can only train yourself to
make things easier for your customers."

Write the IF engine with as many technical hurdles as you want -- with
as steep a learning curve as you desire. An IF engine design will get
the patronage it earns.

Samwyse

unread,
Feb 7, 2006, 6:35:08 AM2/7/06
to
REH wrote:
> MeshGear wrote:

>>So, yeah. The syntax is still a little weird looking, but it's generally
>>standardized now. This also helps me. Hopefully, I can get a working version
>>of Cloak of Darkness sometime this week. In the meantime, I fully plan on
>>playing the heck out of a lot of TADS and inform games to figure out how
>>exactly they handle parsing and world models.

Don't just play them, read the source code as well. TADS and Inform
both have very good parsers that are hidden inside their libraries.
These parsers take up a lot more code that you may expect.

> You will give yourself a lot less headaches if you design your langauge
> before you try and code it. I would begin by deciding on the scope of
> the language, the complexity of it, its "features." Decide what will
> and will not be include in your first release. The will help you
> define boundaries for you project, or you will never be done. Define
> your grammer, explicitly. Map it out in some exact meta-language, like
> BNF. If you are not familar with parsing, study up on it. Parsing can
> be quite easy, and elegant, and fun to code if you know how. The bible
> for this is the so-called "Dragon Book" ("Compilers: Principles,
> Techniques and Tools," by Aho, et. al). Before reading that book, I
> had thought implementing parsers to be hard, and I wrote ugly, ugly,
> parsers. The book will also give you insight into writing your
> language so it is easier to parse.

I've said elsewhere that to solve the problems I encounter at work,
design a domain-specific language and then implement a
compiler/interpreter for it. That's basicly what you're doing. The
best way that I've found to do that is to write programs in my language
and then see what the computer needs to "understand" it. I'll concede
that having done this for a while, I tend not to use things that are
hard to parse. In other words, I'd first write Cloak of Darkness and
see what sort of language results. OTOH, I can see why people, like
yourself, who don't do this every day might want to implement a compiler
first and then code some games.

> You should also think about your testing strategy. It should be part
> of your design, not an after thought. If you start testing from the
> start, it will save you countless hours in the long run. By having
> thorough, automated tests it will be easy to know if additions or
> changes you make later break something.

A huge headache for the group that maintains Inform is the lack of a
good test suite. Producing one is about as much fun as documenting your
code. The extreme programming crowd advocates writing your test suite
first, so you can know when your translator works and when it doesn't.
I'd echo that.

> I think the main thing is to start small. It's easy at the beginning
> to get sweeped up in the "do everything" mentality. I say start small
> and make it solid. Placing the importants on making it easy to
> understand, maintain, and modify.

Ditto. Inform is a lot bigger than you may think, and TADS is even
larger. I'd start off with just your langauage's version of a
pre-processor, then go to a "Hello, world!" program, then a parser, and
finally a full fledged translator.

And speaking of translators, what's your output going to be? Your own
byte-code of the month or a C/Java program? If you want to produce
byte-code, don't invent your own, use Glulx. There are already
interpreters for it, so your games can be shared with everyone.
Producing a different high-level language restricts the number of
players, but it does make the translation process a lot easier. My I-F
tools tend to produce Inform code as output from languages that are each
designed to handle one aspect of I-F design; to date this is
rooms/scenery and NPC conversation.

Mark J. Tilford

unread,
Feb 7, 2006, 7:51:08 AM2/7/06
to

There's also The Flower Garden
http://geocities.com/ralphmerridew/

It's a simple case of disambiguation. It includes working Inform, TADS 2,
and Alan 2 source code, plus demo transcripts.

--
------------------------
Mark Jeffrey Tilford
til...@ugcs.caltech.edu

Neil Cerutti

unread,
Feb 7, 2006, 8:25:58 AM2/7/06
to
On 2006-02-06, David Fisher <da...@hsa.com.au> wrote:
> "Uli Kusterer" <wit...@t-online.de> wrote in message
> news:witness-A77F88...@news.t-online.com...
>> Forget about variable markers and data type markers. As someone
>>else so eloquently said, write for liberal arts majors. Data types
>>should be an internal detail as much as possible
>
> On and off, I have been going through the Inform library code, and
> one of the greatest hindrances to understanding it is the fact that
> there are no type declarations in the Inform language.

It's not really the lack of type names that's bothersome. It's
declarations like these:

[ Keyboard a_buffer a_table nw i w w2 x1 x2;

[ WriteListR o depth stack_pointer classes_p sizes_p i j k k2 l m n q senc mr;

...combined with the large size of many of the routines, and the
goto-tangle that comprises their structure.

Neither of those two routines becomes particularly easier to read with
these type declarations:

[ Keyboard
ParseBuffer a_buffer,
Table a_table,
Number nw, Number i,
DictionaryWord w, DictionaryWord w2,
Address x1, x2;

[ WriteListR
Object o,
Number depth,
Address stack_pointer,
Address classes_p,
Address sizes_p,
Number i, Number j, Number k, Number k2,
Object l,
Number n, Number q, Number senc, Number mr;



> In reality, every variable does have a type. Some examples are:
> number, character, string, object, routine, property, bitmask,
> boolean, subrange (eg. 0 to 9), numeric code (similar to a C
> "enum").

The type system your suggesting is quite a bit more elaborate than
what Inform (and most other languages) currently supports, but yes,
all variables do have types.

> To figure out the actual type of some variables in the Inform
> library, I have had to trace through quite a few levels of routine
> calls to see how the variable is used and what values it is expected
> to have.

Can you give an example? In most cases, types are either obvious or
not relevant.

> Granted, more comments in the code could have fixed this problem,
> but a huge advantage of declaring the type of a variable is that the
> compiler can automatically check if it is being used correctly. If
> you say "x = 4" when x is meant to be a string, the compiler can
> point out the error straight away.

It's an advantage, but not a huge advantage. Run-time type checking
requires thorough testing, but strict compile-time checking doesn't
actually save you from that requirement.

Variadic types, a la Ocaml, would be required to preserve ease-of-use,
e.g.:

Property ( LowString | Routine } short_name;
Property ( LowString | Routine } description;

Individual properties would henceforth need to be prototyped, or just
scrapped altogether.

> Another advantage of declaring types is that the compiler can do
> things like printing a variable correctly, instead of the programmer
> having to say (string) x or (char) x, etc.
>
> So - what about the liberal arts majors ? My view is that since
> there really are types in the language, they will have to come to
> grips with that fact sooner or later - so you might as well make
> them explicit in the language (or at the very least, *allow* the
> programmer to be explicit about them).

Ocaml's strong, strict, infered type system offers, according to its
designers, the best of both worlds: Compile-time type-checking, with
no boring prototyping required. However, in Ocaml type inference
applies only to procedures. Inside a procedure, you must call
the correct procedures for the types you expect.

let average a b =
(a .+ b) ./ 2.0;;

.+ is the addition operator for floating point values. Ocaml evalues
the type of average to be:

val average : float -> float -> float = <fun>

In other words, a function taking two floats and returning a float.

Either of the following would produce an error:

let average a b =
(a .+ b) ./ 2;;

Since 2 is an Integer, which you cannot pass to ./, the floating
point division procedure.

let average a b =
(a + b) ./ 2.0;;

In this case, the result of + is an Integer, which you likewise cannot
pass to ./.

So you wouldn't be freed from writing things like (string) name in
print statements.

--
Neil Cerutti

REH

unread,
Feb 7, 2006, 9:50:43 AM2/7/06
to

Samwyse wrote:
> I've said elsewhere that to solve the problems I encounter at work,
> design a domain-specific language and then implement a
> compiler/interpreter for it. That's basicly what you're doing. The
> best way that I've found to do that is to write programs in my language
> and then see what the computer needs to "understand" it. I'll concede
> that having done this for a while, I tend not to use things that are
> hard to parse. In other words, I'd first write Cloak of Darkness and
> see what sort of language results. OTOH, I can see why people, like
> yourself, who don't do this every day might want to implement a compiler
> first and then code some games.
>
I'm not sure what "this" in your last sentence refers to. If you mean
"write software," I've been doing that for about thirty years, twenty
professionally. If you mean make IF games, you're correct. The last
adventure I wrote was in '83 in BASIC.

I did not say implement a compiler first. I said he should design his
language first, before he starts to code it. Writing code is trivial.
It's constantly having to re-write code because you change you mind
that's a headache. If I were he and really serious about this, I would
design the language and get a lot of feedback from the target user (in
this case, I assume TADS, Inform, et. al., users) before I wrote one
line of code.

REH

David Fisher

unread,
Feb 7, 2006, 6:43:13 PM2/7/06
to
"Neil Cerutti" <lead...@email.com> wrote in message
news:slrnduh7ub.1...@FIAD06.norwich.edu...

> On 2006-02-06, David Fisher <da...@hsa.com.au> wrote:
>>
>> On and off, I have been going through the Inform library code, and
>> one of the greatest hindrances to understanding it is the fact that
>> there are no type declarations in the Inform language.
...

>> In reality, every variable does have a type. Some examples are:
>> number, character, string, object, routine, property, bitmask,
>> boolean, subrange (eg. 0 to 9), numeric code (similar to a C
>> "enum").
>
> The type system your suggesting is quite a bit more elaborate than
> what Inform (and most other languages) currently supports, but yes,
> all variables do have types.

All of them are found in the Inform library code (examples are mostly from
parserm.h):

number - "score"
character - contents of "buffer" array
string - all the constants ending with "__TX"
object - "thedark"
routine - 1st argument to PrintOrRun can be a routine (as a property of an
object)
property - PrintOrRun again
bitmask - indef_type (combination of values ending in "_BIT" - see
NounDomain)
boolean - "meta"
subrange - "lookmode" (1, 2 or 3)
numeric code - tokens (ending with "_TOKEN" - see DebugToken for a list). In
C this could be an "enum".

Some other types are arrays, dictionary entries and classes.

>> To figure out the actual type of some variables in the Inform
>> library, I have had to trace through quite a few levels of routine
>> calls to see how the variable is used and what values it is expected
>> to have.
>
> Can you give an example? In most cases, types are either obvious or
> not relevant.

I'd have to go and find my notes, but I remember a variable which looked
like a boolean value (0 or 1) which can actually have other values as well,
which was very misleading (there is a similar situation in an old program I
am involved in at work, which has caused lots of problems). There was also a
variable which was re-used with a completely different type at one point,
which just confuses things.

...


> Ocaml's strong, strict, infered type system offers, according to its
> designers, the best of both worlds: Compile-time type-checking, with
> no boring prototyping required.

This could work too, but I have heard some negative comments about inferred
type systems (eg. "how on earth did the compiler deduce *that* ??").

My main point is that the programmer needs to understand the different types
that exist in the language, and it is better to be up front about it.
Ideally you could have an IDE that filled in the declarations for you so you
don't have to worry about typing them, but I think they are worth it in
spite of any extra effort.

David Fisher


Andrew Plotkin

unread,
Feb 7, 2006, 7:01:51 PM2/7/06
to
Here, David Fisher <da...@hsa.com.au> wrote:
> "Neil Cerutti" <lead...@email.com> wrote in message
> news:slrnduh7ub.1...@FIAD06.norwich.edu...
> >
> > The type system your suggesting is quite a bit more elaborate than
> > what Inform (and most other languages) currently supports, but yes,
> > all variables do have types.
>
> All of them are found in the Inform library code (examples are mostly from
> parserm.h):
>
> number - "score"
> character - contents of "buffer" array
> string - all the constants ending with "__TX"
> object - "thedark"
> routine - 1st argument to PrintOrRun can be a routine (as a property of an
> object)

(etc)

One would want to be clearer about terminology here:

You're listing the types that Inform *values* can have. A *variable*
is a more complicated matter. For example, many variables in the
library are of a type best described as {string|object|routine}. That
is, the variable can have any of those types -- legally -- and the
code will do an appropriate thing with each of them. (In fact, such
variables can usually contain 0 also, and often 1.)

(Which is quite separate from reused or conditional-separated
variables, which might contain different types at different times or
under different circumstances. That is a matter of library efficiency,
or obfuscation if you like, which could be untangled.)

Then there are variables which are genuinely untyped. For example, the
second argument to ChangeDefault() can be of any type which might be
the value of a property -- i.e., any type at all.

--Z

--
"And Aholibamah bare Jeush, and Jaalam, and Korah: these were the borogoves..."
*
If the Bush administration hasn't subjected you to searches without a warrant,
it's for one reason: they don't feel like it. Not because you're an American.

David Fisher

unread,
Feb 7, 2006, 7:43:03 PM2/7/06
to
"Andrew Plotkin" <erky...@eblong.com> wrote in message
news:dsbcde$piu$1...@reader2.panix.com...

> One would want to be clearer about terminology here:
>
> You're listing the types that Inform *values* can have. A *variable*
> is a more complicated matter. For example, many variables in the
> library are of a type best described as {string|object|routine}. That
> is, the variable can have any of those types -- legally -- and the
> code will do an appropriate thing with each of them. (In fact, such
> variables can usually contain 0 also, and often 1.)
>
> (Which is quite separate from reused or conditional-separated
> variables, which might contain different types at different times or
> under different circumstances. That is a matter of library efficiency,
> or obfuscation if you like, which could be untangled.)
>
> Then there are variables which are genuinely untyped. For example, the
> second argument to ChangeDefault() can be of any type which might be
> the value of a property -- i.e., any type at all.

Fair 'nuf ...

Thanks for the clarifications,

David Fisher


Samwyse

unread,
Feb 7, 2006, 10:26:00 PM2/7/06
to
REH wrote:
> Samwyse wrote:
>
>>I've said elsewhere that to solve the problems I encounter at work,
>>design a domain-specific language and then implement a
>>compiler/interpreter for it. That's basicly what you're doing. The
>>best way that I've found to do that is to write programs in my language
>>and then see what the computer needs to "understand" it. I'll concede
>>that having done this for a while, I tend not to use things that are
>>hard to parse. In other words, I'd first write Cloak of Darkness and
>>see what sort of language results. OTOH, I can see why people, like
>>yourself, who don't do this every day might want to implement a compiler
>>first and then code some games.
>>
>
> I'm not sure what "this" in your last sentence refers to.

By "this", I meant "design a domain-specific language and then implement
a compiler/interpreter for it."

>

> I did not say implement a compiler first. I said he should design his
> language first, before he starts to code it. Writing code is trivial.
> It's constantly having to re-write code because you change you mind
> that's a headache. If I were he and really serious about this, I would
> design the language and get a lot of feedback from the target user (in
> this case, I assume TADS, Inform, et. al., users) before I wrote one
> line of code.

What comes after designing a language, implementing a compiler or coding
some games? Especially if the language is designed for personal use, I
advocate coding a game first, then writing a compiler for the language
that results. TADS seems to have been designed in this way; if you look
at the examples of coding a conversational NPC, you'll see that you
almost never have to say anything more than once. Not only that, but
many times you don't have to assign names to objects because their
structural relationships make it unneeded. Once a minimal
representation exists, then you need to have templates to allow that
minimal form, and classes that supply the "standard" details about
what's happening.

REH

unread,
Feb 8, 2006, 9:07:25 AM2/8/06
to

I'm not sure I understand you fully. Assuming for a moment that you
have already designed the language, when what is "writing a compiler
for the language that results"? If that's true then you are still
designing the language. I agree that it is good the test the language
by trying to design some non-trivial games with it, and see where the
language is lacking. If that's true, I think we are basically saying
the same thing and just talking across each other.

REH

solar penguin

unread,
Feb 8, 2006, 10:04:24 AM2/8/06
to

David Fisher <da...@hsa.com.au> wrote:

>
> On and off, I have been going through the Inform library code, and
> one of the greatest hindrances to understanding it is the fact that
> there are no type declarations in the Inform language.
>
> In reality, every variable does have a type. Some examples are:
> number, character, string, object, routine, property, bitmask,
> boolean, subrange (eg. 0 to 9), numeric code (similar to a C "enum").

That's not strictly true. Everything is untyped and can represent *any*
value: number, character, string, object, routine, property, bitmask,
boolean, subrange (eg. 0 to 9), numeric code. If it happens to be
holding a number now, that doesn't prevent it from holding a pointer or
a character etc. later. And vice versa. Commands like rtrue and rfalse
make use of this to return boolean numbers instead of a routine or an
object.

--
___ _ ___ _
/ __| ___ | | __ _ _ _ | _ \ ___ _ _ __ _ _ _ (_) _ _
\__ \/ _ \| |/ _` || '_| | _// -_)| ' \ / _` || || || || ' \
|___/\___/|_|\__,_||_| |_| \___||_||_|\__, | \_,_||_||_||_|
|___/
http://www.freewebs.com/solar_penguin/

** Klingons stole the cloaking device from the Royal National College
For The Next 2000 Years.

I see your boss. Tell Jabba that I've never seen the anime.


REH

unread,
Feb 8, 2006, 10:44:48 AM2/8/06
to

solar penguin wrote:

> David Fisher <da...@hsa.com.au> wrote:
>
> > In reality, every variable does have a type. Some examples are:
> > number, character, string, object, routine, property, bitmask,
> > boolean, subrange (eg. 0 to 9), numeric code (similar to a C "enum").
>
> That's not strictly true. Everything is untyped and can represent *any*
> value: number, character, string, object, routine, property, bitmask,
> boolean, subrange (eg. 0 to 9), numeric code. If it happens to be
> holding a number now, that doesn't prevent it from holding a pointer or
> a character etc. later. And vice versa. Commands like rtrue and rfalse
> make use of this to return boolean numbers instead of a routine or an
> object.
>
That does not dispute what he said. A variable will always have a
particular type at a given time. Dynamically-typed (or "untyped")
languages allow you to change what that type is by setting the variable
to a value of a different type. That is not the same as never having a
type.

MeshGear

unread,
Feb 11, 2006, 12:16:27 AM2/11/06
to
Thought I'd post a bit of an update.

I believe that, at present, my system is fully capable of handling the Cloak
of Darkness, and I'm going to assign it, at present, version .0.3. A brief
overview of what it can do:

It has two filetypes associated with it: scriptfiles and object files.
Scripts contain a series of commands shot off in a mostly linear manner,
loops, if-statements, and subroutine calls not regarded.

There are three special scripts: verbs.txt, startscript.txt, and
loadfile.txt these are always loaded on startup. Verbs.txt is basically a
programmable user interface. startscript.txt ideally contains all variable
declarations (you can technically make variables anywhere, although it's
safer to just stick them in some sort of up-front manner to prevent them
from being declared repeatedly. Alternatively, you could stick variable
declarations in a bunch of other script files and have startscript call them
all off in succession). It also has startup text and whatnot.

Erm, yes. And loadfile. It's just a list of which files get loaded, in the
form of:

obj(*.txt) and scr(*.txt). The thing out front specifies whether it gets
shifted into the object vector thinger or the script vector thinger.

My original justification for that data levels thing was dividing up data
into smaller chunks, because working with vector vectors is really awkward
:(. Anyway, I thought the interpretor could do 70000 lines in five seconds.
In reality, that's only cause I was printing the line number at each step.
Without any special optimization lines at compile time, it can actually run
through about one million in two seconds (on a P4 running windows XP. So
yeah, probably slower on other systems. I'll streamline this later if I need
to). Anyway though, since people complained, you can now basically load in
whatever files you want. also, loadfile.txt also conveniently acts as a way
of doing include files (for scripts. The objects don't belong to any defined
classes, so including the methods for dealing with the objects is the only
meaningful stuffs so far).

OKay, so yes, infinite number of files allowed (Well, it's actually probably
limited to a couple million. I think vectors tend to explode around 9999999
entries. Which would be impossibly slow anyway, and also impossible to
manage as far as coding goes. I mean WTF are you storing each line in its
own file?).

Also, since I switched to this, I only really have four different data types
to work with -- objects, scripts, universal vector of magical user
variables, and the pointer vector. The meta pointers I've got going
basically replace all the really obtuse data level stuff. So far, they just
point to various labels within objects, and absorb whatever value you stick
there. Which can consist of commands, words, variables, or lewd ascii
drawings. The last on that list will probably crash the interpretor will
probably read it as bizarre formatting and barf. Anyway, ideally, pointers
will also point at actual variables. This isn't really hard to do. I'm just
not exactly sure how to fit it in with a consistent, uniform syntax. Also,
pointers need the functionality to point at other pointers. I forgot why,
but there's something really cool you can do with this. I think it's like,
if you have a pointer pointing at a variable that contains an object name
and a function pointing at a label in an object, you can set the object in
that second pointer to a pointer to the variable containing the object name,
and, erm, I lost myself.

pointer bob;
bob(object: car label: color);

That'd point bob at whatever value color has.

bob(object: pointer to some object label: color);

And this'd let you change whatever the pointer was pointing at, and get the
color for a lot of things with fewer lines of code. Yes. That's what it's
for.

(setptr(pointer_name # object # label) is the main syntax. I thought abotu
something like setptr(ptr_name __ variable), although double underscore is
ugly. It's the most consistent, though. ^ is sort of reasonable, and I think
I have an escape sequence for it already.)

Ah, also need to introduce a bunch of bizarre stuff involving pointers and
variables. Subroutine calls, for instance, can call a subroutine who's name
is stored in a variable. Just think of all the weird crap you could do if it
could also take a pointer!

Anyway, what needs added, besides the previously mentioned pointer
functionality? More robust flow control, for one thing. I have the syntax
for a loop worked out, for the most part. Needs implementation. Basically
sets a label with the command do(label_name), and when while is hit, it
evaluates some statement, and if true, jumps back to the label. Nothing too
odd.

I've also got this idea for a pseudo-loop. When you run an if statement, it
stores toggles an ifstate variable between 1 and 0, for true and false
respectively. this isn't changed until another if statement is called. As
such, the other command I'm thinking about is called whileif. As long as
ifstate is true, the the command contained within the whileif command gets
executed (something like, whileif(setvar[name,john]); or something).
Effectively, this lets the if command act like a normal if command that has
the brackets and the code in between (only you can break from it, I guess.
Can you do that with other if statements? I've never really tried).

And, erm, some randomization command. Hopefully I can figure out how to get
seeding and randomizing done in a single step.

Oh, also some commands to break a script and return to the command-line, and
some commands to prompt the user for entry. Also, a do_nothing command.

Erm, another goal is to get a more streamlined approach to gamestate
handling and generally handlage of state on things which would have states,
in general. Weird odds and sods. Things that make objects run as scripts.
Pointers to scripts. Something to progressively monitor variable changes so
that I can implement a "when" command. Better methods for handling input
than a linear stack -- something to provide for a then command. The ability
to linearly call a set of script names (or, to trigger through a bunch of
labels in objects. This'd allow for using "get all").

Still out on a built-in undo command. In part because that requires way too
much effort on my part to follow a bunch of variables. It's also, in light
of that randomization topic, probably too apt to spark metagame logic (If
XYZ kills my character, I can just undo) and generally makes the writer less
careful about deadending the player. It should be doable in scripts, though,
somehow.

Erm, next "release" will probably round off the scripting language.
Following that, since it doesn't compile thus no compile time error
checking, and since I opted out of runtime error checking to procue cleaner
code, I'll probably write a debugger. Which'll be more of a spell checker,
really. It'll basically just treat every function name like a verb, and you
can type it in. It'll then find that function, then run through the script
starting there, and print out an error message if anything's hit. It'll then
crash, I guess. Or return from that command, and continue running until it
does crash. It'll primarily check for misspelled functions and undeclared
variables being used (which, from my own messing around with this thing I've
got, account for most of the errors I've done).

also, I sitll have the _ to mark a variable, # to mark something that's NOT
a variable thing going on. I also have $, which marks a string of several
values (for being added to a set/array/whatever you want to call a group of
data). And @, which marks a pointer. These will never go away because I
think they're cute and amusing. Also, they sort of prevent ambiguity (and
also potentially let the user create a variable named 1, which stores a
value of 1, or a set called "real," which stores every real number within
some range. which would be very stupid, but I'm just saying).

And if you read this entire post, you're probably crazier than I am :(


Uli Kusterer

unread,
Feb 11, 2006, 6:29:58 AM2/11/06
to
In article <oIKdnStFVM6...@bright.net>,
"MeshGear" <amcco...@bright.net> wrote:

> And if you read this entire post, you're probably crazier than I am :(

Honestly, I'm interested in the whole "writing your own engine" thing.
But you were right. I took three approaches and got only as far a sthe
first 7 paragraphs. Then I started skipping and finally gave up.

How about some structure? Right now this looks like you had a peek at
the source code and just wrote it out in English. Every decent program
has an underlying thought, a methodology, a structure. Why not just tell
us about that in a few short sentences, bullet-list-style. If you can't,
it's a sign that you really need a better design up front.

We don't want to clone your system, we just want to know about your
approach, and maybe provide some feedback.

Cheers,
-- Uli

PS - The word is spelled "interpreter", no "o" in there. Might help on
Google to find more information.

Samwyse

unread,
Feb 11, 2006, 9:41:59 AM2/11/06
to
REH wrote:

> I'm not sure I understand you fully. Assuming for a moment that you
> have already designed the language, when what is "writing a compiler
> for the language that results"? If that's true then you are still
> designing the language. I agree that it is good the test the language
> by trying to design some non-trivial games with it, and see where the
> language is lacking. If that's true, I think we are basically saying
> the same thing and just talking across each other.

Designing a language is different from implementing it. Let's say I
want a language to support conversations with NPCs. The way that I'd
approach this is to start writing examples of what I want to be able to
do with my language:

Actor Bob {
state: sad {
description => "Bob doesn't seem very glad to see you.",
ask_about store => "Business is lousy.",
ask_about wife => "I think she's having an affair."
},
state: happy {
description => "Bob is dancing with joy.",
ask_about store => "Business is great.",
ask_about wife => "We're planning to take a cruise."
}
}

Then I need to write a program that reads this and turns it into data
objects that my run-time engine can interpret.

The process is iterative. Maybe I decide that I've typing the word
"ask_about" too many times, maybe I can't get the program to figure out
what I'm saying. At that point, I revise the language, and then fix the
compiler.

Uli Kusterer

unread,
Feb 11, 2006, 10:31:30 AM2/11/06
to
In article <XImHf.31650$H71....@newssvr13.news.prodigy.com>,
Samwyse <sam...@gmail.com> wrote:

> Then I need to write a program that reads this and turns it into data
> objects that my run-time engine can interpret.

I'd like to emphasise how right this approach is. Don't design the
language to match your parser/compiler, do it the other way around.
Also, keep in mind K.I.S.S.: While it may look cool and be tempting to
have lots of $something, $something and @something constructs there, and
why that might make it immediately obvious to your parser that after
this character a variable, macro or whatever follows, it requires your
users to memorise these arbitrary characters.

Look at C. How many special characters and indicators does it have? It
has a few operators (most of which everyone knows), and that's basically
it. Imagine the result and then implement it. Don't let the
implementation influence the design beyond what is absolutely necessary.

Cheers,
-- Uli

Xub...@gmail.com

unread,
Feb 11, 2006, 5:08:16 PM2/11/06
to
MeshGear wrote:

[lotsa stuff that I snipped]

> And, erm, some randomization command. Hopefully I can figure out how to get
> seeding and randomizing done in a single step.

How about this: The random () function grabs the system time (as
measured in whatever the smallest possible time-unit is, on that
system) as its seed. Ignore any caveats about how accurate a given
time-function is; what's important here is *not* the precise time-lapse
between two instances of random (), but, rather, that each instance of
random () starts from a *different seed-value*.

REH

unread,
Feb 11, 2006, 5:25:29 PM2/11/06
to

"Samwyse" <sam...@gmail.com> wrote in message
news:XImHf.31650$H71....@newssvr13.news.prodigy.com...

> Designing a language is different from implementing it.

Right, which was my entire point.
REH


Uli Kusterer

unread,
Feb 11, 2006, 6:09:55 PM2/11/06
to
In article <1139695696.6...@g14g2000cwa.googlegroups.com>,
Xub...@gmail.com wrote:

Couldn't you just do this once, at startup, like it's usually done?
From then on, most pseudo-random-number generators will give you enough
variance by design.

Re-seeding a PRNG on every call will actually usually worsen the
"shuffledness" of the number.

Cheers,
-- Uli

Uli Kusterer

unread,
Feb 11, 2006, 6:11:23 PM2/11/06
to
In article <witness-0AAF6D...@news.t-online.com>,
Uli Kusterer <wit...@t-online.de> wrote:

> While it may look cool and be tempting to
> have lots of $something, $something and @something constructs there, and
> why that might make it immediately obvious to your parser that after
> this character a variable, macro or whatever follows, it requires your
> users to memorise these arbitrary characters.

One of those $somethings was supposed to be a %something, and the "why
that" was supposed to be "while that". Sorry 'bout that.

Cheers,
-- Uli

Samwyse

unread,
Feb 11, 2006, 7:23:27 PM2/11/06
to

You seem confused. In your own words: "Assuming for a moment that you


have already designed the language, when what is "writing a compiler
for the language that results"? If that's true then you are still
designing the language."

I have on my computer a specification for the Inform language. From
that, I could write my own compiler for Inform. If I did that, I would
not be "still designing the language", the language design is finished
and I would just be implementing that design.

REH

unread,
Feb 11, 2006, 8:08:16 PM2/11/06
to

"Samwyse" <sam...@gmail.com> wrote in message
news:3evHf.27308$Jd....@newssvr25.news.prodigy.net...

No, I'm not. You just misundstand what I was saying. The line you quoted
above what in response to you talking about writing games after designing
the language, then writing a compiler from the language that results. I was
talking about the "language that results" part, not the "writing a compiler"
part. What I was saying is that if you get a "resulting language" while
writing games after designing your language, your design is still in flux,
and not done. The point of which was it is not yet time to be implementing
a compiler as you would just waste time re-writing it as your language
changes. Which was my original point to the OP. I was also agreeing with
you that is was a good idea to "test" your language by trying to writing
some games into before you start coding the compiler. As someone that has
designed and implemented large-scale embedded systems for two decades, I
understand the concept of software development very well. As I said in a
previous post, we are just talking past each other with neither being
understood. That being the case, we think should just drop it as it is not
a very interesting discusion anyways.

REH


MeshGear

unread,
Feb 11, 2006, 11:28:40 PM2/11/06
to
> Couldn't you just do this once, at startup, like it's usually done?
> From then on, most pseudo-random-number generators will give you enough
> variance by design.
>
> Re-seeding a PRNG on every call will actually usually worsen the
> "shuffledness" of the number.
>
> Cheers,
> -- Uli

That's actually the thing, there -- I'm still not entirely sure how C++
handles pseudo-random number generation. The last time I messed with it, I
don't recally it working unless I reseeded constantly (Or not. I think I had
to). I also recall it only generating even numbers.

It should also be possible to seed off of turn number. Or, if there's a
battle system, off of... some state variable, or player health, or
something. This could be an area where more script control would prove
useful!

Anyway, which libaray/.t/.h contains the TADS verb coding? I'm curious as to
how it handles actions, specifically movement related ones.


0 new messages