|
@@ -7,9 +7,113 @@ namespace NTERA.Interpreter.Compiler
|
|
|
{
|
|
|
public static class Preprocessor
|
|
|
{
|
|
|
- public static IDictionary<FunctionDefinition, string> PreprocessFile(string contents, string filename)
|
|
|
+ public static IEnumerable<FunctionVariable> PreprocessHeaderFile(string contents)
|
|
|
{
|
|
|
- Dictionary<FunctionDefinition, string> procs = new Dictionary<FunctionDefinition, string>();
|
|
|
+ Lexer lexer = new Lexer(contents);
|
|
|
+ List<FunctionVariable> constantDefinitions = new List<FunctionVariable>();
|
|
|
+
|
|
|
+ using (var enumerator = lexer.GetEnumerator())
|
|
|
+ {
|
|
|
+ do
|
|
|
+ {
|
|
|
+ if (lexer.TokenMarker.Column != 1)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ if (enumerator.Current == Token.Sharp)
|
|
|
+ {
|
|
|
+ enumerator.MoveNext();
|
|
|
+
|
|
|
+ switch (enumerator.Current)
|
|
|
+ {
|
|
|
+ case Token.Dims:
|
|
|
+ case Token.Dim:
|
|
|
+ {
|
|
|
+ bool isString = enumerator.Current != Token.Dim;
|
|
|
+
|
|
|
+ enumerator.MoveNext();
|
|
|
+ VariableType variableType = VariableType.None;
|
|
|
+
|
|
|
+ while (enumerator.Current == Token.Const
|
|
|
+ || enumerator.Current == Token.Ref
|
|
|
+ || enumerator.Current == Token.Dynamic
|
|
|
+ || enumerator.Current == Token.SaveData
|
|
|
+ || enumerator.Current == Token.CharaData
|
|
|
+ || enumerator.Current == Token.Global)
|
|
|
+ {
|
|
|
+ if (enumerator.Current == Token.Const)
|
|
|
+ variableType |= VariableType.Constant;
|
|
|
+ else if (enumerator.Current == Token.Ref)
|
|
|
+ variableType |= VariableType.Reference;
|
|
|
+ else if (enumerator.Current == Token.Dynamic)
|
|
|
+ variableType |= VariableType.Dynamic;
|
|
|
+ else if (enumerator.Current == Token.SaveData)
|
|
|
+ variableType |= VariableType.SaveData;
|
|
|
+ else if (enumerator.Current == Token.CharaData)
|
|
|
+ variableType |= VariableType.CharaData;
|
|
|
+ else if (enumerator.Current == Token.Global)
|
|
|
+ variableType |= VariableType.Global;
|
|
|
+
|
|
|
+ enumerator.MoveNext();
|
|
|
+ }
|
|
|
+
|
|
|
+ string variable = lexer.Identifier;
|
|
|
+
|
|
|
+ enumerator.MoveNext();
|
|
|
+ Value? defaultValue = null;
|
|
|
+
|
|
|
+ if (enumerator.Current == Token.Comma)
|
|
|
+ {
|
|
|
+ while (enumerator.MoveNext()
|
|
|
+ && enumerator.Current != Token.Equal
|
|
|
+ && enumerator.Current != Token.NewLine
|
|
|
+ && enumerator.Current != Token.EOF)
|
|
|
+ {
|
|
|
+ //arraySize = (int)lexer.Expression().Real;
|
|
|
+
|
|
|
+ //the array size goes here, but we ignore it since it's useless to us
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (enumerator.Current == Token.Equal)
|
|
|
+ {
|
|
|
+ enumerator.MoveNext();
|
|
|
+
|
|
|
+ defaultValue = ConstantExpression(lexer, constantDefinitions);
|
|
|
+ }
|
|
|
+ else if (enumerator.Current != Token.NewLine
|
|
|
+ && enumerator.Current != Token.EOF)
|
|
|
+ {
|
|
|
+ throw new ParserException("Invalid function declaration", lexer.TokenMarker);
|
|
|
+ }
|
|
|
+
|
|
|
+ var functionDefinition = new FunctionVariable(variable,
|
|
|
+ isString ? ValueType.String : ValueType.Real,
|
|
|
+ variableType,
|
|
|
+ defaultValue);
|
|
|
+
|
|
|
+ constantDefinitions.Add(functionDefinition);
|
|
|
+ yield return functionDefinition;
|
|
|
+
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ //resynchronize to next line
|
|
|
+ while (enumerator.Current != Token.NewLine
|
|
|
+ && enumerator.Current != Token.EOF
|
|
|
+ && enumerator.MoveNext())
|
|
|
+ {
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } while (enumerator.MoveNext());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public static IDictionary<FunctionDefinition, string> PreprocessCodeFile(string contents, string filename, ICollection<FunctionVariable> constantDefinitions)
|
|
|
+ {
|
|
|
+ Dictionary<FunctionDefinition, string> procedures = new Dictionary<FunctionDefinition, string>();
|
|
|
|
|
|
Lexer lexer = new Lexer(contents);
|
|
|
|
|
@@ -33,7 +137,7 @@ namespace NTERA.Interpreter.Compiler
|
|
|
filename,
|
|
|
startMarker);
|
|
|
|
|
|
- procs.Add(definition, procBody);
|
|
|
+ procedures.Add(definition, procBody);
|
|
|
|
|
|
isReturnFunction = false;
|
|
|
currentDefinitionName = null;
|
|
@@ -178,7 +282,7 @@ namespace NTERA.Interpreter.Compiler
|
|
|
{
|
|
|
enumerator.MoveNext();
|
|
|
|
|
|
- defaultValue = ConstantExpression(lexer);
|
|
|
+ defaultValue = ConstantExpression(lexer, constantDefinitions);
|
|
|
}
|
|
|
else if (enumerator.Current != Token.NewLine
|
|
|
&& enumerator.Current != Token.EOF)
|
|
@@ -214,7 +318,7 @@ namespace NTERA.Interpreter.Compiler
|
|
|
|
|
|
Commit();
|
|
|
|
|
|
- return procs;
|
|
|
+ return procedures;
|
|
|
}
|
|
|
|
|
|
private static IList<IList<string>> SplitCSV(IEnumerable<string> lines)
|
|
@@ -350,7 +454,7 @@ namespace NTERA.Interpreter.Compiler
|
|
|
{ Token.Caret, 4 }
|
|
|
};
|
|
|
|
|
|
- public static Value ConstantExpression(Lexer lexer)
|
|
|
+ public static Value ConstantExpression(Lexer lexer, ICollection<FunctionVariable> constantDefinitions = null)
|
|
|
{
|
|
|
IEnumerator<Token> currentEnumerator = lexer.GetEnumerator();
|
|
|
|
|
@@ -384,7 +488,14 @@ namespace NTERA.Interpreter.Compiler
|
|
|
}
|
|
|
else if (currentEnumerator.Current == Token.Identifer)
|
|
|
{
|
|
|
- throw new ParserException("Undeclared variable " + lexer.Identifier, lexer.TokenMarker);
|
|
|
+ var variable = constantDefinitions?.FirstOrDefault(x => x.Name == lexer.Identifier && x.VariableType.HasFlag(VariableType.Constant));
|
|
|
+
|
|
|
+ if (variable == null)
|
|
|
+ throw new ParserException("Undeclared variable " + lexer.Identifier, lexer.TokenMarker);
|
|
|
+
|
|
|
+ var value = variable.DefaultValue ?? variable.ValueType == ValueType.String ? (Value)"" : 0;
|
|
|
+
|
|
|
+ stack.Push(value);
|
|
|
}
|
|
|
else if (currentEnumerator.Current == Token.LParen)
|
|
|
{
|