Skip to content

Commit

Permalink
Partially completed Lexical Analysis
Browse files Browse the repository at this point in the history
Able to read in string and store as ASCII in memory, possibly want to
change this to storing in ZSCII instead for later parsing.
New functions: (read, readToMemory, Tokenize)
  • Loading branch information
Adeimantius committed Mar 14, 2015
1 parent 7b9bb9f commit d173a07
Show file tree
Hide file tree
Showing 8 changed files with 379 additions and 72 deletions.
193 changes: 193 additions & 0 deletions Build1/zmachine/zmachine/Lex.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace zmachine
{

public class Lex
{
Memory memory;
uint dictionaryAddress;
List<ushort> separators = new List<ushort>();
List<String> dictionary = new List<String>();
int mp = 0; // Memory Pointer

public Lex(Memory mem)
{
memory = mem;
dictionaryAddress = memory.getByte(Memory.ADDR_DICT);
}

public void tokenize(List<String> input)
{
uint separatorLength = memory.getByte(dictionaryAddress);
uint entryLength = memory.getByte(dictionaryAddress + separatorLength + 1);
uint dictionaryLength = memory.getWord(dictionaryAddress + separatorLength + 2);

for (uint i = dictionaryAddress; i < separatorLength; i++)
{
separators.Add(memory.getByte(i + 1)); // Find 'n' different word separators and add to list

}
for (uint i = dictionaryAddress; i < dictionaryLength; i += entryLength)
{
String word = getZSCII(i + separatorLength + 1, 0).str; // Take dictionary entries and convert to zchars
dictionary.Add(word); // Find 'n' different dictionary entries and add words to list
}

for (int i = 0; i < dictionary.Count; i++)
{
// convert dictionary from words to zchars
}

}

public String searchDict(String word)
{
for (int i = 0; i < dictionary.Count; i++)
{
if (dictionary[i] == word)
{
return dictionary[i];
}
}
return "Could not identify keyword:" + word;
}

public void parseWord(String word)
{
for (int i = 0; i < wordArray.Length; i++) // Look up in dictionary
{
int j = 0;
while (wordArray[i] == dictionary[j])
j++; // figure out what to do when a match is found between input and the dictionary.
}

}

// Store string (in ASCII) at address in byte 1 onward with a zero terminator.
public void readToMemory(String input, int address)
{
int[] c = new int[3]; // Store three zchars across 16 bits (two bytes). May have to make a dynamic list and pad it once every 3 reads.
int i;
mp = address + 1;
ushort word = 0;
bool stringComplete = false;

while (stringComplete != true)
{
for (int j; j < 3; j++)
{
if (i + j > input.Length)
{
c[j] = Convert.ToInt32('5'); // Pad word with 5's.
stringComplete = true;
}
else // Write next char from input into 3-char array
{
c[j] = input[i + j];
}
word += (ushort)(c[j] << 10 - (5 * j)); // Write 3 chars into word
}
//word += (ushort)(c[0] << 10);
//word += (ushort)(c[1] << 5);
//word += (ushort)(c[2]);
memory.setWord((uint)(address + mp), word); // Write word to memory
i += 3;
mp += 2;
}
memory.setWord((uint)(address + mp), 0); // Write empty word to terminate after read is complete.

}

// Get console input and fix it to ZSpec standards.
public void read(int textBufferAddress, int parseBuffer)
{

// NOTE: These is a String.Contains function that may be of great value with the resulting zstring..!
int maxInputLength = memory.getByte((uint)textBufferAddress) - 1; //byte 0 of the text-buffer should initially contain the maximum number of letters which can be typed, minus 1
int maxWordLength = memory.getByte((uint) parseBuffer);

int zstringLength;
String input = "";

input += Console.ReadLine(); // Get initial input from console terminal
input.Remove(maxInputLength); // Limit input to size of text-buffer
input.TrimEnd('\n'); // Remove carriage return from end of string
input.ToLower(); // Convert to lowercase

input = readToMemory(input, textBufferAddress); //stored in bytes 1 onward, with a zero terminator (but without any other terminator, such as a carriage return code
}


int wordindex = 0;

int[] wordStartIndex;
String[] wordArray = input.Split(' '); // Tokenize into words
for (int i = 0; i < wordArray.Length; i++)
{
wordStartIndex[i] = wordindex; // take index of word

for (int j = 0; j < wordArray[i].Length; j++)
{
wordindex++; // Add 1 for each char
}
wordindex++; // Add 1 for each space
}

List<String> zstringArray = new List<String>(); // Make array to hold onto zstrings
getZSCII(null, null); // Convert to Zchars



int padLength = 0;

String last = zstringArray[zstringArray.Count - 1];
zstringArray = zstringArray.RemoveAt(zstringArray.Count - 1); // pop the last zstring in the array
// Figure out size in memory
padLength = last.Length % 3; //--------------------------------- Get length of zstring and check if last word needs padding
last.PadRight(padLength, '5'); // Pad with 5s
zstringArray = zstringArray.Add(last);

for (int i = 0; i < zstringArray.Count; i += 3) // Pack into 3-char pieces as a Zstring
{
Concatenate 3 consecutive chars into a word;
memory.setWord((uint)(textBufferAddress + (2 + 4 * i)), (ushort)zstringArray[i]); // Write number of words in byte 1, write words from byte 2 onward (stopping at maxWordLength;
}
//

// tokenize(input) // Tokenize input using the main dictionary
setVar(firstoperand, zstringArray[i]); // Store string in buffer in first operand

/* sequence of characters is read in from the current input stream until a carriage return
*
* The text typed is reduced to lower case (so that it can tidily be printed back by the program if need be) and stored in bytes 1 onward, with a zero terminator (not a carriage return!)
* There are two input streams - the file containing commands (ZORK1) and the keyboard. Op_input_stream will swap them.
*
* if byte 1 contains a positive value at the start of the input, then read assumes that number of characters are left over from an interrupted previous input,
* and writes the new characters after those already there.
* ^ I'm going to hate this.
*
* byte 0 of the parse-buffer should hold the maximum number of textual words which can be parsed.
* (If this is n, the buffer must be at least 2 + 4*n bytes long to hold the results of the analysis.)
*
* The interpreter divides the text into words and looks them up in the dictionary, as described in S 13.
* The number of words is written in byte 1 and one 4-byte block is written for each word, from byte 2 onwards
* (except that it should stop before going beyond the maximum number of words specified).
* Each block consists of the byte address of the word in the dictionary, if it is in the dictionary, or 0 if it isn't;
* followed by a byte giving the number of letters in the word; and finally a byte giving the position in the text-buffer of the first letter of the word.
*/
return input;
}

public char readChar()
{
// read keypress and pass as a char into getZchar
return '0';
}

}
}
69 changes: 46 additions & 23 deletions Build1/zmachine/zmachine/Machine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ partial class Machine {
// This class moves through the input file and extracts bytes to deconstruct instructions in the code
Memory memory = new Memory(1024 * 128); // Initialize memory
Memory stack = new Memory(1024 * 32); // Stack of size 32768 (can be larger, but this should be fine)
ObjectTable objectTable = new ObjectTable(new Memory(1024 * 128));
ObjectTable objectTable;
Lex lex;

public bool debug = false;

// StateOfPlay stateofplay = new StateOfPlay(); // Will contain (1) Local variable table, (2) contents of the stack, (3) value of PC, (4) current routine call state.
uint pc = 0; // Program Counter to step through memory
Expand Down Expand Up @@ -115,14 +117,15 @@ public Machine(string filename)
setProgramCounter();

for (int i =0 ; i < 128 ; ++i)
callStack[i] = new RoutineCallState();
callStack[i] = new RoutineCallState();

objectTable = new ObjectTable(memory);
lex = new Lex(memory);
}

