I'm trying to assign the results of a simple calculation (r*r+d) (which results in a number) into the integer "s" like so:

mov(r*r+d,s);

But it results in the following compiler error:

Error in file "west.hla" at line 1077 :
Expected ',', encountered '*'.
Near: << * >>


D:\MASM>

What do I need to use for the syntax to be correct?

P.S. Found a solution to the multi-dimensional problem. r*r+d results in a unique number each time from (that is, I'm multiplying row*row+column to synthesize a multi-dimensional array. This creates a larger single-dimension array, but it works).

Example:

m[15,2] becomes [15*15+2] which is 227. m[227] is then set to 19, corresponding to the room #19.

Regards,

Paul Panks
dunric@yahoo.com
Posted on 2003-05-02 23:40:32 by Paul Panks

I'm trying to assign the results of a simple calculation (r*r+d) (which results in a number) into the integer "s" like so:

mov(r*r+d,s);

But it results in the following compiler error:

Error in file "west.hla" at line 1077 :
Expected ',', encountered '*'.
Near: << * >>


D:\MASM>

What do I need to use for the syntax to be correct?

P.S. Found a solution to the multi-dimensional problem. r*r+d results in a unique number each time from (that is, I'm multiplying row*row+column to synthesize a multi-dimensional array. This creates a larger single-dimension array, but it works).

Example:

m[15,2] becomes [15*15+2] which is 227. m[227] is then set to 19, corresponding to the room #19.

Regards,

Paul Panks
dunric@yahoo.com


re:
mov(r*r+d,s);

You're confusing *compile-time* calculations with *run-time* calculations
(a common mistake among people learning assembly language, btw).

The computations like you've listed in the MOV instruction above
may only involve constants (or VAL objects) whose value is known at
the point of this instruction, e.g.,

const
r :int32 := 15;
d:int32 := 4;
.
.
.
mov( r*r+d, s );

Note that this MOV instruction is completely equivalent to

mov( 229, s );

HOWEVER, if r and (/or) d are memory variables, this statement
is not legal (for a couple of reasons). First of all, memory to memory
moves are illegal (I'm assuming s is a variable). Second, calculations
like this are not permissible as operands. What you need to do is
calculate the expression into a register and then store that register
into S, e.g.,

mov( r, eax );
intmul( r, eax );
add( d, eax );
mov( eax, s );

Yep, that's a pain. Welcome to assembly language!

Cheers,
Randy Hyde
Posted on 2003-05-03 09:28:47 by rhyde
Using your calculation r*r+c, both row 1 column 4, and row 2 column 1 give 5.

row 2, column 6 and row 3 column 1 both give 10.

I believe you should use r*n+c, where n is the total number of rows.
Posted on 2003-05-04 00:46:18 by V Coder
Well, I looked at the source code.
Here are a couple of comments.

Problem #1, as I suspected, is the fact that you're indexing into a dword array
using a byte indexing scheme. You must multiply your index by the array element
size (in bytes, four in this case) before accessing the element. Otherwise you
get total garbage. There are probably some other problems in there as well,
but this is the #1 problem. The size of your m array needs to be better than
1681 (41*41) if you're really going to index it using the room number squared.

At the beginning of your code, you do this to initialize m:

// Start up...

// room 1
mov(5,m[3]);
mov(2,m[6]);

// room 2
mov(4,m[7]);
mov(1,m[10]);

// room 3
mov(5,m[13]);
.
.
.

If you were to use a true two-dimensional array (rather than
a sparse array as you are using), you could initialize this
static array at load time rather than at run time by assigning
an array constant to m, e.g.,

static
m:int32 := [ 1, 5, 2, 4, ...];

This would shave a ton of instructions off the front of your code.

Rather than using straight-line code to print the room descriptions,
I'd use a data structure like this:

 

type
RoomText:record
RoomName:string;
RoomDesc:string;
RoomExits:string;
endrecord;


static
RoomInfo: RoomText[42] :=
[
RoomText:[ "","",""], //No room 0?
RoomText:
[
"Village tavern",

"You are standing in a tavern with creaky wooden floors. Laughter and" nl
"commotion surround you as the bartender tends to his customers. A few" nl
"tables and chairs are visible here. A staircase heads upstairs to the" nl
"second floor of the tavern." nl,

"<south, up>"
],
<<40 more RoomText declarations>>
];



Now your code to emit the room description becomes just the following:

intmul( @size( RoomText ), r, esi );
console.setOutputAttr( win.fgnd_LightCyan | win.bgnd_Black );
stdout.put( (type string RoomInfo.RoomName), nl );
console.setOutputAttr( win.fgnd_LightGray | win.bgnd_Black );
stdout.put( (type string RoomInfo.RoomDesc), nl );
console.setOutputAttr( win.fgnd_White | win.bgnd_Black );
stdout.put( "Exits: " );
console.setOutputAttr( win.fgnd_Yellow | win.bgnd_Black );
stdout.put( (type string RoomInfo.RoomExits), nl );

This short sequence replaces those 42 if statements (if(r=1) then.... if(r=2) then..., etc)
in your existing code. Note that the intmul instruction multiplies the index (r) by
the size of an array element (@size(RoomText)). This is the trick that you were
missing in your earlier code.

As for the parse routine, if your adventure game follows the traditional
<verb><noun> command structure, I'd recommend converting the first
word to a number in the range 0..#verbs and the second word on the line
to a number in the range 0..#nouns (with zero representing an unknown
noun or verb) and then use these two values as an index into a two dimensional
array of procedure pointers and call the procedure responsible for that combination.

E.g., assume we have:

verbs: go, get, put

nouns: north, east, shield

You would create a 4x4 array of procedure pointers as follows:

 

type
procPtr: procedure;

static
procPtrs: procPtr[4,8] :=
[
&invalid, &invalid, &invalid, &invalid, // index zero is always an invalid command

// go north go east go shield

&invalid, &gonorth, &goeast, &invalid,

// get north get east get shield

&invalid, &invalid, &invalid, &getshield,

// put north put east put shield
&invalid, &invalid, &invalid, &putsheild
];



Assuming you can turn the nouns and verbs into the values 0..3 and 0..2 respectively,
(and leave the values in noun and verb), you can call the procedure than handles
the command thusly:


 

intmul( 8, verb, edx ); // could also shl verb by three and use that value.
add( noun, edx );
call( procPtrs[ edx*4] ); // Calls one of the functions invalid, gonorth, goeast,
// getshield, or putshield depending upon the values
// of noun and verb.


Then you'd just have to supply one procedure for each legal command.

I think you'll agree that this scheme will produce far less code than the string
of if statements you're currently using.

This project, btw, *begs* to be written in an object-oriented fashion using
classes in HLA. However, I'm assuming you've probably not done much object-oriented
programming in the past, so you'll probably find the schemes I've suggested thus far
to be a bit more convenient.

BTW, another good approach is to use the HLA pattern matching library to parse
the user commands, e.g.,


 

str.lower( input_line_from_user );
pat.match( input_line_from_user );

pat.zeroOrMoreWS();
pat.matchStr( "go" );
pat.zeroOrMoreWS();
pat.matchStr( "north" );

GoNorth();

pat.alternate;

pat.zeroOrMoreWS();
pat.matchStr( "go" );
pat.zeroOrMoreWS();
pat.matchStr( "east" );

GoEast();

pat.alternate;

pat.zeroOrMoreWS();
pat.matchStr( "get" );
pat.zeroOrMoreWS();
pat.matchStr( "shield" );

GetShield();

pat.alternate;

pat.zeroOrMoreWS();
pat.matchStr( "put" );
pat.zeroOrMoreWS();
pat.matchStr( "shield" );

PutShield();

pat.if_failure;

stdout.put( "Illegal command" nl );

pat.endmatch;


The pattern matching code is really easy to understand and modify
(unlike the array stuff I've suggested, which is a bit more painful to
create and modify) at the expense of longer code.

Cheers,
Randy Hyde
Posted on 2003-05-06 23:26:55 by rhyde