Browse Source

Implement ERH header parsing

Bepsi 6 years ago
parent
commit
13de0f4919

+ 36 - 1
NTERA.Compiler/Compiler.cs

@@ -240,6 +240,8 @@ namespace NTERA.Compiler
 
 			var csvDefinition = new CSVDefinition();
 
+			Console.WriteLine("Preprocessing CSV files...");
+
 
 			foreach (var file in Directory.EnumerateFiles(csvPath, "*.csv", SearchOption.AllDirectories))
 			{
@@ -251,6 +253,37 @@ namespace NTERA.Compiler
 				Preprocessor.ProcessCSV(csvDefinition, path, File.ReadLines(file, Encoding.UTF8));
 			}
 
+			Console.WriteLine("Preprocessing header files...");
+
+			ConcurrentBag<FunctionVariable> preprocessedConstants = new ConcurrentBag<FunctionVariable>();
+
+#if DEBUG
+			foreach (var file in Directory.EnumerateFiles(erbPath, "*.erh", SearchOption.AllDirectories))
+#else
+			Parallel.ForEach(Directory.EnumerateFiles(erbPath, "*.erh", SearchOption.AllDirectories), new ParallelOptions
+			{
+				MaxDegreeOfParallelism = 8
+			}, file =>
+#endif
+			{
+				try
+				{
+					foreach (var variable in Preprocessor.PreprocessHeaderFile(File.ReadAllText(file)))
+						preprocessedConstants.Add(variable);
+				}
+				catch (Exception ex)
+				{
+					lock (Errors)
+						Errors.Add(new Tuple<ParserError, string>(new ParserError($"Internal pre-process lexer error [{ex}]", new Marker()), Path.GetFileName(file)));
+				}
+#if DEBUG
+			}
+#else
+			});
+#endif
+
+			Console.WriteLine("Preprocessing functions...");
+
 			ConcurrentDictionary<FunctionDefinition, string> preprocessedFunctions = new ConcurrentDictionary<FunctionDefinition, string>();
 
 #if DEBUG
@@ -264,7 +297,7 @@ namespace NTERA.Compiler
 			{
 				try
 				{
-					foreach (var kv in Preprocessor.PreprocessFile(File.ReadAllText(file), Path.GetFileName(file)))
+					foreach (var kv in Preprocessor.PreprocessCodeFile(File.ReadAllText(file), Path.GetFileName(file), null))
 						preprocessedFunctions[kv.Key] = kv.Value;
 				}
 				catch (Exception ex)
@@ -284,6 +317,8 @@ namespace NTERA.Compiler
 			var procedures = DeclaredFunctions.Keys.Where(x => !x.IsReturnFunction).ToList();
 
 
+			Console.WriteLine("Compiling functions...");
+
 #if DEBUG
 			foreach (var kv in DeclaredFunctions)
 #else

+ 3 - 0
NTERA.Interpreter/Compiler/FunctionDefinition.cs

@@ -36,6 +36,9 @@ namespace NTERA.Interpreter.Compiler
 		Constant = 1,
 		Reference = 2,
 		Dynamic = 4,
+		SaveData = 8,
+		CharaData = 16,
+		Global = 32,
 	}
 
 	public class FunctionVariable

+ 118 - 7
NTERA.Interpreter/Compiler/Preprocessor.cs

@@ -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)
 				{

+ 9 - 0
NTERA.Interpreter/Compiler/Token.cs

@@ -28,6 +28,15 @@
 		[LexerKeyword("DYNAMIC")]
 		Dynamic,
 
+		[LexerKeyword("SAVEDATA")]
+		SaveData,
+
+		[LexerKeyword("CHARADATA")]
+		CharaData,
+
+		[LexerKeyword("GLOBAL")]
+		Global,
+
 		[LexerKeyword("FUNCTION")]
 		[LexerKeyword("FUNCTIONS")]
 		ReturnFunction,