// Find the PC start point in the header file and set PC
public void setProgramCounter()
{

pc = memory.getWord(Memory.ADDR_INITIALPC); // Set PC by looking at pc start byte in header file
}

Expand Down Expand Up @@ -163,9 +166,9 @@ public void processInstruction()
// Value of 0 means variable, value of 1 means small

// load both operands of long form instruction
ushort op1 = loadOperand(opTypeA == 0 ? OperandType.Small : OperandType.Var);
ushort op2 = loadOperand(opTypeB == 0 ? OperandType.Small : OperandType.Var);
process2OP(opcode, op1, op2);
operandList.Add(loadOperand(opTypeA == 0 ? OperandType.Small : OperandType.Var));
operandList.Add(loadOperand(opTypeB == 0 ? OperandType.Small : OperandType.Var));
process2OP(opcode, operandList);
}
break;

Expand Down Expand Up @@ -218,7 +221,7 @@ public void processInstruction()

if (type == 0)
{
process2OP(opcode, operandList[0], operandList[1]); // Need to pass in two operands?
process2OP(opcode, operandList); // Need to pass in two operands?
}
else
{
Expand Down Expand Up @@ -276,31 +279,42 @@ public ushort loadOperand(OperandType optype)
}
}

void process2OP(int opcode, ushort operand1, ushort operand2)
void process2OP(int opcode, List<ushort> operands)
{
OpcodeHandler_2OP op = OP2opcodes[opcode];
Debug.WriteLine(pcStart.ToString("X4") + " : [2OP/" + opcode.ToString("X2") + "] " + op.name() + " " + operand1.ToString() + " " + operand2.ToString());
op.run(this, operand1, operand2);
if (debug)
{
Debug.Write(pcStart.ToString("X4") + " " + stateString() + " : [2OP/" + opcode.ToString("X2") + "] " + op.name());
foreach (ushort v in operands)
Debug.Write(" " + v);
Debug.WriteLine("");
}
op.run(this, operands);
}
void process1OP(int opcode, ushort operand1)
{
OpcodeHandler_1OP op = OP1opcodes[opcode];
Debug.WriteLine(pcStart.ToString("X4") + " : [1OP/" + opcode.ToString("X2") + "] " + op.name() + " " + operand1.ToString());
if (debug)
Debug.WriteLine(pcStart.ToString("X4") + " " + stateString() + " : [1OP/" + opcode.ToString("X2") + "] " + op.name() + " " + operand1.ToString());
op.run(this, operand1);
}
void process0OP(int opcode)
{
OpcodeHandler_0OP op = OP0opcodes[opcode];
Debug.WriteLine(pcStart.ToString("X4") + " : [0OP/" + opcode.ToString("X2") + "] " + op.name());
if (debug)
Debug.WriteLine(pcStart.ToString("X4") + " " + stateString() + " : [0OP/" + opcode.ToString("X2") + "] " + op.name());
op.run(this);
}
void processVAR(int opcode, List<ushort> operands)
{
OpcodeHandler_OPVAR op = VARopcodes[opcode];
Debug.Write(pcStart.ToString("X4") + " : [VAR/" + opcode.ToString("X2") + "] " + op.name());
foreach (ushort v in operands)
Debug.Write(" " + v);
Debug.WriteLine("");
if (debug)
{
Debug.Write(pcStart.ToString("X4") + " " + stateString() + " : [VAR/" + opcode.ToString("X2") + "] " + op.name());
foreach (ushort v in operands)
Debug.Write(" " + v);
Debug.WriteLine("");
}
op.run(this, operands);
}

