mirror of
https://github.com/crskycode/GARbro.git
synced 2024-11-27 07:34:00 +08:00
(Experimental): implemented IPT composite images.
use LEX/YACC to parse IPT files.
This commit is contained in:
parent
e0114ad91d
commit
14a94d20f1
720
Experimental/Artemis/GplexBuffers.cs
Normal file
720
Experimental/Artemis/GplexBuffers.cs
Normal file
@ -0,0 +1,720 @@
|
|||||||
|
// ==============================================================
|
||||||
|
// <auto-generated>
|
||||||
|
// This code automatically produced from an embedded resource.
|
||||||
|
// Do not edit this file, or it will become incompatible with
|
||||||
|
// the specification from which it was generated.
|
||||||
|
// </auto-generated>
|
||||||
|
// ==============================================================
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
|
namespace QUT.GplexBuffers
|
||||||
|
{
|
||||||
|
// Code copied from GPLEX embedded resource
|
||||||
|
[Serializable]
|
||||||
|
public class BufferException : Exception
|
||||||
|
{
|
||||||
|
public BufferException() { }
|
||||||
|
public BufferException(string message) : base(message) { }
|
||||||
|
public BufferException(string message, Exception innerException)
|
||||||
|
: base(message, innerException) { }
|
||||||
|
protected BufferException(SerializationInfo info, StreamingContext context)
|
||||||
|
: base(info, context) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class ScanBuff
|
||||||
|
{
|
||||||
|
private string fileNm;
|
||||||
|
|
||||||
|
public const int EndOfFile = -1;
|
||||||
|
public const int UnicodeReplacementChar = 0xFFFD;
|
||||||
|
|
||||||
|
public bool IsFile { get { return (fileNm != null); } }
|
||||||
|
public string FileName { get { return fileNm; } set { fileNm = value; } }
|
||||||
|
|
||||||
|
public abstract int Pos { get; set; }
|
||||||
|
public abstract int Read();
|
||||||
|
public virtual void Mark() { }
|
||||||
|
|
||||||
|
public abstract string GetString(int begin, int limit);
|
||||||
|
|
||||||
|
public static ScanBuff GetBuffer(string source)
|
||||||
|
{
|
||||||
|
return new StringBuffer(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ScanBuff GetBuffer(IList<string> source)
|
||||||
|
{
|
||||||
|
return new LineBuffer(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if (!NOFILES)
|
||||||
|
public static ScanBuff GetBuffer(Stream source)
|
||||||
|
{
|
||||||
|
return new BuildBuffer(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if (!BYTEMODE)
|
||||||
|
public static ScanBuff GetBuffer(Stream source, int fallbackCodePage)
|
||||||
|
{
|
||||||
|
return new BuildBuffer(source, fallbackCodePage);
|
||||||
|
}
|
||||||
|
#endif // !BYTEMODE
|
||||||
|
#endif // !NOFILES
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Buffer classes
|
||||||
|
|
||||||
|
// ==============================================================
|
||||||
|
// ===== Definitions for various ScanBuff derived classes ====
|
||||||
|
// ==============================================================
|
||||||
|
// =============== String input ================
|
||||||
|
// ==============================================================
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This class reads characters from a single string as
|
||||||
|
/// required, for example, by Visual Studio language services
|
||||||
|
/// </summary>
|
||||||
|
sealed class StringBuffer : ScanBuff
|
||||||
|
{
|
||||||
|
string str; // input buffer
|
||||||
|
int bPos; // current position in buffer
|
||||||
|
int sLen;
|
||||||
|
|
||||||
|
public StringBuffer(string source)
|
||||||
|
{
|
||||||
|
this.str = source;
|
||||||
|
this.sLen = source.Length;
|
||||||
|
this.FileName = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int Read()
|
||||||
|
{
|
||||||
|
if (bPos < sLen) return str[bPos++];
|
||||||
|
else if (bPos == sLen) { bPos++; return '\n'; } // one strike, see new line
|
||||||
|
else { bPos++; return EndOfFile; } // two strikes and you're out!
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string GetString(int begin, int limit)
|
||||||
|
{
|
||||||
|
// "limit" can be greater than sLen with the BABEL
|
||||||
|
// option set. Read returns a "virtual" EOL if
|
||||||
|
// an attempt is made to read past the end of the
|
||||||
|
// string buffer. Without the guard any attempt
|
||||||
|
// to fetch yytext for a token that includes the
|
||||||
|
// EOL will throw an index exception.
|
||||||
|
if (limit > sLen) limit = sLen;
|
||||||
|
if (limit <= begin) return "";
|
||||||
|
else return str.Substring(begin, limit - begin);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int Pos
|
||||||
|
{
|
||||||
|
get { return bPos; }
|
||||||
|
set { bPos = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString() { return "StringBuffer"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==============================================================
|
||||||
|
// The LineBuff class contributed by Nigel Horspool,
|
||||||
|
// nigelh@cs.uvic.cs
|
||||||
|
// ==============================================================
|
||||||
|
|
||||||
|
sealed class LineBuffer : ScanBuff
|
||||||
|
{
|
||||||
|
IList<string> line; // list of source lines from a file
|
||||||
|
int numLines; // number of strings in line list
|
||||||
|
string curLine; // current line in that list
|
||||||
|
int cLine; // index of current line in the list
|
||||||
|
int curLen; // length of current line
|
||||||
|
int curLineStart; // position of line start in whole file
|
||||||
|
int curLineEnd; // position of line end in whole file
|
||||||
|
int maxPos; // max position ever visited in whole file
|
||||||
|
int cPos; // ordinal number of code in source
|
||||||
|
|
||||||
|
// Constructed from a list of strings, one per source line.
|
||||||
|
// The lines have had trailing '\n' characters removed.
|
||||||
|
public LineBuffer(IList<string> lineList)
|
||||||
|
{
|
||||||
|
line = lineList;
|
||||||
|
numLines = line.Count;
|
||||||
|
cPos = curLineStart = 0;
|
||||||
|
curLine = (numLines > 0 ? line[0] : "");
|
||||||
|
maxPos = curLineEnd = curLen = curLine.Length;
|
||||||
|
cLine = 1;
|
||||||
|
FileName = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int Read()
|
||||||
|
{
|
||||||
|
if (cPos < curLineEnd)
|
||||||
|
return curLine[cPos++ - curLineStart];
|
||||||
|
if (cPos++ == curLineEnd)
|
||||||
|
return '\n';
|
||||||
|
if (cLine >= numLines)
|
||||||
|
return EndOfFile;
|
||||||
|
curLine = line[cLine];
|
||||||
|
curLen = curLine.Length;
|
||||||
|
curLineStart = curLineEnd + 1;
|
||||||
|
curLineEnd = curLineStart + curLen;
|
||||||
|
if (curLineEnd > maxPos)
|
||||||
|
maxPos = curLineEnd;
|
||||||
|
cLine++;
|
||||||
|
return curLen > 0 ? curLine[0] : '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
// To speed up searches for the line containing a position
|
||||||
|
private int cachedPosition;
|
||||||
|
private int cachedIxdex;
|
||||||
|
private int cachedLineStart;
|
||||||
|
|
||||||
|
// Given a position pos within the entire source, the results are
|
||||||
|
// ix -- the index of the containing line
|
||||||
|
// lstart -- the position of the first character on that line
|
||||||
|
private void findIndex(int pos, out int ix, out int lstart)
|
||||||
|
{
|
||||||
|
if (pos >= cachedPosition)
|
||||||
|
{
|
||||||
|
ix = cachedIxdex; lstart = cachedLineStart;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ix = lstart = 0;
|
||||||
|
}
|
||||||
|
while (ix < numLines)
|
||||||
|
{
|
||||||
|
int len = line[ix].Length + 1;
|
||||||
|
if (pos < lstart + len) break;
|
||||||
|
lstart += len;
|
||||||
|
ix++;
|
||||||
|
}
|
||||||
|
cachedPosition = pos;
|
||||||
|
cachedIxdex = ix;
|
||||||
|
cachedLineStart = lstart;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string GetString(int begin, int limit)
|
||||||
|
{
|
||||||
|
if (begin >= maxPos || limit <= begin) return "";
|
||||||
|
int endIx, begIx, endLineStart, begLineStart;
|
||||||
|
findIndex(begin, out begIx, out begLineStart);
|
||||||
|
int begCol = begin - begLineStart;
|
||||||
|
findIndex(limit, out endIx, out endLineStart);
|
||||||
|
int endCol = limit - endLineStart;
|
||||||
|
string s = line[begIx];
|
||||||
|
if (begIx == endIx)
|
||||||
|
{
|
||||||
|
// the usual case, substring all on one line
|
||||||
|
return (endCol <= s.Length) ?
|
||||||
|
s.Substring(begCol, endCol - begCol)
|
||||||
|
: s.Substring(begCol) + "\n";
|
||||||
|
}
|
||||||
|
// the string spans multiple lines, yuk!
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
if (begCol < s.Length)
|
||||||
|
sb.Append(s.Substring(begCol));
|
||||||
|
for (; ; )
|
||||||
|
{
|
||||||
|
sb.Append("\n");
|
||||||
|
s = line[++begIx];
|
||||||
|
if (begIx >= endIx) break;
|
||||||
|
sb.Append(s);
|
||||||
|
}
|
||||||
|
if (endCol <= s.Length)
|
||||||
|
{
|
||||||
|
sb.Append(s.Substring(0, endCol));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sb.Append(s);
|
||||||
|
sb.Append("\n");
|
||||||
|
}
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int Pos
|
||||||
|
{
|
||||||
|
get { return cPos; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
cPos = value;
|
||||||
|
findIndex(cPos, out cLine, out curLineStart);
|
||||||
|
// cLine should be the *next* line after curLine.
|
||||||
|
curLine = (cLine < numLines ? line[cLine++] : "");
|
||||||
|
curLineEnd = curLineStart + curLine.Length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString() { return "LineBuffer"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
#if (!NOFILES)
|
||||||
|
// ==============================================================
|
||||||
|
// ===== class BuildBuff : for unicode text files ========
|
||||||
|
// ==============================================================
|
||||||
|
|
||||||
|
class BuildBuffer : ScanBuff
|
||||||
|
{
|
||||||
|
// Double buffer for char stream.
|
||||||
|
class BufferElement
|
||||||
|
{
|
||||||
|
StringBuilder bldr = new StringBuilder();
|
||||||
|
StringBuilder next = new StringBuilder();
|
||||||
|
int minIx;
|
||||||
|
int maxIx;
|
||||||
|
int brkIx;
|
||||||
|
bool appendToNext;
|
||||||
|
|
||||||
|
internal BufferElement() { }
|
||||||
|
|
||||||
|
internal int MaxIndex { get { return maxIx; } }
|
||||||
|
// internal int MinIndex { get { return minIx; } }
|
||||||
|
|
||||||
|
internal char this[int index]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (index < minIx || index >= maxIx)
|
||||||
|
throw new BufferException("Index was outside data buffer");
|
||||||
|
else if (index < brkIx)
|
||||||
|
return bldr[index - minIx];
|
||||||
|
else
|
||||||
|
return next[index - brkIx];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void Append(char[] block, int count)
|
||||||
|
{
|
||||||
|
maxIx += count;
|
||||||
|
if (appendToNext)
|
||||||
|
this.next.Append(block, 0, count);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.bldr.Append(block, 0, count);
|
||||||
|
brkIx = maxIx;
|
||||||
|
appendToNext = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal string GetString(int start, int limit)
|
||||||
|
{
|
||||||
|
if (limit <= start)
|
||||||
|
return "";
|
||||||
|
if (start >= minIx && limit <= maxIx)
|
||||||
|
if (limit < brkIx) // String entirely in bldr builder
|
||||||
|
return bldr.ToString(start - minIx, limit - start);
|
||||||
|
else if (start >= brkIx) // String entirely in next builder
|
||||||
|
return next.ToString(start - brkIx, limit - start);
|
||||||
|
else // Must do a string-concatenation
|
||||||
|
return
|
||||||
|
bldr.ToString(start - minIx, brkIx - start) +
|
||||||
|
next.ToString(0, limit - brkIx);
|
||||||
|
else
|
||||||
|
throw new BufferException("String was outside data buffer");
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void Mark(int limit)
|
||||||
|
{
|
||||||
|
if (limit > brkIx + 16) // Rotate blocks
|
||||||
|
{
|
||||||
|
StringBuilder temp = bldr;
|
||||||
|
bldr = next;
|
||||||
|
next = temp;
|
||||||
|
next.Length = 0;
|
||||||
|
minIx = brkIx;
|
||||||
|
brkIx = maxIx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BufferElement data = new BufferElement();
|
||||||
|
|
||||||
|
int bPos; // Postion index in the StringBuilder
|
||||||
|
BlockReader NextBlk; // Delegate that serves char-arrays;
|
||||||
|
|
||||||
|
private string EncodingName
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
StreamReader rdr = NextBlk.Target as StreamReader;
|
||||||
|
return (rdr == null ? "raw-bytes" : rdr.CurrentEncoding.BodyName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public BuildBuffer(Stream stream)
|
||||||
|
{
|
||||||
|
FileStream fStrm = (stream as FileStream);
|
||||||
|
if (fStrm != null) FileName = fStrm.Name;
|
||||||
|
NextBlk = BlockReaderFactory.Raw(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if (!BYTEMODE)
|
||||||
|
public BuildBuffer(Stream stream, int fallbackCodePage)
|
||||||
|
{
|
||||||
|
FileStream fStrm = (stream as FileStream);
|
||||||
|
if (fStrm != null) FileName = fStrm.Name;
|
||||||
|
NextBlk = BlockReaderFactory.Get(stream, fallbackCodePage);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Marks a conservative lower bound for the buffer,
|
||||||
|
/// allowing space to be reclaimed. If an application
|
||||||
|
/// needs to call GetString at arbitrary past locations
|
||||||
|
/// in the input stream, Mark() is not called.
|
||||||
|
/// </summary>
|
||||||
|
public override void Mark() { data.Mark(bPos - 2); }
|
||||||
|
|
||||||
|
public override int Pos
|
||||||
|
{
|
||||||
|
get { return bPos; }
|
||||||
|
set { bPos = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Read returns the ordinal number of the next char, or
|
||||||
|
/// EOF (-1) for an end of stream. Note that the next
|
||||||
|
/// code point may require *two* calls of Read().
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public override int Read()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// Characters at positions
|
||||||
|
// [data.offset, data.offset + data.bldr.Length)
|
||||||
|
// are available in data.bldr.
|
||||||
|
//
|
||||||
|
if (bPos < data.MaxIndex)
|
||||||
|
{
|
||||||
|
// ch0 cannot be EOF
|
||||||
|
return (int)data[bPos++];
|
||||||
|
}
|
||||||
|
else // Read from underlying stream
|
||||||
|
{
|
||||||
|
// Experimental code, blocks of page size
|
||||||
|
char[] chrs = new char[4096];
|
||||||
|
int count = NextBlk(chrs, 0, 4096);
|
||||||
|
if (count == 0)
|
||||||
|
return EndOfFile;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data.Append(chrs, count);
|
||||||
|
return (int)data[bPos++];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string GetString(int begin, int limit)
|
||||||
|
{
|
||||||
|
return data.GetString(begin, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return "StringBuilder buffer, encoding: " + this.EncodingName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============== End ScanBuff-derived classes ==================
|
||||||
|
|
||||||
|
public delegate int BlockReader(char[] block, int index, int number);
|
||||||
|
|
||||||
|
// A delegate factory, serving up a delegate that
|
||||||
|
// reads a block of characters from the underlying
|
||||||
|
// encoded stream, via a StreamReader object.
|
||||||
|
//
|
||||||
|
public static class BlockReaderFactory
|
||||||
|
{
|
||||||
|
public static BlockReader Raw(Stream stream)
|
||||||
|
{
|
||||||
|
return delegate(char[] block, int index, int number)
|
||||||
|
{
|
||||||
|
byte[] b = new byte[number];
|
||||||
|
int count = stream.Read(b, 0, number);
|
||||||
|
int i = 0;
|
||||||
|
int j = index;
|
||||||
|
for (; i < count; i++, j++)
|
||||||
|
block[j] = (char)b[i];
|
||||||
|
return count;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#if (!BYTEMODE)
|
||||||
|
public static BlockReader Get(Stream stream, int fallbackCodePage)
|
||||||
|
{
|
||||||
|
Encoding encoding;
|
||||||
|
int preamble = Preamble(stream);
|
||||||
|
|
||||||
|
if (preamble != 0) // There is a valid BOM here!
|
||||||
|
encoding = Encoding.GetEncoding(preamble);
|
||||||
|
else if (fallbackCodePage == -1) // Fallback is "raw" bytes
|
||||||
|
return Raw(stream);
|
||||||
|
else if (fallbackCodePage != -2) // Anything but "guess"
|
||||||
|
encoding = Encoding.GetEncoding(fallbackCodePage);
|
||||||
|
else // This is the "guess" option
|
||||||
|
{
|
||||||
|
int guess = new Guesser(stream).GuessCodePage();
|
||||||
|
stream.Seek(0, SeekOrigin.Begin);
|
||||||
|
if (guess == -1) // ==> this is a 7-bit file
|
||||||
|
encoding = Encoding.ASCII;
|
||||||
|
else if (guess == 65001)
|
||||||
|
encoding = Encoding.UTF8;
|
||||||
|
else // ==> use the machine default
|
||||||
|
encoding = Encoding.Default;
|
||||||
|
}
|
||||||
|
StreamReader reader = new StreamReader(stream, encoding);
|
||||||
|
return reader.Read;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int Preamble(Stream stream)
|
||||||
|
{
|
||||||
|
int b0 = stream.ReadByte();
|
||||||
|
int b1 = stream.ReadByte();
|
||||||
|
|
||||||
|
if (b0 == 0xfe && b1 == 0xff)
|
||||||
|
return 1201; // UTF16BE
|
||||||
|
if (b0 == 0xff && b1 == 0xfe)
|
||||||
|
return 1200; // UTF16LE
|
||||||
|
|
||||||
|
int b2 = stream.ReadByte();
|
||||||
|
if (b0 == 0xef && b1 == 0xbb && b2 == 0xbf)
|
||||||
|
return 65001; // UTF8
|
||||||
|
//
|
||||||
|
// There is no unicode preamble, so we
|
||||||
|
// return denoter for the machine default.
|
||||||
|
//
|
||||||
|
stream.Seek(0, SeekOrigin.Begin);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif // !BYTEMODE
|
||||||
|
}
|
||||||
|
#endif // !NOFILES
|
||||||
|
#endregion Buffer classes
|
||||||
|
|
||||||
|
// ==============================================================
|
||||||
|
// ============ class CodePageHandling =============
|
||||||
|
// ==============================================================
|
||||||
|
#if (!NOFILES)
|
||||||
|
public static class CodePageHandling
|
||||||
|
{
|
||||||
|
public static int GetCodePage(string option)
|
||||||
|
{
|
||||||
|
string command = option.ToUpperInvariant();
|
||||||
|
if (command.StartsWith("CodePage:", StringComparison.OrdinalIgnoreCase))
|
||||||
|
command = command.Substring(9);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (command.Equals("RAW"))
|
||||||
|
return -1;
|
||||||
|
else if (command.Equals("GUESS"))
|
||||||
|
return -2;
|
||||||
|
else if (command.Equals("DEFAULT"))
|
||||||
|
return 0;
|
||||||
|
else if (char.IsDigit(command[0]))
|
||||||
|
return int.Parse(command, CultureInfo.InvariantCulture);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Encoding enc = Encoding.GetEncoding(command);
|
||||||
|
return enc.CodePage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (FormatException)
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine(
|
||||||
|
"Invalid format \"{0}\", using machine default", option);
|
||||||
|
}
|
||||||
|
catch (ArgumentException)
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine(
|
||||||
|
"Unknown code page \"{0}\", using machine default", option);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#region guesser
|
||||||
|
#if (!BYTEMODE)
|
||||||
|
// ==============================================================
|
||||||
|
// ============ Encoding Guesser =============
|
||||||
|
// ==============================================================
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This class provides a simple finite state automaton that
|
||||||
|
/// scans the file looking for (1) valid UTF-8 byte patterns,
|
||||||
|
/// (2) bytes >= 0x80 which are not part of a UTF-8 sequence.
|
||||||
|
/// The method then guesses whether it is UTF-8 or maybe some
|
||||||
|
/// local machine default encoding. This works well for the
|
||||||
|
/// various Latin encodings.
|
||||||
|
/// </summary>
|
||||||
|
internal class Guesser
|
||||||
|
{
|
||||||
|
ScanBuff buffer;
|
||||||
|
|
||||||
|
public int GuessCodePage() { return Scan(); }
|
||||||
|
|
||||||
|
const int maxAccept = 10;
|
||||||
|
const int initial = 0;
|
||||||
|
const int eofNum = 0;
|
||||||
|
const int goStart = -1;
|
||||||
|
const int INITIAL = 0;
|
||||||
|
const int EndToken = 0;
|
||||||
|
|
||||||
|
#region user code
|
||||||
|
/*
|
||||||
|
* Reads the bytes of a file to determine if it is
|
||||||
|
* UTF-8 or a single-byte code page file.
|
||||||
|
*/
|
||||||
|
public long utfX;
|
||||||
|
public long uppr;
|
||||||
|
#endregion user code
|
||||||
|
|
||||||
|
int state;
|
||||||
|
int currentStart = startState[0];
|
||||||
|
int code;
|
||||||
|
|
||||||
|
#region ScannerTables
|
||||||
|
static int[] startState = new int[] { 11, 0 };
|
||||||
|
|
||||||
|
#region CharacterMap
|
||||||
|
static sbyte[] map = new sbyte[256] {
|
||||||
|
/* '\0' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
/* '\x10' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
/* '\x20' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
/* '0' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
/* '@' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
/* 'P' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
/* '`' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
/* 'p' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
/* '\x80' */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
/* '\x90' */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
/* '\xA0' */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
/* '\xB0' */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
/* '\xC0' */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
/* '\xD0' */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
/* '\xE0' */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||||
|
/* '\xF0' */ 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5 };
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
static sbyte[][] nextState = new sbyte[][] {
|
||||||
|
new sbyte[] {0, 0, 0, 0, 0, 0},
|
||||||
|
new sbyte[] {-1, -1, 10, -1, -1, -1},
|
||||||
|
new sbyte[] {-1, -1, -1, -1, -1, -1},
|
||||||
|
new sbyte[] {-1, -1, 8, -1, -1, -1},
|
||||||
|
new sbyte[] {-1, -1, 5, -1, -1, -1},
|
||||||
|
new sbyte[] {-1, -1, 6, -1, -1, -1},
|
||||||
|
new sbyte[] {-1, -1, 7, -1, -1, -1},
|
||||||
|
null,
|
||||||
|
new sbyte[] {-1, -1, 9, -1, -1, -1},
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
new sbyte[] {-1, 1, 2, 3, 4, 2}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
[SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")]
|
||||||
|
// Reason for suppression: cannot have self-reference in array initializer.
|
||||||
|
static Guesser()
|
||||||
|
{
|
||||||
|
nextState[7] = nextState[2];
|
||||||
|
nextState[9] = nextState[2];
|
||||||
|
nextState[10] = nextState[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
int NextState()
|
||||||
|
{
|
||||||
|
if (code == ScanBuff.EndOfFile)
|
||||||
|
return eofNum;
|
||||||
|
else
|
||||||
|
return nextState[state][map[code]];
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public Guesser(System.IO.Stream file) { SetSource(file); }
|
||||||
|
|
||||||
|
public void SetSource(System.IO.Stream source)
|
||||||
|
{
|
||||||
|
this.buffer = new BuildBuffer(source);
|
||||||
|
code = buffer.Read();
|
||||||
|
}
|
||||||
|
|
||||||
|
int Scan()
|
||||||
|
{
|
||||||
|
for (; ; )
|
||||||
|
{
|
||||||
|
int next;
|
||||||
|
state = currentStart;
|
||||||
|
while ((next = NextState()) == goStart)
|
||||||
|
code = buffer.Read();
|
||||||
|
|
||||||
|
state = next;
|
||||||
|
code = buffer.Read();
|
||||||
|
|
||||||
|
while ((next = NextState()) > eofNum)
|
||||||
|
{
|
||||||
|
state = next;
|
||||||
|
code = buffer.Read();
|
||||||
|
}
|
||||||
|
if (state <= maxAccept)
|
||||||
|
{
|
||||||
|
#region ActionSwitch
|
||||||
|
#pragma warning disable 162
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case eofNum:
|
||||||
|
switch (currentStart)
|
||||||
|
{
|
||||||
|
case 11:
|
||||||
|
if (utfX == 0 && uppr == 0) return -1; /* raw ascii */
|
||||||
|
else if (uppr * 10 > utfX) return 0; /* default code page */
|
||||||
|
else return 65001; /* UTF-8 encoding */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return EndToken;
|
||||||
|
case 1: // Recognized '{Upper128}', Shortest string "\xC0"
|
||||||
|
case 2: // Recognized '{Upper128}', Shortest string "\x80"
|
||||||
|
case 3: // Recognized '{Upper128}', Shortest string "\xE0"
|
||||||
|
case 4: // Recognized '{Upper128}', Shortest string "\xF0"
|
||||||
|
uppr++;
|
||||||
|
break;
|
||||||
|
case 5: // Recognized '{Utf8pfx4}{Utf8cont}', Shortest string "\xF0\x80"
|
||||||
|
uppr += 2;
|
||||||
|
break;
|
||||||
|
case 6: // Recognized '{Utf8pfx4}{Utf8cont}{2}', Shortest string "\xF0\x80\x80"
|
||||||
|
uppr += 3;
|
||||||
|
break;
|
||||||
|
case 7: // Recognized '{Utf8pfx4}{Utf8cont}{3}', Shortest string "\xF0\x80\x80\x80"
|
||||||
|
utfX += 3;
|
||||||
|
break;
|
||||||
|
case 8: // Recognized '{Utf8pfx3}{Utf8cont}', Shortest string "\xE0\x80"
|
||||||
|
uppr += 2;
|
||||||
|
break;
|
||||||
|
case 9: // Recognized '{Utf8pfx3}{Utf8cont}{2}', Shortest string "\xE0\x80\x80"
|
||||||
|
utfX += 2;
|
||||||
|
break;
|
||||||
|
case 10: // Recognized '{Utf8pfx2}{Utf8cont}', Shortest string "\xC0\x80"
|
||||||
|
utfX++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#pragma warning restore 162
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // end class Guesser
|
||||||
|
|
||||||
|
#endif // !BYTEMODE
|
||||||
|
#endregion
|
||||||
|
#endif // !NOFILES
|
||||||
|
|
||||||
|
// End of code copied from embedded resource
|
||||||
|
}
|
33
Experimental/Artemis/IPT.Language.analyzer.lex
Normal file
33
Experimental/Artemis/IPT.Language.analyzer.lex
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
%namespace GameRes.Formats.Artemis
|
||||||
|
%scannertype IPTScanner
|
||||||
|
%visibility internal
|
||||||
|
%tokentype Token
|
||||||
|
|
||||||
|
%option stack, minimize, parser, verbose, persistbuffer, noembedbuffers
|
||||||
|
|
||||||
|
Space [ \t\v\n\f]
|
||||||
|
Number [0-9]+
|
||||||
|
|
||||||
|
%{
|
||||||
|
|
||||||
|
%}
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
{Space}+ /* skip */
|
||||||
|
|
||||||
|
{Number} { GetNumber(); return (int)Token.NUMBER; }
|
||||||
|
|
||||||
|
\"(\\.|[^\\"\n])*\" { GetStringLiteral(); return (int)Token.STRING_LITERAL; }
|
||||||
|
|
||||||
|
[a-zA-Z]+ { yylval.s = yytext; return (int)Token.IDENTIFIER; }
|
||||||
|
|
||||||
|
"{" { return '{'; }
|
||||||
|
|
||||||
|
"}" { return '}'; }
|
||||||
|
|
||||||
|
"=" { return '='; }
|
||||||
|
|
||||||
|
"," { return ','; }
|
||||||
|
|
||||||
|
%%
|
49
Experimental/Artemis/IPT.Language.grammar.y
Normal file
49
Experimental/Artemis/IPT.Language.grammar.y
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
%namespace GameRes.Formats.Artemis
|
||||||
|
%partial
|
||||||
|
%parsertype IPTParser
|
||||||
|
%visibility internal
|
||||||
|
%tokentype Token
|
||||||
|
|
||||||
|
%union {
|
||||||
|
public int n;
|
||||||
|
public string s;
|
||||||
|
public IPTObject o;
|
||||||
|
}
|
||||||
|
|
||||||
|
%start input
|
||||||
|
|
||||||
|
%token NUMBER STRING_LITERAL IDENTIFIER
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
input: root_definition ;
|
||||||
|
|
||||||
|
root_definition: IDENTIFIER '=' object { RootObject[$1.s] = $3.o; }
|
||||||
|
;
|
||||||
|
|
||||||
|
object: '{' { BeginObject(); }
|
||||||
|
decl_list optional_comma
|
||||||
|
'}' { EndObject(); }
|
||||||
|
;
|
||||||
|
|
||||||
|
decl_list: statement
|
||||||
|
| decl_list ',' statement
|
||||||
|
;
|
||||||
|
|
||||||
|
optional_comma: ',' | /* empty */ ;
|
||||||
|
|
||||||
|
statement: definition | lvalue ;
|
||||||
|
|
||||||
|
definition: IDENTIFIER '=' value { CurrentObject[$1.s] = $3.Value; }
|
||||||
|
;
|
||||||
|
|
||||||
|
lvalue: value { CurrentObject.Values.Add ($1.Value); }
|
||||||
|
;
|
||||||
|
|
||||||
|
value: object | string | number ;
|
||||||
|
|
||||||
|
string: STRING_LITERAL ;
|
||||||
|
|
||||||
|
number: NUMBER ;
|
||||||
|
|
||||||
|
%%
|
151
Experimental/Artemis/IPT.Parser.Generated.cs
Normal file
151
Experimental/Artemis/IPT.Parser.Generated.cs
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
// This code was generated by the Gardens Point Parser Generator
|
||||||
|
// Copyright (c) Wayne Kelly, John Gough, QUT 2005-2014
|
||||||
|
// (see accompanying GPPGcopyright.rtf)
|
||||||
|
|
||||||
|
// GPPG version 1.5.2
|
||||||
|
|
||||||
|
// options: no-lines gplex
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.CodeDom.Compiler;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Text;
|
||||||
|
using QUT.Gppg;
|
||||||
|
|
||||||
|
namespace GameRes.Formats.Artemis
|
||||||
|
{
|
||||||
|
internal enum Token {
|
||||||
|
error=127,EOF=128,NUMBER=129,STRING_LITERAL=130,IDENTIFIER=131};
|
||||||
|
|
||||||
|
internal partial struct ValueType
|
||||||
|
{
|
||||||
|
public int n;
|
||||||
|
public string s;
|
||||||
|
public IPTObject o;
|
||||||
|
}
|
||||||
|
// Abstract base class for GPLEX scanners
|
||||||
|
[GeneratedCodeAttribute( "Gardens Point Parser Generator", "1.5.2")]
|
||||||
|
internal abstract class ScanBase : AbstractScanner<ValueType,LexLocation> {
|
||||||
|
private LexLocation __yylloc = new LexLocation();
|
||||||
|
public override LexLocation yylloc { get { return __yylloc; } set { __yylloc = value; } }
|
||||||
|
protected virtual bool yywrap() { return true; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Utility class for encapsulating token information
|
||||||
|
[GeneratedCodeAttribute( "Gardens Point Parser Generator", "1.5.2")]
|
||||||
|
internal class ScanObj {
|
||||||
|
public int token;
|
||||||
|
public ValueType yylval;
|
||||||
|
public LexLocation yylloc;
|
||||||
|
public ScanObj( int t, ValueType val, LexLocation loc ) {
|
||||||
|
this.token = t; this.yylval = val; this.yylloc = loc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[GeneratedCodeAttribute( "Gardens Point Parser Generator", "1.5.2")]
|
||||||
|
internal partial class IPTParser: ShiftReduceParser<ValueType, LexLocation>
|
||||||
|
{
|
||||||
|
#pragma warning disable 649
|
||||||
|
private static Dictionary<int, string> aliases;
|
||||||
|
#pragma warning restore 649
|
||||||
|
private static Rule[] rules = new Rule[19];
|
||||||
|
private static State[] states = new State[26];
|
||||||
|
private static string[] nonTerms = new string[] {
|
||||||
|
"input", "$accept", "root_definition", "object", "Anon@1", "decl_list",
|
||||||
|
"optional_comma", "statement", "definition", "lvalue", "value", "string",
|
||||||
|
"number", };
|
||||||
|
|
||||||
|
static IPTParser() {
|
||||||
|
states[0] = new State(new int[]{131,4},new int[]{-1,1,-3,3});
|
||||||
|
states[1] = new State(new int[]{128,2});
|
||||||
|
states[2] = new State(-1);
|
||||||
|
states[3] = new State(-2);
|
||||||
|
states[4] = new State(new int[]{61,5});
|
||||||
|
states[5] = new State(new int[]{123,7},new int[]{-4,6});
|
||||||
|
states[6] = new State(-3);
|
||||||
|
states[7] = new State(-4,new int[]{-5,8});
|
||||||
|
states[8] = new State(new int[]{131,15,123,7,130,20,129,22},new int[]{-6,9,-8,25,-9,14,-10,23,-11,24,-4,18,-12,19,-13,21});
|
||||||
|
states[9] = new State(new int[]{44,12,125,-9},new int[]{-7,10});
|
||||||
|
states[10] = new State(new int[]{125,11});
|
||||||
|
states[11] = new State(-5);
|
||||||
|
states[12] = new State(new int[]{131,15,123,7,130,20,129,22,125,-8},new int[]{-8,13,-9,14,-10,23,-11,24,-4,18,-12,19,-13,21});
|
||||||
|
states[13] = new State(-7);
|
||||||
|
states[14] = new State(-10);
|
||||||
|
states[15] = new State(new int[]{61,16});
|
||||||
|
states[16] = new State(new int[]{123,7,130,20,129,22},new int[]{-11,17,-4,18,-12,19,-13,21});
|
||||||
|
states[17] = new State(-12);
|
||||||
|
states[18] = new State(-14);
|
||||||
|
states[19] = new State(-15);
|
||||||
|
states[20] = new State(-17);
|
||||||
|
states[21] = new State(-16);
|
||||||
|
states[22] = new State(-18);
|
||||||
|
states[23] = new State(-11);
|
||||||
|
states[24] = new State(-13);
|
||||||
|
states[25] = new State(-6);
|
||||||
|
|
||||||
|
for (int sNo = 0; sNo < states.Length; sNo++) states[sNo].number = sNo;
|
||||||
|
|
||||||
|
rules[1] = new Rule(-2, new int[]{-1,128});
|
||||||
|
rules[2] = new Rule(-1, new int[]{-3});
|
||||||
|
rules[3] = new Rule(-3, new int[]{131,61,-4});
|
||||||
|
rules[4] = new Rule(-5, new int[]{});
|
||||||
|
rules[5] = new Rule(-4, new int[]{123,-5,-6,-7,125});
|
||||||
|
rules[6] = new Rule(-6, new int[]{-8});
|
||||||
|
rules[7] = new Rule(-6, new int[]{-6,44,-8});
|
||||||
|
rules[8] = new Rule(-7, new int[]{44});
|
||||||
|
rules[9] = new Rule(-7, new int[]{});
|
||||||
|
rules[10] = new Rule(-8, new int[]{-9});
|
||||||
|
rules[11] = new Rule(-8, new int[]{-10});
|
||||||
|
rules[12] = new Rule(-9, new int[]{131,61,-11});
|
||||||
|
rules[13] = new Rule(-10, new int[]{-11});
|
||||||
|
rules[14] = new Rule(-11, new int[]{-4});
|
||||||
|
rules[15] = new Rule(-11, new int[]{-12});
|
||||||
|
rules[16] = new Rule(-11, new int[]{-13});
|
||||||
|
rules[17] = new Rule(-12, new int[]{130});
|
||||||
|
rules[18] = new Rule(-13, new int[]{129});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Initialize() {
|
||||||
|
this.InitSpecialTokens((int)Token.error, (int)Token.EOF);
|
||||||
|
this.InitStates(states);
|
||||||
|
this.InitRules(rules);
|
||||||
|
this.InitNonTerminals(nonTerms);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void DoAction(int action)
|
||||||
|
{
|
||||||
|
#pragma warning disable 162, 1522
|
||||||
|
switch (action)
|
||||||
|
{
|
||||||
|
case 3: // root_definition -> IDENTIFIER, '=', object
|
||||||
|
{ RootObject[ValueStack[ValueStack.Depth-3].s] = ValueStack[ValueStack.Depth-1].o; }
|
||||||
|
break;
|
||||||
|
case 4: // Anon@1 -> /* empty */
|
||||||
|
{ BeginObject(); }
|
||||||
|
break;
|
||||||
|
case 5: // object -> '{', Anon@1, decl_list, optional_comma, '}'
|
||||||
|
{ EndObject(); }
|
||||||
|
break;
|
||||||
|
case 12: // definition -> IDENTIFIER, '=', value
|
||||||
|
{ CurrentObject[ValueStack[ValueStack.Depth-3].s] = ValueStack[ValueStack.Depth-1].Value; }
|
||||||
|
break;
|
||||||
|
case 13: // lvalue -> value
|
||||||
|
{ CurrentObject.Values.Add (ValueStack[ValueStack.Depth-1].Value); }
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#pragma warning restore 162, 1522
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override string TerminalToString(int terminal)
|
||||||
|
{
|
||||||
|
if (aliases != null && aliases.ContainsKey(terminal))
|
||||||
|
return aliases[terminal];
|
||||||
|
else if (((Token)terminal).ToString() != terminal.ToString(CultureInfo.InvariantCulture))
|
||||||
|
return ((Token)terminal).ToString();
|
||||||
|
else
|
||||||
|
return CharToString((char)terminal);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
64
Experimental/Artemis/IPT.Parser.cs
Normal file
64
Experimental/Artemis/IPT.Parser.cs
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace GameRes.Formats.Artemis
|
||||||
|
{
|
||||||
|
internal partial struct ValueType
|
||||||
|
{
|
||||||
|
public object Value { get { return o ?? s as object ?? (object)n; } }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal partial class IPTParser
|
||||||
|
{
|
||||||
|
public IPTParser () : base (null) { }
|
||||||
|
|
||||||
|
internal IPTObject RootObject { get; set; }
|
||||||
|
|
||||||
|
Stack<IPTObject> m_value_stack;
|
||||||
|
|
||||||
|
public void Parse (Stream s)
|
||||||
|
{
|
||||||
|
this.RootObject = new IPTObject();
|
||||||
|
m_value_stack = new Stack<IPTObject>();
|
||||||
|
this.Scanner = new IPTScanner (s);
|
||||||
|
this.Parse();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal IPTObject CurrentObject
|
||||||
|
{
|
||||||
|
get { return m_value_stack.Count > 0 ? m_value_stack.Peek() : RootObject; }
|
||||||
|
}
|
||||||
|
|
||||||
|
void BeginObject ()
|
||||||
|
{
|
||||||
|
m_value_stack.Push (new IPTObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndObject ()
|
||||||
|
{
|
||||||
|
CurrentSemanticValue.o = m_value_stack.Pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class IPTObject
|
||||||
|
{
|
||||||
|
Hashtable m_dict = new Hashtable();
|
||||||
|
ArrayList m_values = new ArrayList();
|
||||||
|
|
||||||
|
public ArrayList Values { get { return m_values; } }
|
||||||
|
|
||||||
|
public object this[string field]
|
||||||
|
{
|
||||||
|
get { return m_dict[field]; }
|
||||||
|
set { m_dict[field] = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Contains (string field)
|
||||||
|
{
|
||||||
|
return m_dict.ContainsKey (field);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
713
Experimental/Artemis/IPT.Scanner.Generated.cs
Normal file
713
Experimental/Artemis/IPT.Scanner.Generated.cs
Normal file
@ -0,0 +1,713 @@
|
|||||||
|
//
|
||||||
|
// This CSharp output file generated by Gardens Point LEX
|
||||||
|
// Gardens Point LEX (GPLEX) is Copyright (c) John Gough, QUT 2006-2014.
|
||||||
|
// Output produced by GPLEX is the property of the user.
|
||||||
|
// See accompanying file GPLEXcopyright.rtf.
|
||||||
|
//
|
||||||
|
// GPLEX Version: 1.2.2
|
||||||
|
// GPLEX frame file <embedded resource>
|
||||||
|
//
|
||||||
|
// Option settings: verbose, parser, stack, minimize
|
||||||
|
// Option settings: compressNext, persistBuffer, noEmbedBuffers
|
||||||
|
//
|
||||||
|
|
||||||
|
//
|
||||||
|
// Revised backup code
|
||||||
|
// Version 1.2.1 of 24-June-2013
|
||||||
|
//
|
||||||
|
//
|
||||||
|
#define STACK
|
||||||
|
#define PERSIST
|
||||||
|
#define BYTEMODE
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
|
using QUT.GplexBuffers;
|
||||||
|
|
||||||
|
namespace GameRes.Formats.Artemis
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Summary Canonical example of GPLEX automaton
|
||||||
|
/// </summary>
|
||||||
|
|
||||||
|
#if STANDALONE
|
||||||
|
//
|
||||||
|
// These are the dummy declarations for stand-alone GPLEX applications
|
||||||
|
// normally these declarations would come from the parser.
|
||||||
|
// If you declare /noparser, or %option noparser then you get this.
|
||||||
|
//
|
||||||
|
|
||||||
|
internal enum Token
|
||||||
|
{
|
||||||
|
EOF = 0, maxParseToken = int.MaxValue
|
||||||
|
// must have at least these two, values are almost arbitrary
|
||||||
|
}
|
||||||
|
|
||||||
|
internal abstract class ScanBase
|
||||||
|
{
|
||||||
|
[SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yylex")]
|
||||||
|
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yylex")]
|
||||||
|
public abstract int yylex();
|
||||||
|
|
||||||
|
[SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yywrap")]
|
||||||
|
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yywrap")]
|
||||||
|
protected virtual bool yywrap() { return true; }
|
||||||
|
|
||||||
|
#if BABEL
|
||||||
|
protected abstract int CurrentSc { get; set; }
|
||||||
|
// EolState is the 32-bit of state data persisted at
|
||||||
|
// the end of each line for Visual Studio colorization.
|
||||||
|
// The default is to return CurrentSc. You must override
|
||||||
|
// this if you want more complicated behavior.
|
||||||
|
public virtual int EolState {
|
||||||
|
get { return CurrentSc; }
|
||||||
|
set { CurrentSc = value; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal interface IColorScan
|
||||||
|
{
|
||||||
|
void SetSource(string source, int offset);
|
||||||
|
int GetNext(ref int state, out int start, out int end);
|
||||||
|
#endif // BABEL
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // STANDALONE
|
||||||
|
|
||||||
|
// If the compiler can't find the scanner base class maybe you
|
||||||
|
// need to run GPPG with the /gplex option, or GPLEX with /noparser
|
||||||
|
#if BABEL
|
||||||
|
internal sealed partial class IPTScanner : ScanBase, IColorScan
|
||||||
|
{
|
||||||
|
private ScanBuff buffer;
|
||||||
|
int currentScOrd; // start condition ordinal
|
||||||
|
|
||||||
|
protected override int CurrentSc
|
||||||
|
{
|
||||||
|
// The current start state is a property
|
||||||
|
// to try to avoid the user error of setting
|
||||||
|
// scState but forgetting to update the FSA
|
||||||
|
// start state "currentStart"
|
||||||
|
//
|
||||||
|
get { return currentScOrd; } // i.e. return YY_START;
|
||||||
|
set { currentScOrd = value; // i.e. BEGIN(value);
|
||||||
|
currentStart = startState[value]; }
|
||||||
|
}
|
||||||
|
#else // BABEL
|
||||||
|
internal sealed partial class IPTScanner : ScanBase
|
||||||
|
{
|
||||||
|
private ScanBuff buffer;
|
||||||
|
int currentScOrd; // start condition ordinal
|
||||||
|
#endif // BABEL
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The input buffer for this scanner.
|
||||||
|
/// </summary>
|
||||||
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||||
|
public ScanBuff Buffer { get { return buffer; } }
|
||||||
|
|
||||||
|
private static int GetMaxParseToken() {
|
||||||
|
System.Reflection.FieldInfo f = typeof(Token).GetField("maxParseToken");
|
||||||
|
return (f == null ? int.MaxValue : (int)f.GetValue(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parserMax = GetMaxParseToken();
|
||||||
|
|
||||||
|
enum Result {accept, noMatch, contextFound};
|
||||||
|
|
||||||
|
const int maxAccept = 8;
|
||||||
|
const int initial = 9;
|
||||||
|
const int eofNum = 0;
|
||||||
|
const int goStart = -1;
|
||||||
|
const int INITIAL = 0;
|
||||||
|
|
||||||
|
#region user code
|
||||||
|
#endregion user code
|
||||||
|
|
||||||
|
int state;
|
||||||
|
int currentStart = startState[0];
|
||||||
|
int code; // last code read
|
||||||
|
int cCol; // column number of code
|
||||||
|
int lNum; // current line number
|
||||||
|
//
|
||||||
|
// The following instance variables are used, among other
|
||||||
|
// things, for constructing the yylloc location objects.
|
||||||
|
//
|
||||||
|
int tokPos; // buffer position at start of token
|
||||||
|
int tokCol; // zero-based column number at start of token
|
||||||
|
int tokLin; // line number at start of token
|
||||||
|
int tokEPos; // buffer position at end of token
|
||||||
|
int tokECol; // column number at end of token
|
||||||
|
int tokELin; // line number at end of token
|
||||||
|
string tokTxt; // lazily constructed text of token
|
||||||
|
#if STACK
|
||||||
|
private Stack<int> scStack = new Stack<int>();
|
||||||
|
#endif // STACK
|
||||||
|
|
||||||
|
#region ScannerTables
|
||||||
|
struct Table {
|
||||||
|
public int min; public int rng; public int dflt;
|
||||||
|
public sbyte[] nxt;
|
||||||
|
public Table(int m, int x, int d, sbyte[] n) {
|
||||||
|
min = m; rng = x; dflt = d; nxt = n;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static int[] startState = new int[] {9, 0};
|
||||||
|
|
||||||
|
static Table[] NxS = new Table[12] {
|
||||||
|
/* NxS[ 0] */ new Table(0, 0, 0, null), // Shortest string ""
|
||||||
|
/* NxS[ 1] */ // Shortest string "\t"
|
||||||
|
new Table(9, 24, -1, new sbyte[] {1, 1, 1, 1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, 1}),
|
||||||
|
/* NxS[ 2] */ new Table(0, 0, -1, null), // Shortest string ","
|
||||||
|
/* NxS[ 3] */ // Shortest string "0"
|
||||||
|
new Table(48, 10, -1, new sbyte[] {3, 3, 3, 3, 3, 3,
|
||||||
|
3, 3, 3, 3}),
|
||||||
|
/* NxS[ 4] */ new Table(0, 0, -1, null), // Shortest string "="
|
||||||
|
/* NxS[ 5] */ // Shortest string "A"
|
||||||
|
new Table(65, 58, -1, new sbyte[] {5, 5, 5, 5, 5, 5,
|
||||||
|
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||||
|
5, 5, 5, 5, -1, -1, -1, -1, -1, -1, 5, 5, 5, 5, 5, 5,
|
||||||
|
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||||
|
5, 5, 5, 5}),
|
||||||
|
/* NxS[ 6] */ new Table(0, 0, -1, null), // Shortest string "{"
|
||||||
|
/* NxS[ 7] */ new Table(0, 0, -1, null), // Shortest string "}"
|
||||||
|
/* NxS[ 8] */ new Table(0, 0, -1, null), // Shortest string "\"\""
|
||||||
|
/* NxS[ 9] */ // Shortest string ""
|
||||||
|
new Table(9, 117, -1, new sbyte[] {1, 1, 1, 1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, 1, -1, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, -1, -1,
|
||||||
|
-1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, -1, -1, -1, 4, -1,
|
||||||
|
-1, -1, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||||
|
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1,
|
||||||
|
-1, -1, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||||
|
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, -1, 7}),
|
||||||
|
/* NxS[ 10] */ // Shortest string "\""
|
||||||
|
new Table(10, 83, 10, new sbyte[] {-1, 10, 10, 10, 10, 10,
|
||||||
|
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||||
|
10, 10, 8, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||||
|
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||||
|
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||||
|
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11}),
|
||||||
|
/* NxS[ 11] */ // Shortest string "\"\\"
|
||||||
|
new Table(10, 1, 10, new sbyte[] {-1}),
|
||||||
|
};
|
||||||
|
|
||||||
|
int NextState() {
|
||||||
|
if (code == ScanBuff.EndOfFile)
|
||||||
|
return eofNum;
|
||||||
|
else
|
||||||
|
unchecked {
|
||||||
|
int rslt;
|
||||||
|
int idx = (byte)(code - NxS[state].min);
|
||||||
|
if ((uint)idx >= (uint)NxS[state].rng) rslt = NxS[state].dflt;
|
||||||
|
else rslt = NxS[state].nxt[idx];
|
||||||
|
return rslt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#if BACKUP
|
||||||
|
// ==============================================================
|
||||||
|
// == Nested struct used for backup in automata that do backup ==
|
||||||
|
// ==============================================================
|
||||||
|
|
||||||
|
struct Context // class used for automaton backup.
|
||||||
|
{
|
||||||
|
public int bPos;
|
||||||
|
public int rPos; // scanner.readPos saved value
|
||||||
|
public int cCol;
|
||||||
|
public int lNum; // Need this in case of backup over EOL.
|
||||||
|
public int state;
|
||||||
|
public int cChr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Context ctx = new Context();
|
||||||
|
#endif // BACKUP
|
||||||
|
|
||||||
|
// ==============================================================
|
||||||
|
// ==== Nested struct to support input switching in scanners ====
|
||||||
|
// ==============================================================
|
||||||
|
|
||||||
|
struct BufferContext {
|
||||||
|
internal ScanBuff buffSv;
|
||||||
|
internal int chrSv;
|
||||||
|
internal int cColSv;
|
||||||
|
internal int lNumSv;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==============================================================
|
||||||
|
// ===== Private methods to save and restore buffer contexts ====
|
||||||
|
// ==============================================================
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This method creates a buffer context record from
|
||||||
|
/// the current buffer object, together with some
|
||||||
|
/// scanner state values.
|
||||||
|
/// </summary>
|
||||||
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||||
|
BufferContext MkBuffCtx()
|
||||||
|
{
|
||||||
|
BufferContext rslt;
|
||||||
|
rslt.buffSv = this.buffer;
|
||||||
|
rslt.chrSv = this.code;
|
||||||
|
rslt.cColSv = this.cCol;
|
||||||
|
rslt.lNumSv = this.lNum;
|
||||||
|
return rslt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This method restores the buffer value and allied
|
||||||
|
/// scanner state from the given context record value.
|
||||||
|
/// </summary>
|
||||||
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||||
|
void RestoreBuffCtx(BufferContext value)
|
||||||
|
{
|
||||||
|
this.buffer = value.buffSv;
|
||||||
|
this.code = value.chrSv;
|
||||||
|
this.cCol = value.cColSv;
|
||||||
|
this.lNum = value.lNumSv;
|
||||||
|
}
|
||||||
|
// =================== End Nested classes =======================
|
||||||
|
|
||||||
|
#if !NOFILES
|
||||||
|
internal IPTScanner(Stream file) {
|
||||||
|
SetSource(file); // no unicode option
|
||||||
|
}
|
||||||
|
#endif // !NOFILES
|
||||||
|
|
||||||
|
internal IPTScanner() { }
|
||||||
|
|
||||||
|
private int readPos;
|
||||||
|
|
||||||
|
void GetCode()
|
||||||
|
{
|
||||||
|
if (code == '\n') // This needs to be fixed for other conventions
|
||||||
|
// i.e. [\r\n\205\u2028\u2029]
|
||||||
|
{
|
||||||
|
cCol = -1;
|
||||||
|
lNum++;
|
||||||
|
}
|
||||||
|
readPos = buffer.Pos;
|
||||||
|
|
||||||
|
// Now read new codepoint.
|
||||||
|
code = buffer.Read();
|
||||||
|
if (code > ScanBuff.EndOfFile)
|
||||||
|
{
|
||||||
|
#if (!BYTEMODE)
|
||||||
|
if (code >= 0xD800 && code <= 0xDBFF)
|
||||||
|
{
|
||||||
|
int next = buffer.Read();
|
||||||
|
if (next < 0xDC00 || next > 0xDFFF)
|
||||||
|
code = ScanBuff.UnicodeReplacementChar;
|
||||||
|
else
|
||||||
|
code = (0x10000 + ((code & 0x3FF) << 10) + (next & 0x3FF));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
cCol++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MarkToken()
|
||||||
|
{
|
||||||
|
#if (!PERSIST)
|
||||||
|
buffer.Mark();
|
||||||
|
#endif
|
||||||
|
tokPos = readPos;
|
||||||
|
tokLin = lNum;
|
||||||
|
tokCol = cCol;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MarkEnd()
|
||||||
|
{
|
||||||
|
tokTxt = null;
|
||||||
|
tokEPos = readPos;
|
||||||
|
tokELin = lNum;
|
||||||
|
tokECol = cCol;
|
||||||
|
}
|
||||||
|
|
||||||
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||||
|
int Peek()
|
||||||
|
{
|
||||||
|
int rslt, codeSv = code, cColSv = cCol, lNumSv = lNum, bPosSv = buffer.Pos;
|
||||||
|
GetCode(); rslt = code;
|
||||||
|
lNum = lNumSv; cCol = cColSv; code = codeSv; buffer.Pos = bPosSv;
|
||||||
|
return rslt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==============================================================
|
||||||
|
// ===== Initialization of string-based input buffers ====
|
||||||
|
// ==============================================================
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create and initialize a StringBuff buffer object for this scanner
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="source">the input string</param>
|
||||||
|
/// <param name="offset">starting offset in the string</param>
|
||||||
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||||
|
public void SetSource(string source, int offset)
|
||||||
|
{
|
||||||
|
this.buffer = ScanBuff.GetBuffer(source);
|
||||||
|
this.buffer.Pos = offset;
|
||||||
|
this.lNum = 0;
|
||||||
|
this.code = '\n'; // to initialize yyline, yycol and lineStart
|
||||||
|
GetCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================ LineBuffer Initialization ===================
|
||||||
|
/// <summary>
|
||||||
|
/// Create and initialize a LineBuff buffer object for this scanner
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="source">the list of input strings</param>
|
||||||
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||||
|
public void SetSource(IList<string> source)
|
||||||
|
{
|
||||||
|
this.buffer = ScanBuff.GetBuffer(source);
|
||||||
|
this.code = '\n'; // to initialize yyline, yycol and lineStart
|
||||||
|
this.lNum = 0;
|
||||||
|
GetCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !NOFILES
|
||||||
|
// =============== StreamBuffer Initialization ==================
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create and initialize a StreamBuff buffer object for this scanner.
|
||||||
|
/// StreamBuff is buffer for 8-bit byte files.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="source">the input byte stream</param>
|
||||||
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||||
|
public void SetSource(Stream source)
|
||||||
|
{
|
||||||
|
this.buffer = ScanBuff.GetBuffer(source);
|
||||||
|
this.lNum = 0;
|
||||||
|
this.code = '\n'; // to initialize yyline, yycol and lineStart
|
||||||
|
GetCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !BYTEMODE
|
||||||
|
// ================ TextBuffer Initialization ===================
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create and initialize a TextBuff buffer object for this scanner.
|
||||||
|
/// TextBuff is a buffer for encoded unicode files.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="source">the input text file</param>
|
||||||
|
/// <param name="fallbackCodePage">Code page to use if file has
|
||||||
|
/// no BOM. For 0, use machine default; for -1, 8-bit binary</param>
|
||||||
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||||
|
public void SetSource(Stream source, int fallbackCodePage)
|
||||||
|
{
|
||||||
|
this.buffer = ScanBuff.GetBuffer(source, fallbackCodePage);
|
||||||
|
this.lNum = 0;
|
||||||
|
this.code = '\n'; // to initialize yyline, yycol and lineStart
|
||||||
|
GetCode();
|
||||||
|
}
|
||||||
|
#endif // !BYTEMODE
|
||||||
|
#endif // !NOFILES
|
||||||
|
|
||||||
|
// ==============================================================
|
||||||
|
|
||||||
|
#if BABEL
|
||||||
|
//
|
||||||
|
// Get the next token for Visual Studio
|
||||||
|
//
|
||||||
|
// "state" is the inout mode variable that maintains scanner
|
||||||
|
// state between calls, using the EolState property. In principle,
|
||||||
|
// if the calls of EolState are costly set could be called once
|
||||||
|
// only per line, at the start; and get called only at the end
|
||||||
|
// of the line. This needs more infrastructure ...
|
||||||
|
//
|
||||||
|
public int GetNext(ref int state, out int start, out int end)
|
||||||
|
{
|
||||||
|
Token next;
|
||||||
|
int s, e;
|
||||||
|
s = state; // state at start
|
||||||
|
EolState = state;
|
||||||
|
next = (Token)Scan();
|
||||||
|
state = EolState;
|
||||||
|
e = state; // state at end;
|
||||||
|
start = tokPos;
|
||||||
|
end = tokEPos - 1; // end is the index of last char.
|
||||||
|
return (int)next;
|
||||||
|
}
|
||||||
|
#endif // BABEL
|
||||||
|
|
||||||
|
// ======== AbstractScanner<> Implementation =========
|
||||||
|
|
||||||
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||||
|
[SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yylex")]
|
||||||
|
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yylex")]
|
||||||
|
public override int yylex()
|
||||||
|
{
|
||||||
|
// parserMax is set by reflecting on the Tokens
|
||||||
|
// enumeration. If maxParseToken is defined
|
||||||
|
// that is used, otherwise int.MaxValue is used.
|
||||||
|
int next;
|
||||||
|
do { next = Scan(); } while (next >= parserMax);
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||||
|
int yypos { get { return tokPos; } }
|
||||||
|
|
||||||
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||||
|
int yyline { get { return tokLin; } }
|
||||||
|
|
||||||
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||||
|
int yycol { get { return tokCol; } }
|
||||||
|
|
||||||
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||||
|
[SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yytext")]
|
||||||
|
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yytext")]
|
||||||
|
public string yytext
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (tokTxt == null)
|
||||||
|
tokTxt = buffer.GetString(tokPos, tokEPos);
|
||||||
|
return tokTxt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Discards all but the first "n" codepoints in the recognized pattern.
|
||||||
|
/// Resets the buffer position so that only n codepoints have been consumed;
|
||||||
|
/// yytext is also re-evaluated.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="n">The number of codepoints to consume</param>
|
||||||
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||||
|
void yyless(int n)
|
||||||
|
{
|
||||||
|
buffer.Pos = tokPos;
|
||||||
|
// Must read at least one char, so set before start.
|
||||||
|
cCol = tokCol - 1;
|
||||||
|
GetCode();
|
||||||
|
// Now ensure that line counting is correct.
|
||||||
|
lNum = tokLin;
|
||||||
|
// And count the rest of the text.
|
||||||
|
for (int i = 0; i < n; i++) GetCode();
|
||||||
|
MarkEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// It would be nice to count backward in the text
|
||||||
|
// but it does not seem possible to re-establish
|
||||||
|
// the correct column counts except by going forward.
|
||||||
|
//
|
||||||
|
/// <summary>
|
||||||
|
/// Removes the last "n" code points from the pattern.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="n">The number to remove</param>
|
||||||
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||||
|
void _yytrunc(int n) { yyless(yyleng - n); }
|
||||||
|
|
||||||
|
//
|
||||||
|
// This is painful, but we no longer count
|
||||||
|
// codepoints. For the overwhelming majority
|
||||||
|
// of cases the single line code is fast, for
|
||||||
|
// the others, well, at least it is all in the
|
||||||
|
// buffer so no files are touched. Note that we
|
||||||
|
// can't use (tokEPos - tokPos) because of the
|
||||||
|
// possibility of surrogate pairs in the token.
|
||||||
|
//
|
||||||
|
/// <summary>
|
||||||
|
/// The length of the pattern in codepoints (not the same as
|
||||||
|
/// string-length if the pattern contains any surrogate pairs).
|
||||||
|
/// </summary>
|
||||||
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||||
|
[SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yyleng")]
|
||||||
|
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yyleng")]
|
||||||
|
public int yyleng
|
||||||
|
{
|
||||||
|
get {
|
||||||
|
if (tokELin == tokLin)
|
||||||
|
return tokECol - tokCol;
|
||||||
|
else
|
||||||
|
#if BYTEMODE
|
||||||
|
return tokEPos - tokPos;
|
||||||
|
#else
|
||||||
|
{
|
||||||
|
int ch;
|
||||||
|
int count = 0;
|
||||||
|
int save = buffer.Pos;
|
||||||
|
buffer.Pos = tokPos;
|
||||||
|
do {
|
||||||
|
ch = buffer.Read();
|
||||||
|
if (!char.IsHighSurrogate((char)ch)) count++;
|
||||||
|
} while (buffer.Pos < tokEPos && ch != ScanBuff.EndOfFile);
|
||||||
|
buffer.Pos = save;
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
#endif // BYTEMODE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============ methods available in actions ==============
|
||||||
|
|
||||||
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||||
|
internal int YY_START {
|
||||||
|
get { return currentScOrd; }
|
||||||
|
set { currentScOrd = value;
|
||||||
|
currentStart = startState[value];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||||
|
internal void BEGIN(int next) {
|
||||||
|
currentScOrd = next;
|
||||||
|
currentStart = startState[next];
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============== The main tokenizer code =================
|
||||||
|
|
||||||
|
int Scan() {
|
||||||
|
for (; ; ) {
|
||||||
|
int next; // next state to enter
|
||||||
|
#if LEFTANCHORS
|
||||||
|
for (;;) {
|
||||||
|
// Discard characters that do not start any pattern.
|
||||||
|
// Must check the left anchor condition after *every* GetCode!
|
||||||
|
state = ((cCol == 0) ? anchorState[currentScOrd] : currentStart);
|
||||||
|
if ((next = NextState()) != goStart) break; // LOOP EXIT HERE...
|
||||||
|
GetCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // !LEFTANCHORS
|
||||||
|
state = currentStart;
|
||||||
|
while ((next = NextState()) == goStart) {
|
||||||
|
// At this point, the current character has no
|
||||||
|
// transition from the current state. We discard
|
||||||
|
// the "no-match" char. In traditional LEX such
|
||||||
|
// characters are echoed to the console.
|
||||||
|
GetCode();
|
||||||
|
}
|
||||||
|
#endif // LEFTANCHORS
|
||||||
|
// At last, a valid transition ...
|
||||||
|
MarkToken();
|
||||||
|
state = next;
|
||||||
|
GetCode();
|
||||||
|
#if BACKUP
|
||||||
|
bool contextSaved = false;
|
||||||
|
while ((next = NextState()) > eofNum) { // Exit for goStart AND for eofNum
|
||||||
|
if (state <= maxAccept && next > maxAccept) { // need to prepare backup data
|
||||||
|
// Store data for the *latest* accept state that was found.
|
||||||
|
SaveStateAndPos( ref ctx );
|
||||||
|
contextSaved = true;
|
||||||
|
}
|
||||||
|
state = next;
|
||||||
|
GetCode();
|
||||||
|
}
|
||||||
|
if (state > maxAccept && contextSaved)
|
||||||
|
RestoreStateAndPos( ref ctx );
|
||||||
|
#else // BACKUP
|
||||||
|
while ((next = NextState()) > eofNum) { // Exit for goStart AND for eofNum
|
||||||
|
state = next;
|
||||||
|
GetCode();
|
||||||
|
}
|
||||||
|
#endif // BACKUP
|
||||||
|
if (state <= maxAccept) {
|
||||||
|
MarkEnd();
|
||||||
|
#region ActionSwitch
|
||||||
|
#pragma warning disable 162, 1522
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case eofNum:
|
||||||
|
if (yywrap())
|
||||||
|
return (int)Token.EOF;
|
||||||
|
break;
|
||||||
|
case 1: // Recognized '{Space}+', Shortest string "\t"
|
||||||
|
/* skip */
|
||||||
|
break;
|
||||||
|
case 2: // Recognized '","', Shortest string ","
|
||||||
|
return ',';
|
||||||
|
break;
|
||||||
|
case 3: // Recognized '{Number}', Shortest string "0"
|
||||||
|
GetNumber(); return (int)Token.NUMBER;
|
||||||
|
break;
|
||||||
|
case 4: // Recognized '"="', Shortest string "="
|
||||||
|
return '=';
|
||||||
|
break;
|
||||||
|
case 5: // Recognized '[a-zA-Z]+', Shortest string "A"
|
||||||
|
yylval.s = yytext; return (int)Token.IDENTIFIER;
|
||||||
|
break;
|
||||||
|
case 6: // Recognized '"{"', Shortest string "{"
|
||||||
|
return '{';
|
||||||
|
break;
|
||||||
|
case 7: // Recognized '"}"', Shortest string "}"
|
||||||
|
return '}';
|
||||||
|
break;
|
||||||
|
case 8: // Recognized '\"(\\.|[^\\"\n])*\"', Shortest string "\"\""
|
||||||
|
GetStringLiteral(); return (int)Token.STRING_LITERAL;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#pragma warning restore 162, 1522
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if BACKUP
|
||||||
|
void SaveStateAndPos(ref Context ctx) {
|
||||||
|
ctx.bPos = buffer.Pos;
|
||||||
|
ctx.rPos = readPos;
|
||||||
|
ctx.cCol = cCol;
|
||||||
|
ctx.lNum = lNum;
|
||||||
|
ctx.state = state;
|
||||||
|
ctx.cChr = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RestoreStateAndPos(ref Context ctx) {
|
||||||
|
buffer.Pos = ctx.bPos;
|
||||||
|
readPos = ctx.rPos;
|
||||||
|
cCol = ctx.cCol;
|
||||||
|
lNum = ctx.lNum;
|
||||||
|
state = ctx.state;
|
||||||
|
code = ctx.cChr;
|
||||||
|
}
|
||||||
|
#endif // BACKUP
|
||||||
|
|
||||||
|
// ============= End of the tokenizer code ================
|
||||||
|
|
||||||
|
#if STACK
|
||||||
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||||
|
internal void yy_clear_stack() { scStack.Clear(); }
|
||||||
|
|
||||||
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||||
|
internal int yy_top_state() { return scStack.Peek(); }
|
||||||
|
|
||||||
|
internal void yy_push_state(int state)
|
||||||
|
{
|
||||||
|
scStack.Push(currentScOrd);
|
||||||
|
BEGIN(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void yy_pop_state()
|
||||||
|
{
|
||||||
|
// Protect against input errors that pop too far ...
|
||||||
|
if (scStack.Count > 0) {
|
||||||
|
int newSc = scStack.Pop();
|
||||||
|
BEGIN(newSc);
|
||||||
|
} // Otherwise leave stack unchanged.
|
||||||
|
}
|
||||||
|
#endif // STACK
|
||||||
|
|
||||||
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||||
|
internal void ECHO() { Console.Out.Write(yytext); }
|
||||||
|
|
||||||
|
} // end class $Scanner
|
||||||
|
|
||||||
|
|
||||||
|
} // end namespace
|
36
Experimental/Artemis/IPT.Scanner.cs
Normal file
36
Experimental/Artemis/IPT.Scanner.cs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace GameRes.Formats.Artemis
|
||||||
|
{
|
||||||
|
internal partial class IPTScanner
|
||||||
|
{
|
||||||
|
void GetNumber()
|
||||||
|
{
|
||||||
|
yylval.n = int.Parse (yytext);
|
||||||
|
yylval.s = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetStringLiteral ()
|
||||||
|
{
|
||||||
|
yylval.s = yytext.Substring (1, yytext.Length-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void yyerror (string format, params object[] args)
|
||||||
|
{
|
||||||
|
base.yyerror (format, args);
|
||||||
|
if (args.Length > 0)
|
||||||
|
throw new YYParseException (string.Format (format, args));
|
||||||
|
else
|
||||||
|
throw new YYParseException (format);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class YYParseException : Exception
|
||||||
|
{
|
||||||
|
public YYParseException (string message) : base (message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
4
Experimental/Artemis/IPT.parser
Normal file
4
Experimental/Artemis/IPT.parser
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
Parser placeholder
|
||||||
|
------------------
|
||||||
|
|
||||||
|
This is only a placeholder file for grouping the component files (LEX, YACC) that compose the parser.
|
210
Experimental/Artemis/ImageIPT.cs
Normal file
210
Experimental/Artemis/ImageIPT.cs
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
//! \file ImageIPT.cs
|
||||||
|
//! \date 2019 Jan 27
|
||||||
|
//! \brief IPT composite image desciption.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2019 by morkt
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.Composition;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
|
||||||
|
namespace GameRes.Formats.Artemis
|
||||||
|
{
|
||||||
|
internal class IptTile
|
||||||
|
{
|
||||||
|
public int Id;
|
||||||
|
public string FileName;
|
||||||
|
public int X;
|
||||||
|
public int Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class IptMetaData : ImageMetaData
|
||||||
|
{
|
||||||
|
public string Mode;
|
||||||
|
public string BaseName;
|
||||||
|
public IEnumerable<IptTile> Tiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Export(typeof(ImageFormat))]
|
||||||
|
public class IptFormat : ImageFormat
|
||||||
|
{
|
||||||
|
public override string Tag { get { return "IPT"; } }
|
||||||
|
public override string Description { get { return "Artemis composite image descriptor"; } }
|
||||||
|
public override uint Signature { get { return 0; } }
|
||||||
|
|
||||||
|
public override ImageMetaData ReadMetaData (IBinaryStream file)
|
||||||
|
{
|
||||||
|
if (!file.Name.HasExtension (".ipt"))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var parser = new IPTParser();
|
||||||
|
parser.Parse (file.AsStream);
|
||||||
|
var ipt = parser.RootObject["ipt"] as IPTObject;
|
||||||
|
if (null == ipt)
|
||||||
|
return null;
|
||||||
|
var mode = ipt["mode"] as string;
|
||||||
|
var canvas = ipt["base"] as IPTObject;
|
||||||
|
if (null == mode || null == canvas)
|
||||||
|
return null;
|
||||||
|
var tiles = ipt.Values.Cast<IPTObject>() .Select (t => new IptTile {
|
||||||
|
Id = (int)t["id"],
|
||||||
|
FileName = (string)t["file"],
|
||||||
|
X = (int)t["x"],
|
||||||
|
Y = (int)t["y"],
|
||||||
|
}); // XXX order by Id?
|
||||||
|
if ("cut" == mode && !tiles.Any())
|
||||||
|
return null;
|
||||||
|
return new IptMetaData {
|
||||||
|
Width = (uint)(int)canvas["w"],
|
||||||
|
Height = (uint)(int)canvas["h"],
|
||||||
|
OffsetX = (int)canvas["x"],
|
||||||
|
OffsetY = (int)canvas["y"],
|
||||||
|
BPP = 32,
|
||||||
|
Mode = mode,
|
||||||
|
BaseName = (string)canvas.Values[0],
|
||||||
|
Tiles = tiles.ToList(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public override ImageData Read (IBinaryStream file, ImageMetaData info)
|
||||||
|
{
|
||||||
|
var meta = (IptMetaData)info;
|
||||||
|
if (meta.Mode != "diff" && meta.Mode != "cut")
|
||||||
|
throw new InvalidFormatException (string.Format ("Not supported IPT tile mode '{0}'.", meta.Mode));
|
||||||
|
var canvas = new WriteableBitmap (meta.iWidth, meta.iHeight, ImageData.DefaultDpiX,
|
||||||
|
ImageData.DefaultDpiY, PixelFormats.Bgr32, null);
|
||||||
|
var base_dir = VFS.GetDirectoryName (file.Name);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
canvas.Lock();
|
||||||
|
if ("diff" == meta.Mode)
|
||||||
|
{
|
||||||
|
var base_name = VFS.CombinePath (base_dir, meta.BaseName + ".png");
|
||||||
|
ReadIntoCanvas (base_name, canvas, 0, 0);
|
||||||
|
}
|
||||||
|
foreach (var tile in meta.Tiles)
|
||||||
|
{
|
||||||
|
var tile_name = VFS.CombinePath (base_dir, tile.FileName + ".png");
|
||||||
|
ReadIntoCanvas (tile_name, canvas, tile.X, tile.Y, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
canvas.Unlock();
|
||||||
|
}
|
||||||
|
canvas.Freeze();
|
||||||
|
return new ImageData (canvas, meta);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReadIntoCanvas (string filename, WriteableBitmap output, int x, int y, bool blend = false)
|
||||||
|
{
|
||||||
|
if (y >= output.PixelHeight || x >= output.PixelWidth)
|
||||||
|
return;
|
||||||
|
var tile = ReadBitmapFromFile (filename);
|
||||||
|
int src_x = x >= 0 ? 0 : -x;
|
||||||
|
int src_y = y >= 0 ? 0 : -y;
|
||||||
|
var width = Math.Min (tile.PixelWidth - src_x, output.PixelWidth - x);
|
||||||
|
var height = Math.Min (tile.PixelHeight - src_y, output.PixelHeight - y);
|
||||||
|
var source = new Int32Rect (src_x, src_y, width, height);
|
||||||
|
if (!source.HasArea)
|
||||||
|
return;
|
||||||
|
if (blend && tile.Format == PixelFormats.Bgra32)
|
||||||
|
{
|
||||||
|
BlendBitmap (tile, source, output, x, y);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int dst_stride = output.BackBufferStride;
|
||||||
|
int offset = y * dst_stride + x * 4;
|
||||||
|
var buf_pos = output.BackBuffer + offset;
|
||||||
|
var size = output.PixelHeight * dst_stride - offset;
|
||||||
|
tile.CopyPixels (source, (IntPtr)buf_pos, size, dst_stride);
|
||||||
|
}
|
||||||
|
var target = new Int32Rect (x, y, width, height);
|
||||||
|
output.AddDirtyRect (target);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlendBitmap (BitmapSource bitmap, Int32Rect source, WriteableBitmap output, int x, int y)
|
||||||
|
{
|
||||||
|
int src_stride = source.Width * 4;
|
||||||
|
var pixels = new byte[src_stride * source.Height];
|
||||||
|
bitmap.CopyPixels (source, pixels, src_stride, 0);
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
int dst_stride = output.BackBufferStride;
|
||||||
|
int offset = y * dst_stride + x * 4;
|
||||||
|
byte* buffer = (byte*)(output.BackBuffer + offset);
|
||||||
|
int src = 0;
|
||||||
|
for (int h = 0; h < source.Height; ++h)
|
||||||
|
{
|
||||||
|
int dst = 0;
|
||||||
|
for (int w = 0; w < source.Width; ++w)
|
||||||
|
{
|
||||||
|
byte src_alpha = pixels[src+3];
|
||||||
|
if (src_alpha > 0)
|
||||||
|
{
|
||||||
|
if (0xFF == src_alpha)
|
||||||
|
{
|
||||||
|
buffer[dst ] = pixels[src];
|
||||||
|
buffer[dst+1] = pixels[src+1];
|
||||||
|
buffer[dst+2] = pixels[src+2];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
buffer[dst+0] = (byte)((pixels[src+0] * src_alpha + buffer[dst+0] * (0xFF - src_alpha)) / 0xFF);
|
||||||
|
buffer[dst+1] = (byte)((pixels[src+1] * src_alpha + buffer[dst+1] * (0xFF - src_alpha)) / 0xFF);
|
||||||
|
buffer[dst+2] = (byte)((pixels[src+2] * src_alpha + buffer[dst+2] * (0xFF - src_alpha)) / 0xFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dst += 4;
|
||||||
|
src += 4;
|
||||||
|
}
|
||||||
|
buffer += dst_stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BitmapSource ReadBitmapFromFile (string filename)
|
||||||
|
{
|
||||||
|
using (var input = VFS.OpenBinaryStream (filename))
|
||||||
|
{
|
||||||
|
var image = Read (input);
|
||||||
|
if (null == image)
|
||||||
|
throw new InvalidFormatException ("Invalid IPT tile format.");
|
||||||
|
var bitmap = image.Bitmap;
|
||||||
|
if (bitmap.Format.BitsPerPixel != 32)
|
||||||
|
bitmap = new FormatConvertedBitmap (bitmap, PixelFormats.Bgr32, null, 0);
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write (Stream file, ImageData image)
|
||||||
|
{
|
||||||
|
throw new System.NotImplementedException ("IptFormat.Write not implemented");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
875
Experimental/Artemis/ShiftReduceParserCode.cs
Normal file
875
Experimental/Artemis/ShiftReduceParserCode.cs
Normal file
@ -0,0 +1,875 @@
|
|||||||
|
// Gardens Point Parser Generator
|
||||||
|
// Copyright (c) Wayne Kelly, QUT 2005-2014
|
||||||
|
// (see accompanying GPPGcopyright.rtf)
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
|
namespace QUT.Gppg {
|
||||||
|
/// <summary>
|
||||||
|
/// Abstract class for GPPG shift-reduce parsers.
|
||||||
|
/// Parsers generated by GPPG derive from this base
|
||||||
|
/// class, overriding the abstract Initialize() and
|
||||||
|
/// DoAction() methods.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TValue">Semantic value type</typeparam>
|
||||||
|
/// <typeparam name="TSpan">Location type</typeparam>
|
||||||
|
#if EXPORT_GPPG
|
||||||
|
public abstract class ShiftReduceParser<TValue, TSpan>
|
||||||
|
#else
|
||||||
|
internal abstract class ShiftReduceParser<TValue, TSpan>
|
||||||
|
#endif
|
||||||
|
where TSpan : IMerge<TSpan>, new() {
|
||||||
|
private AbstractScanner<TValue, TSpan> scanner;
|
||||||
|
/// <summary>
|
||||||
|
/// The abstract scanner for this parser.
|
||||||
|
/// </summary>
|
||||||
|
protected AbstractScanner<TValue, TSpan> Scanner {
|
||||||
|
get { return scanner; }
|
||||||
|
set { scanner = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructor for base class
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="scanner">Scanner instance for this parser</param>
|
||||||
|
protected ShiftReduceParser( AbstractScanner<TValue, TSpan> scanner ) {
|
||||||
|
this.scanner = scanner;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==============================================================
|
||||||
|
// TECHNICAL EXPLANATION.
|
||||||
|
// Why the next two fields are not exposed via properties.
|
||||||
|
// ==============================================================
|
||||||
|
// These fields are of the generic parameter types, and are
|
||||||
|
// frequently instantiated as struct types in derived classes.
|
||||||
|
// Semantic actions are defined in the derived classes and refer
|
||||||
|
// to instance fields of these structs. In such cases the code
|
||||||
|
// "get_CurrentSemanticValue().myField = blah;" will fail since
|
||||||
|
// the getter pushes the value of the field, not the reference.
|
||||||
|
// So, in the presence of properties, gppg would need to encode
|
||||||
|
// such field accesses as ...
|
||||||
|
// "tmp = get_CurrentSemanticValue(); // Fetch value
|
||||||
|
// tmp.myField = blah; // update
|
||||||
|
// set_CurrentSemanticValue(tmp); " // Write update back.
|
||||||
|
// There is no issue if TValue is restricted to be a ref type.
|
||||||
|
// The same explanation applies to scanner.yylval.
|
||||||
|
// ==============================================================
|
||||||
|
/// <summary>
|
||||||
|
/// The current value of the "$$" symbolic variable in the parser
|
||||||
|
/// </summary>
|
||||||
|
[SuppressMessage( "Microsoft.Design", "CA1051:DoNotDeclareVisibleInstanceFields" )]
|
||||||
|
protected TValue CurrentSemanticValue;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The current value of the "@$" symbolic variable in the parser
|
||||||
|
/// </summary>
|
||||||
|
[SuppressMessage( "Microsoft.Design", "CA1051:DoNotDeclareVisibleInstanceFields" )]
|
||||||
|
protected TSpan CurrentLocationSpan;
|
||||||
|
protected int NextToken;
|
||||||
|
|
||||||
|
private TSpan LastSpan;
|
||||||
|
private State FsaState;
|
||||||
|
private bool recovering;
|
||||||
|
private int tokensSinceLastError;
|
||||||
|
|
||||||
|
private PushdownPrefixState<State> StateStack = new PushdownPrefixState<State>();
|
||||||
|
private PushdownPrefixState<TValue> valueStack = new PushdownPrefixState<TValue>();
|
||||||
|
private PushdownPrefixState<TSpan> locationStack = new PushdownPrefixState<TSpan>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The stack of semantic value (YYSTYPE) values.
|
||||||
|
/// </summary>
|
||||||
|
protected PushdownPrefixState<TValue> ValueStack { get { return valueStack; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The stack of location value (YYLTYPE) varlues.
|
||||||
|
/// </summary>
|
||||||
|
protected PushdownPrefixState<TSpan> LocationStack { get { return locationStack; } }
|
||||||
|
|
||||||
|
private int errorToken;
|
||||||
|
private int endOfFileToken;
|
||||||
|
private string[] nonTerminals;
|
||||||
|
private State[] states;
|
||||||
|
private Rule[] rules;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialization method to allow derived classes
|
||||||
|
/// to insert the rule list into this base class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="rules">The array of Rule objects</param>
|
||||||
|
protected void InitRules( Rule[] rules ) { this.rules = rules; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialization method to allow derived classes to
|
||||||
|
/// insert the states table into this base class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="states">The pre-initialized states table</param>
|
||||||
|
protected void InitStates( State[] states ) { this.states = states; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// OBSOLETE FOR VERSION 1.4.0
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="size"></param>
|
||||||
|
protected void InitStateTable( int size ) { states = new State[size]; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialization method to allow derived classes
|
||||||
|
/// to insert the special value for the error and EOF tokens.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="err">The error state ordinal</param>
|
||||||
|
/// <param name="end">The EOF stat ordinal</param>
|
||||||
|
protected void InitSpecialTokens( int err, int end ) {
|
||||||
|
errorToken = err;
|
||||||
|
endOfFileToken = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialization method to allow derived classes to
|
||||||
|
/// insert the non-terminal symbol names into this base class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="names">Non-terminal symbol names</param>
|
||||||
|
protected void InitNonTerminals( string[] names ) { nonTerminals = names; }
|
||||||
|
|
||||||
|
#region YYAbort, YYAccept etcetera.
|
||||||
|
[Serializable]
|
||||||
|
[SuppressMessage( "Microsoft.Design", "CA1064:ExceptionsShouldBePublic" )]
|
||||||
|
// Reason for FxCop message suppression -
|
||||||
|
// This exception cannot escape from the local context
|
||||||
|
private class AcceptException : Exception {
|
||||||
|
internal AcceptException() { }
|
||||||
|
protected AcceptException( SerializationInfo i, StreamingContext c ) : base( i, c ) { }
|
||||||
|
}
|
||||||
|
[Serializable]
|
||||||
|
[SuppressMessage( "Microsoft.Design", "CA1064:ExceptionsShouldBePublic" )]
|
||||||
|
// Reason for FxCop message suppression -
|
||||||
|
// This exception cannot escape from the local context
|
||||||
|
private class AbortException : Exception {
|
||||||
|
internal AbortException() { }
|
||||||
|
protected AbortException( SerializationInfo i, StreamingContext c ) : base( i, c ) { }
|
||||||
|
}
|
||||||
|
[Serializable]
|
||||||
|
[SuppressMessage( "Microsoft.Design", "CA1064:ExceptionsShouldBePublic" )]
|
||||||
|
// Reason for FxCop message suppression -
|
||||||
|
// This exception cannot escape from the local context
|
||||||
|
private class ErrorException : Exception {
|
||||||
|
internal ErrorException() { }
|
||||||
|
protected ErrorException( SerializationInfo i, StreamingContext c ) : base( i, c ) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
// The following methods are only called from within
|
||||||
|
// a semantic action. The thrown exceptions can never
|
||||||
|
// propagate outside the ShiftReduceParser class in
|
||||||
|
// which they are nested.
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Force parser to terminate, returning "true"
|
||||||
|
/// </summary>
|
||||||
|
protected static void YYAccept() { throw new AcceptException(); }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Force parser to terminate, returning "false"
|
||||||
|
/// </summary>
|
||||||
|
protected static void YYAbort() { throw new AbortException(); }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Force parser to terminate, returning
|
||||||
|
/// "false" if error recovery fails.
|
||||||
|
/// </summary>
|
||||||
|
protected static void YYError() { throw new ErrorException(); }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check if parser in error recovery state.
|
||||||
|
/// </summary>
|
||||||
|
protected bool YYRecovering { get { return recovering; } }
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Abstract base method. ShiftReduceParser calls this
|
||||||
|
/// to initialize the base class data structures. Concrete
|
||||||
|
/// parser classes must override this method.
|
||||||
|
/// </summary>
|
||||||
|
protected abstract void Initialize();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Main entry point of the Shift-Reduce Parser.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>True if parse succeeds, else false for
|
||||||
|
/// unrecoverable errors</returns>
|
||||||
|
public bool Parse() {
|
||||||
|
Initialize(); // allow derived classes to instantiate rules, states and nonTerminals
|
||||||
|
|
||||||
|
NextToken = 0;
|
||||||
|
FsaState = states[0];
|
||||||
|
|
||||||
|
StateStack.Push( FsaState );
|
||||||
|
valueStack.Push( CurrentSemanticValue );
|
||||||
|
LocationStack.Push( CurrentLocationSpan );
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
#if TRACE_ACTIONS
|
||||||
|
Console.Error.WriteLine("Entering state {0} ", FsaState.number);
|
||||||
|
DisplayStack();
|
||||||
|
#endif
|
||||||
|
int action = FsaState.defaultAction;
|
||||||
|
|
||||||
|
if (FsaState.ParserTable != null) {
|
||||||
|
if (NextToken == 0) {
|
||||||
|
// We save the last token span, so that the location span
|
||||||
|
// of production right hand sides that begin or end with a
|
||||||
|
// nullable production will be correct.
|
||||||
|
LastSpan = scanner.yylloc;
|
||||||
|
NextToken = scanner.yylex();
|
||||||
|
#if TRACE_ACTIONS
|
||||||
|
Console.Error.WriteLine( "Reading: Next token is {0}", TerminalToString( NextToken ) );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#if TRACE_ACTIONS
|
||||||
|
else
|
||||||
|
Console.Error.WriteLine( "Next token is still {0}", TerminalToString( NextToken ) );
|
||||||
|
#endif
|
||||||
|
if (FsaState.ParserTable.ContainsKey( NextToken ))
|
||||||
|
action = FsaState.ParserTable[NextToken];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action > 0) // shift
|
||||||
|
{
|
||||||
|
Shift( action );
|
||||||
|
}
|
||||||
|
else if (action < 0) // reduce
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Reduce( -action );
|
||||||
|
if (action == -1) // accept
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception x) {
|
||||||
|
if (x is AbortException)
|
||||||
|
return false;
|
||||||
|
else if (x is AcceptException)
|
||||||
|
return true;
|
||||||
|
else if (x is ErrorException && !ErrorRecovery())
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
throw; // Rethrow x, preserving information.
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (action == 0) // error
|
||||||
|
if (!ErrorRecovery())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Shift( int stateIndex ) {
|
||||||
|
#if TRACE_ACTIONS
|
||||||
|
Console.Error.Write("Shifting token {0}, ", TerminalToString(NextToken));
|
||||||
|
#endif
|
||||||
|
FsaState = states[stateIndex];
|
||||||
|
|
||||||
|
valueStack.Push( scanner.yylval );
|
||||||
|
StateStack.Push( FsaState );
|
||||||
|
LocationStack.Push( scanner.yylloc );
|
||||||
|
|
||||||
|
if (recovering) {
|
||||||
|
if (NextToken != errorToken)
|
||||||
|
tokensSinceLastError++;
|
||||||
|
|
||||||
|
if (tokensSinceLastError > 5)
|
||||||
|
recovering = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NextToken != endOfFileToken)
|
||||||
|
NextToken = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Reduce( int ruleNumber ) {
|
||||||
|
#if TRACE_ACTIONS
|
||||||
|
DisplayRule(ruleNumber);
|
||||||
|
#endif
|
||||||
|
Rule rule = rules[ruleNumber];
|
||||||
|
int rhLen = rule.RightHandSide.Length;
|
||||||
|
//
|
||||||
|
// Default actions for unit productions.
|
||||||
|
//
|
||||||
|
if (rhLen == 1) {
|
||||||
|
CurrentSemanticValue = valueStack.TopElement(); // Default action: $$ = $1;
|
||||||
|
CurrentLocationSpan = LocationStack.TopElement(); // Default action "@$ = @1;
|
||||||
|
}
|
||||||
|
else if (rhLen == 0) {
|
||||||
|
// Create a new blank value.
|
||||||
|
// Explicit semantic action may mutate this value
|
||||||
|
CurrentSemanticValue = default( TValue );
|
||||||
|
// The location span for an empty production will start with the
|
||||||
|
// beginning of the next lexeme, and end with the finish of the
|
||||||
|
// previous lexeme. This gives the correct behaviour when this
|
||||||
|
// nonsense value is used in later Merge operations.
|
||||||
|
CurrentLocationSpan = (scanner.yylloc != null && LastSpan != null ?
|
||||||
|
scanner.yylloc.Merge( LastSpan ) :
|
||||||
|
default( TSpan ));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Default action: $$ = $1;
|
||||||
|
CurrentSemanticValue = valueStack[LocationStack.Depth - rhLen];
|
||||||
|
// Default action "@$ = @1.Merge(@N)" for location info.
|
||||||
|
TSpan at1 = LocationStack[LocationStack.Depth - rhLen];
|
||||||
|
TSpan atN = LocationStack[LocationStack.Depth - 1];
|
||||||
|
CurrentLocationSpan =
|
||||||
|
((at1 != null && atN != null) ? at1.Merge( atN ) : default( TSpan ));
|
||||||
|
}
|
||||||
|
|
||||||
|
DoAction( ruleNumber );
|
||||||
|
|
||||||
|
for (int i = 0; i < rule.RightHandSide.Length; i++) {
|
||||||
|
StateStack.Pop();
|
||||||
|
valueStack.Pop();
|
||||||
|
LocationStack.Pop();
|
||||||
|
}
|
||||||
|
FsaState = StateStack.TopElement();
|
||||||
|
|
||||||
|
if (FsaState.Goto.ContainsKey( rule.LeftHandSide ))
|
||||||
|
FsaState = states[FsaState.Goto[rule.LeftHandSide]];
|
||||||
|
|
||||||
|
StateStack.Push( FsaState );
|
||||||
|
valueStack.Push( CurrentSemanticValue );
|
||||||
|
LocationStack.Push( CurrentLocationSpan );
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Execute the selected action from array.
|
||||||
|
/// Must be overriden in derived classes.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="actionNumber">Index of the action to perform</param>
|
||||||
|
protected abstract void DoAction( int actionNumber );
|
||||||
|
|
||||||
|
private bool ErrorRecovery() {
|
||||||
|
bool discard;
|
||||||
|
|
||||||
|
if (!recovering) // if not recovering from previous error
|
||||||
|
ReportError();
|
||||||
|
|
||||||
|
if (!FindErrorRecoveryState())
|
||||||
|
return false;
|
||||||
|
//
|
||||||
|
// The interim fix for the "looping in error recovery"
|
||||||
|
// artifact involved moving the setting of the recovering
|
||||||
|
// bool until after invalid tokens have been discarded.
|
||||||
|
//
|
||||||
|
ShiftErrorToken();
|
||||||
|
discard = DiscardInvalidTokens();
|
||||||
|
recovering = true;
|
||||||
|
tokensSinceLastError = 0;
|
||||||
|
return discard;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ReportError() {
|
||||||
|
StringBuilder errorMsg = new StringBuilder();
|
||||||
|
errorMsg.AppendFormat( "Syntax error, unexpected {0}", TerminalToString( NextToken ) );
|
||||||
|
|
||||||
|
if (FsaState.ParserTable.Count < 7) {
|
||||||
|
bool first = true;
|
||||||
|
foreach (int terminal in FsaState.ParserTable.Keys) {
|
||||||
|
if (first)
|
||||||
|
errorMsg.Append( ", expecting " );
|
||||||
|
else
|
||||||
|
errorMsg.Append( ", or " );
|
||||||
|
|
||||||
|
errorMsg.Append( TerminalToString( terminal ) );
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
scanner.yyerror( errorMsg.ToString() );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShiftErrorToken() {
|
||||||
|
int old_next = NextToken;
|
||||||
|
NextToken = errorToken;
|
||||||
|
|
||||||
|
Shift( FsaState.ParserTable[NextToken] );
|
||||||
|
|
||||||
|
#if TRACE_ACTIONS
|
||||||
|
Console.Error.WriteLine("Entering state {0} ", FsaState.number);
|
||||||
|
#endif
|
||||||
|
NextToken = old_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool FindErrorRecoveryState() {
|
||||||
|
while (true) // pop states until one found that accepts error token
|
||||||
|
{
|
||||||
|
if (FsaState.ParserTable != null &&
|
||||||
|
FsaState.ParserTable.ContainsKey( errorToken ) &&
|
||||||
|
FsaState.ParserTable[errorToken] > 0) // shift
|
||||||
|
return true;
|
||||||
|
|
||||||
|
#if TRACE_ACTIONS
|
||||||
|
Console.Error.WriteLine("Error: popping state {0}", StateStack.TopElement().number);
|
||||||
|
#endif
|
||||||
|
StateStack.Pop();
|
||||||
|
valueStack.Pop();
|
||||||
|
LocationStack.Pop();
|
||||||
|
|
||||||
|
#if TRACE_ACTIONS
|
||||||
|
DisplayStack();
|
||||||
|
#endif
|
||||||
|
if (StateStack.IsEmpty()) {
|
||||||
|
#if TRACE_ACTIONS
|
||||||
|
Console.Error.WriteLine("Aborting: didn't find a state that accepts error token");
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
FsaState = StateStack.TopElement();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool DiscardInvalidTokens() {
|
||||||
|
|
||||||
|
int action = FsaState.defaultAction;
|
||||||
|
|
||||||
|
if (FsaState.ParserTable != null) {
|
||||||
|
// Discard tokens until find one that works ...
|
||||||
|
while (true) {
|
||||||
|
if (NextToken == 0) {
|
||||||
|
#if TRACE_ACTIONS
|
||||||
|
Console.Error.Write("Reading a token: ");
|
||||||
|
#endif
|
||||||
|
NextToken = scanner.yylex();
|
||||||
|
}
|
||||||
|
#if TRACE_ACTIONS
|
||||||
|
Console.Error.WriteLine("Next token is {0}", TerminalToString(NextToken));
|
||||||
|
#endif
|
||||||
|
if (NextToken == endOfFileToken)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (FsaState.ParserTable.ContainsKey( NextToken ))
|
||||||
|
action = FsaState.ParserTable[NextToken];
|
||||||
|
|
||||||
|
if (action != 0)
|
||||||
|
return true;
|
||||||
|
else {
|
||||||
|
#if TRACE_ACTIONS
|
||||||
|
Console.Error.WriteLine("Error: Discarding {0}", TerminalToString(NextToken));
|
||||||
|
#endif
|
||||||
|
NextToken = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (recovering && tokensSinceLastError == 0) {
|
||||||
|
//
|
||||||
|
// Boolean recovering is not set until after the first
|
||||||
|
// error token has been shifted. Thus if we get back
|
||||||
|
// here with recovering set and no tokens read we are
|
||||||
|
// looping on the same error recovery action. This
|
||||||
|
// happens if current_state.ParserTable is null because
|
||||||
|
// the state has an LR(0) reduction, but not all
|
||||||
|
// lookahead tokens are valid. This only occurs for
|
||||||
|
// error productions that *end* on "error".
|
||||||
|
//
|
||||||
|
// This action discards tokens one at a time until
|
||||||
|
// the looping stops. Another attack would be to always
|
||||||
|
// use the LALR(1) table if a production ends on "error"
|
||||||
|
//
|
||||||
|
#if TRACE_ACTIONS
|
||||||
|
Console.Error.WriteLine("Error: panic discard of {0}", TerminalToString(NextToken));
|
||||||
|
#endif
|
||||||
|
if (NextToken == endOfFileToken)
|
||||||
|
return false;
|
||||||
|
NextToken = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Traditional YACC method. Discards the next input token.
|
||||||
|
/// </summary>
|
||||||
|
[SuppressMessage( "Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yyclearin" )]
|
||||||
|
[SuppressMessage( "Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yyclearin" )]
|
||||||
|
// Reason for FxCop message suppression -
|
||||||
|
// This is a traditional name for YACC-like functionality
|
||||||
|
protected void yyclearin() { NextToken = 0; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tradional YACC method. Clear the "recovering" flag.
|
||||||
|
/// </summary>
|
||||||
|
[SuppressMessage( "Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yyerrok" )]
|
||||||
|
[SuppressMessage( "Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yyerrok" )]
|
||||||
|
// Reason for FxCop message suppression -
|
||||||
|
// This is a traditional name for YACC-like functionality
|
||||||
|
protected void yyerrok() { recovering = false; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// OBSOLETE FOR VERSION 1.4.0
|
||||||
|
/// Method used by derived types to insert new
|
||||||
|
/// state instances in the "states" array.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stateNumber">index of the state</param>
|
||||||
|
/// <param name="state">data for the state</param>
|
||||||
|
protected void AddState( int stateNumber, State state ) {
|
||||||
|
states[stateNumber] = state;
|
||||||
|
state.number = stateNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DisplayStack() {
|
||||||
|
Console.Error.Write( "State stack is now:" );
|
||||||
|
for (int i = 0; i < StateStack.Depth; i++)
|
||||||
|
Console.Error.Write( " {0}", StateStack[i].number );
|
||||||
|
Console.Error.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DisplayRule( int ruleNumber ) {
|
||||||
|
Console.Error.Write( "Reducing stack by rule {0}, ", ruleNumber );
|
||||||
|
DisplayProduction( rules[ruleNumber] );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DisplayProduction( Rule rule ) {
|
||||||
|
if (rule.RightHandSide.Length == 0)
|
||||||
|
Console.Error.Write( "/* empty */ " );
|
||||||
|
else
|
||||||
|
foreach (int symbol in rule.RightHandSide)
|
||||||
|
Console.Error.Write( "{0} ", SymbolToString( symbol ) );
|
||||||
|
|
||||||
|
Console.Error.WriteLine( "-> {0}", SymbolToString( rule.LeftHandSide ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Abstract state class naming terminal symbols.
|
||||||
|
/// This is overridden by derived classes with the
|
||||||
|
/// name (or alias) to be used in error messages.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="terminal">The terminal ordinal</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
protected abstract string TerminalToString( int terminal );
|
||||||
|
|
||||||
|
private string SymbolToString( int symbol ) {
|
||||||
|
if (symbol < 0)
|
||||||
|
return nonTerminals[-symbol - 1];
|
||||||
|
else
|
||||||
|
return TerminalToString( symbol );
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Return text representation of argument character
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input">The character to convert</param>
|
||||||
|
/// <returns>String representation of the character</returns>
|
||||||
|
protected static string CharToString( char input ) {
|
||||||
|
switch (input) {
|
||||||
|
case '\a': return @"'\a'";
|
||||||
|
case '\b': return @"'\b'";
|
||||||
|
case '\f': return @"'\f'";
|
||||||
|
case '\n': return @"'\n'";
|
||||||
|
case '\r': return @"'\r'";
|
||||||
|
case '\t': return @"'\t'";
|
||||||
|
case '\v': return @"'\v'";
|
||||||
|
case '\0': return @"'\0'";
|
||||||
|
default: return string.Format( CultureInfo.InvariantCulture, "'{0}'", input );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Classes implementing this interface must supply a
|
||||||
|
/// method that merges two location objects to return
|
||||||
|
/// a new object of the same type.
|
||||||
|
/// GPPG-generated parsers have the default location
|
||||||
|
/// action equivalent to "@$ = @1.Merge(@N);" where N
|
||||||
|
/// is the right-hand-side length of the production.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TSpan">The Location type</typeparam>
|
||||||
|
#if EXPORT_GPPG
|
||||||
|
public interface IMerge<TSpan>
|
||||||
|
#else
|
||||||
|
internal interface IMerge<TSpan>
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interface method that creates a location object from
|
||||||
|
/// the current and last object. Typically used to create
|
||||||
|
/// a location object extending from the start of the @1
|
||||||
|
/// object to the end of the @N object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="last">The lexically last object to merge</param>
|
||||||
|
/// <returns>The merged location object</returns>
|
||||||
|
TSpan Merge( TSpan last );
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This is the default class that carries location
|
||||||
|
/// information from the scanner to the parser.
|
||||||
|
/// If you don't declare "%YYLTYPE Foo" the parser
|
||||||
|
/// will expect to deal with this type.
|
||||||
|
/// </summary>
|
||||||
|
#if EXPORT_GPPG
|
||||||
|
public class LexLocation : IMerge<LexLocation>
|
||||||
|
#else
|
||||||
|
[SuppressMessage( "Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses" )]
|
||||||
|
internal class LexLocation : IMerge<LexLocation>
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
private int startLine; // start line
|
||||||
|
private int startColumn; // start column
|
||||||
|
private int endLine; // end line
|
||||||
|
private int endColumn; // end column
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The line at which the text span starts.
|
||||||
|
/// </summary>
|
||||||
|
public int StartLine { get { return startLine; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The column at which the text span starts.
|
||||||
|
/// </summary>
|
||||||
|
public int StartColumn { get { return startColumn; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The line on which the text span ends.
|
||||||
|
/// </summary>
|
||||||
|
public int EndLine { get { return endLine; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The column of the first character
|
||||||
|
/// beyond the end of the text span.
|
||||||
|
/// </summary>
|
||||||
|
public int EndColumn { get { return endColumn; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Default no-arg constructor.
|
||||||
|
/// </summary>
|
||||||
|
public LexLocation() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructor for text-span with given start and end.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sl">start line</param>
|
||||||
|
/// <param name="sc">start column</param>
|
||||||
|
/// <param name="el">end line </param>
|
||||||
|
/// <param name="ec">end column</param>
|
||||||
|
public LexLocation( int sl, int sc, int el, int ec ) { startLine = sl; startColumn = sc; endLine = el; endColumn = ec; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a text location which spans from the
|
||||||
|
/// start of "this" to the end of the argument "last"
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="last">The last location in the result span</param>
|
||||||
|
/// <returns>The merged span</returns>
|
||||||
|
public LexLocation Merge( LexLocation last ) { return new LexLocation( this.startLine, this.startColumn, last.endLine, last.endColumn ); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Abstract scanner class that GPPG expects its scanners to
|
||||||
|
/// extend.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TValue">Semantic value type YYSTYPE</typeparam>
|
||||||
|
/// <typeparam name="TSpan">Source location type YYLTYPE</typeparam>
|
||||||
|
#if EXPORT_GPPG
|
||||||
|
public abstract class AbstractScanner<TValue, TSpan>
|
||||||
|
#else
|
||||||
|
internal abstract class AbstractScanner<TValue, TSpan>
|
||||||
|
#endif
|
||||||
|
where TSpan : IMerge<TSpan> {
|
||||||
|
/// <summary>
|
||||||
|
/// Lexical value optionally set by the scanner. The value
|
||||||
|
/// is of the %YYSTYPE type declared in the parser spec.
|
||||||
|
/// </summary>
|
||||||
|
[SuppressMessage( "Microsoft.Design", "CA1051:DoNotDeclareVisibleInstanceFields" )]
|
||||||
|
[SuppressMessage( "Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yylval" )]
|
||||||
|
[SuppressMessage( "Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yylval" )]
|
||||||
|
// Reason for FxCop message suppression -
|
||||||
|
// This is a traditional name for YACC-like functionality
|
||||||
|
// A field must be declared for this value of parametric type,
|
||||||
|
// since it may be instantiated by a value struct. If it were
|
||||||
|
// implemented as a property, machine generated code in derived
|
||||||
|
// types would not be able to select on the returned value.
|
||||||
|
#pragma warning disable 649
|
||||||
|
public TValue yylval; // Lexical value: set by scanner
|
||||||
|
#pragma warning restore 649
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Current scanner location property. The value is of the
|
||||||
|
/// type declared by %YYLTYPE in the parser specification.
|
||||||
|
/// </summary>
|
||||||
|
[SuppressMessage( "Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yylloc" )]
|
||||||
|
[SuppressMessage( "Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yylloc" )]
|
||||||
|
// Reason for FxCop message suppression -
|
||||||
|
// This is a traditional name for YACC-like functionality
|
||||||
|
public virtual TSpan yylloc {
|
||||||
|
get { return default( TSpan ); } // Empty implementation allowing
|
||||||
|
set { /* skip */ } // yylloc to be ignored entirely.
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Main call point for LEX-like scanners. Returns an int
|
||||||
|
/// corresponding to the token recognized by the scanner.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>An int corresponding to the token</returns>
|
||||||
|
[SuppressMessage( "Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yylex" )]
|
||||||
|
[SuppressMessage( "Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yylex" )]
|
||||||
|
// Reason for FxCop message suppression -
|
||||||
|
// This is a traditional name for YACC-like functionality
|
||||||
|
public abstract int yylex();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Traditional error reporting provided by LEX-like scanners
|
||||||
|
/// to their YACC-like clients.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="format">Message format string</param>
|
||||||
|
/// <param name="args">Optional array of args</param>
|
||||||
|
[SuppressMessage( "Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yyerror" )]
|
||||||
|
[SuppressMessage( "Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yyerror" )]
|
||||||
|
// Reason for FxCop message suppression -
|
||||||
|
// This is a traditional name for YACC-like functionality
|
||||||
|
public virtual void yyerror( string format, params object[] args ) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Encapsulated state for the parser.
|
||||||
|
/// Opaque to users, visible to the tool-generated code.
|
||||||
|
/// </summary>
|
||||||
|
#if EXPORT_GPPG
|
||||||
|
public class State
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The number of states in the automaton.
|
||||||
|
/// </summary>
|
||||||
|
public int number;
|
||||||
|
#else
|
||||||
|
internal class State {
|
||||||
|
/// <summary>
|
||||||
|
/// The index of this state in the states array.
|
||||||
|
/// </summary>
|
||||||
|
internal int number;
|
||||||
|
#endif
|
||||||
|
internal Dictionary<int, int> ParserTable; // Terminal -> ParseAction
|
||||||
|
internal Dictionary<int, int> Goto; // NonTerminal -> State;
|
||||||
|
internal int defaultAction; // = 0; // ParseAction
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// State transition data for this state. Pairs of elements of the
|
||||||
|
/// goto array associate symbol ordinals with next state indices.
|
||||||
|
/// The actions array is passed to another constructor.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="actions">The action list</param>c
|
||||||
|
/// <param name="goToList">Next state data</param>
|
||||||
|
public State( int[] actions, int[] goToList )
|
||||||
|
: this( actions ) {
|
||||||
|
Goto = new Dictionary<int, int>();
|
||||||
|
for (int i = 0; i < goToList.Length; i += 2)
|
||||||
|
Goto.Add( goToList[i], goToList[i + 1] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Action data for this state. Pairs of elements of the
|
||||||
|
/// action array associate action ordinals with each of
|
||||||
|
/// those symbols that have actions in the current state.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="actions">The action array</param>
|
||||||
|
public State( int[] actions ) {
|
||||||
|
ParserTable = new Dictionary<int, int>();
|
||||||
|
for (int i = 0; i < actions.Length; i += 2)
|
||||||
|
ParserTable.Add( actions[i], actions[i + 1] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set the default action for this state.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="defaultAction">Ordinal of the default action</param>
|
||||||
|
public State( int defaultAction ) {
|
||||||
|
this.defaultAction = defaultAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set the default action and the state transition table.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="defaultAction">The default action</param>
|
||||||
|
/// <param name="goToList">Transitions from this state</param>
|
||||||
|
public State( int defaultAction, int[] goToList )
|
||||||
|
: this( defaultAction ) {
|
||||||
|
Goto = new Dictionary<int, int>();
|
||||||
|
for (int i = 0; i < goToList.Length; i += 2)
|
||||||
|
Goto.Add( goToList[i], goToList[i + 1] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rule representation at runtime.
|
||||||
|
/// </summary>
|
||||||
|
#if EXPORT_GPPG
|
||||||
|
public class Rule
|
||||||
|
#else
|
||||||
|
internal class Rule
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
internal int LeftHandSide; // symbol
|
||||||
|
internal int[] RightHandSide; // symbols
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rule constructor. This holds the ordinal of
|
||||||
|
/// the left hand side symbol, and the list of
|
||||||
|
/// right hand side symbols, in lexical order.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="left">The LHS non-terminal</param>
|
||||||
|
/// <param name="right">The RHS symbols, in lexical order</param>
|
||||||
|
public Rule( int left, int[] right ) {
|
||||||
|
this.LeftHandSide = left;
|
||||||
|
this.RightHandSide = right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stack utility for the shift-reduce parser.
|
||||||
|
/// GPPG parsers have three instances:
|
||||||
|
/// (1) The parser state stack, T = QUT.Gppg.State,
|
||||||
|
/// (2) The semantic value stack, T = TValue,
|
||||||
|
/// (3) The location stack, T = TSpan.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
#if EXPORT_GPPG
|
||||||
|
public class PushdownPrefixState<T>
|
||||||
|
#else
|
||||||
|
internal class PushdownPrefixState<T>
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
// Note that we cannot use the BCL Stack<T> class
|
||||||
|
// here as derived types need to index into stacks.
|
||||||
|
//
|
||||||
|
private T[] array = new T[8];
|
||||||
|
private int tos = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indexer for values of the stack below the top.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="index">index of the element, starting from the bottom</param>
|
||||||
|
/// <returns>the selected element</returns>
|
||||||
|
public T this[int index] { get { return array[index]; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The current depth of the stack.
|
||||||
|
/// </summary>
|
||||||
|
public int Depth { get { return tos; } }
|
||||||
|
|
||||||
|
internal void Push( T value ) {
|
||||||
|
if (tos >= array.Length) {
|
||||||
|
T[] newarray = new T[array.Length * 2];
|
||||||
|
System.Array.Copy( array, newarray, tos );
|
||||||
|
array = newarray;
|
||||||
|
}
|
||||||
|
array[tos++] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal T Pop() {
|
||||||
|
T rslt = array[--tos];
|
||||||
|
array[tos] = default( T );
|
||||||
|
return rslt;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal T TopElement() { return array[tos - 1]; }
|
||||||
|
|
||||||
|
internal bool IsEmpty() { return tos == 0; }
|
||||||
|
}
|
||||||
|
}
|
@ -78,13 +78,16 @@
|
|||||||
<Reference Include="WindowsBase" />
|
<Reference Include="WindowsBase" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="Artemis\ImageIPT.cs" />
|
||||||
<Compile Include="Cabinet\ArcCAB.cs" />
|
<Compile Include="Cabinet\ArcCAB.cs" />
|
||||||
<Compile Include="CellWorks\ArcDB.cs" />
|
<Compile Include="CellWorks\ArcDB.cs" />
|
||||||
|
<Compile Include="Artemis\GplexBuffers.cs" />
|
||||||
<Compile Include="Opus\AudioOPUS.cs" />
|
<Compile Include="Opus\AudioOPUS.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="RPGMaker\ArcRGSS.cs" />
|
<Compile Include="RPGMaker\ArcRGSS.cs" />
|
||||||
<Compile Include="RPGMaker\AudioRPGMV.cs" />
|
<Compile Include="RPGMaker\AudioRPGMV.cs" />
|
||||||
<Compile Include="RPGMaker\ImageRPGMV.cs" />
|
<Compile Include="RPGMaker\ImageRPGMV.cs" />
|
||||||
|
<Compile Include="Artemis\ShiftReduceParserCode.cs" />
|
||||||
<Compile Include="WebP\ImageWEBP.cs" />
|
<Compile Include="WebP\ImageWEBP.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@ -109,11 +112,47 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="Key\" />
|
<Folder Include="Key\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup Label="IPTFiles">
|
||||||
|
<Compile Include="Artemis\IPT.Parser.cs">
|
||||||
|
<DependentUpon>IPT.parser</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Artemis\IPT.Parser.Generated.cs">
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DesignTime>True</DesignTime>
|
||||||
|
<DependentUpon>IPT.Language.grammar.y</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Artemis\IPT.Scanner.cs">
|
||||||
|
<DependentUpon>IPT.parser</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Artemis\IPT.Scanner.Generated.cs">
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DesignTime>True</DesignTime>
|
||||||
|
<DependentUpon>IPT.Language.analyzer.lex</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<None Include="Artemis\IPT.Language.analyzer.lex">
|
||||||
|
<DependentUpon>IPT.parser</DependentUpon>
|
||||||
|
</None>
|
||||||
|
<None Include="Artemis\IPT.Language.grammar.y">
|
||||||
|
<DependentUpon>IPT.parser</DependentUpon>
|
||||||
|
</None>
|
||||||
|
<None Include="Artemis\IPT.parser" />
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="YltParsers">
|
||||||
|
<Names>ipt</Names>
|
||||||
|
</PropertyGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<PreBuildEvent>perl "$(SolutionDir)inc-revision.pl" "$(ProjectPath)" $(ConfigurationName)
|
<PreBuildEvent>perl "$(SolutionDir)inc-revision.pl" "$(ProjectPath)" $(ConfigurationName)
|
||||||
exit 0</PreBuildEvent>
|
exit 0</PreBuildEvent>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Label="YltProperties">
|
||||||
|
<YltTools>$(SolutionDir)packages\YaccLexTools.0.2.2\tools\</YltTools>
|
||||||
|
<GplexTool>"$(YltTools)gplex.exe"</GplexTool>
|
||||||
|
<GppgTool>"$(YltTools)gppg.exe"</GppgTool>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Label="GenerateIPTProperties">
|
||||||
|
<IPTParser>$(ProjectDir)Artemis\IPT</IPTParser>
|
||||||
|
</PropertyGroup>
|
||||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||||
@ -123,6 +162,18 @@ exit 0</PreBuildEvent>
|
|||||||
</Target>
|
</Target>
|
||||||
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
|
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
|
||||||
<Import Project="..\packages\System.Data.SQLite.Core.1.0.109.2\build\net46\System.Data.SQLite.Core.targets" Condition="Exists('..\packages\System.Data.SQLite.Core.1.0.109.2\build\net46\System.Data.SQLite.Core.targets')" />
|
<Import Project="..\packages\System.Data.SQLite.Core.1.0.109.2\build\net46\System.Data.SQLite.Core.targets" Condition="Exists('..\packages\System.Data.SQLite.Core.1.0.109.2\build\net46\System.Data.SQLite.Core.targets')" />
|
||||||
|
<Target Name="BeforeBuild" DependsOnTargets="YltBuildGen" />
|
||||||
|
<Target Name="YltBuildGen" DependsOnTargets="GenerateIPT" />
|
||||||
|
<Target Name="GenerateIPT" Inputs="$(IPTParser).Language.analyzer.lex;$(IPTParser).Language.grammar.y" Outputs="$(IPTParser).Scanner.Generated.cs;$(IPTParser).Parser.Generated.cs">
|
||||||
|
<Message Text="Generating scanner for $(IPTParser) ..." />
|
||||||
|
<Exec Command="$(GplexTool) /codePage:UTF-8 "/out:$(IPTParser).Scanner.Generated.cs" "$(IPTParser).Language.analyzer.lex"" WorkingDirectory="$(ProjectDir)Artemis" Outputs="$(GenDir)Scanner.cs">
|
||||||
|
<Output TaskParameter="Outputs" ItemName="IPTScanner" />
|
||||||
|
</Exec>
|
||||||
|
<Message Text="Generating parser for $(IPTParser) ..." />
|
||||||
|
<Exec Command="$(GppgTool) /no-lines /gplex "$(IPTParser).Language.grammar.y" > "$(IPTParser).Parser.Generated.cs"" WorkingDirectory="$(ProjectDir)" Outputs="$(IPTParser).Parser.Generated.cs">
|
||||||
|
<Output TaskParameter="Outputs" ItemName="IPT" />
|
||||||
|
</Exec>
|
||||||
|
</Target>
|
||||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
Other similar extension points exist, see Microsoft.Common.targets.
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
<Target Name="BeforeBuild">
|
<Target Name="BeforeBuild">
|
||||||
|
@ -6,4 +6,5 @@
|
|||||||
<package id="MSFTCompressionCab" version="1.0.0" targetFramework="net46" />
|
<package id="MSFTCompressionCab" version="1.0.0" targetFramework="net46" />
|
||||||
<package id="NETStandard.Library" version="2.0.1" targetFramework="net46" />
|
<package id="NETStandard.Library" version="2.0.1" targetFramework="net46" />
|
||||||
<package id="System.Data.SQLite.Core" version="1.0.109.2" targetFramework="net46" />
|
<package id="System.Data.SQLite.Core" version="1.0.109.2" targetFramework="net46" />
|
||||||
|
<package id="YaccLexTools" version="0.2.2" targetFramework="net46" />
|
||||||
</packages>
|
</packages>
|
Loading…
Reference in New Issue
Block a user