Expand Down Expand Up @@ -399,11 +413,11 @@ void processVAR(int opcode, List<ushort> operands)
new op_output_stream(), // 243/13
new op_input_stream() // 244/14
};
// --------------------------------------------------------------------------------------------



public void branch(bool condition) // Check branch instructions
public void branch(bool condition) // Check branch instructions
{
// Debug.WriteLine("BRANCH: " + (condition ? "1" : "0"));

byte branchInfo = pc_getByte();
int branchOn = ((branchInfo >> 7) & 0x01);
Expand All @@ -428,10 +442,10 @@ public void branch(bool condition) // Check branch instructions
{
if (offset == 0 || offset == 1)
{
popRoutineData(0); // if offset is 0 or 1, return 0.
return;
popRoutineData((ushort)offset);
}
pc += offset - 2;
else
pc += offset - 2;
}

}
Expand Down Expand Up @@ -489,13 +503,13 @@ public ushort getVar(ushort variable)

}

// --------------------------------------------------------------------------------------------
public string getAbbrev(int abbrevIndex)
{
StringAndReadLength abbrev = getZSCII((uint)(memory.getWord((uint)(memory.getWord(Memory.ADDR_ABBREVS) + abbrevIndex * 2)) * 2), 0);
return abbrev.str;
}

// -----------------------------------------------------------------
public class StringAndReadLength
{
public String str = "";
Expand Down Expand Up @@ -655,6 +669,15 @@ public String objectName(int objectId) // I hate putting this here, but
return name;
}

public String stateString()
{
String s = "M: " + memory.getCrc32() + " S: " + stack.getCrc32();
// for (ushort i = 1; i < 256; ++i)
// s += " " + getVar(i);
return s;
}
// --------------------------------------------------------------------------------------------


} // end Machine
} // end namespace
6 changes: 6 additions & 0 deletions Build1/zmachine/zmachine/Memory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,12 @@ public void dumpHeader()

}

public uint getCrc32()
{
Crc32 crc32 = new Crc32();
return crc32.ComputeChecksum(memory);
}


}
}
Loading

0 comments on commit d173a07

Please sign in to comment.