diff --git a/cparser/cparser.vcxproj b/cparser/cparser.vcxproj
index ef6081a..e159195 100644
--- a/cparser/cparser.vcxproj
+++ b/cparser/cparser.vcxproj
@@ -16,7 +16,11 @@
+
+
+
+
{B0411C78-2F06-49E0-8DE9-5C52A466F5DE}
diff --git a/cparser/cparser.vcxproj.filters b/cparser/cparser.vcxproj.filters
index e9b2014..7602985 100644
--- a/cparser/cparser.vcxproj.filters
+++ b/cparser/cparser.vcxproj.filters
@@ -29,5 +29,17 @@
Header Files
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
\ No newline at end of file
diff --git a/cparser/main.cpp b/cparser/main.cpp
index 783deec..7b20f1b 100644
--- a/cparser/main.cpp
+++ b/cparser/main.cpp
@@ -3,127 +3,158 @@
#include
#include
#include
+#include
#include "filehelper.h"
#include "stringutils.h"
+#include "testfiles.h"
using namespace std;
-string Input;
-string ConsumedInput;
-size_t Index = 0;
-string Error;
-
-string IdentifierStr = "";
-uint64_t NumberVal = 0;
-
-int LastChar = ' ';
-
-enum Token
+struct Lexer
{
- //status tokens
- tok_eof = -10000,
- tok_error,
-
- //keywords
- tok_typedef, //"typedef"
- tok_struct, //"struct"
- tok_char, //"char"
- tok_unsigned, //"unsigned"
- tok_int, //"int"
- tok_sizeof, //"sizeof"
- tok_WORD, //"WORD"
- tok_DWORD, //"DWORD"
-
- //others
- tok_identifier, //[a-zA-Z][a-zA-Z0-9]
- tok_number //(0x[0-9a-fA-F]+)|([0-9]+)
-};
-
-unordered_map KeywordMap;
-
-void setup()
-{
- KeywordMap["typedef"] = tok_typedef;
- KeywordMap["struct"] = tok_struct;
- KeywordMap["char"] = tok_char;
- KeywordMap["unsigned"] = tok_unsigned;
- KeywordMap["int"] = tok_int;
- KeywordMap["sizeof"] = tok_sizeof;
- KeywordMap["WORD"] = tok_WORD;
- KeywordMap["DWORD"] = tok_DWORD;
-}
-
-Token ReportError(const String & error)
-{
- Error = error;
- return tok_error;
-}
-
-String tokString(int tok)
-{
- switch (Token(tok))
+ explicit Lexer()
{
- case tok_eof: return "tok_eof";
- case tok_error: return StringUtils::sprintf("tok_error \"%s\"", Error.c_str());
- case tok_identifier: return StringUtils::sprintf("tok_identifier \"%s\"", IdentifierStr.c_str());
- case tok_number: return StringUtils::sprintf("tok_number %llu (0x%llX)", NumberVal, NumberVal);
- default:
- for (const auto & itr : KeywordMap)
- {
- if (tok == itr.second)
- return "tok_" + itr.first;
- }
- if (tok > 0 && tok < 265)
- {
- String s;
- s = tok;
- return s;
- }
- return "";
+ SetupKeywordMap();
}
-}
-int readChar()
-{
- if (Index == Input.length())
- return EOF;
- ConsumedInput += Input[Index];
- return uint8_t(Input[Index++]); //do not sign-extend to support UTF-8
-}
+ string Input;
+ string ConsumedInput;
+ size_t Index = 0;
+ string Error;
-int getToken()
-{
- //skip whitespace
- while (isspace(LastChar))
- LastChar = readChar();
+ string IdentifierStr = "";
+ uint64_t NumberVal = 0;
- //identifier/keyword
- if (isalpha(LastChar)) //[a-zA-Z]
+ int LastChar = ' ';
+
+ enum Token
{
- IdentifierStr = LastChar;
- while (isalnum(LastChar = readChar())) //[0-9a-zA-Z]
- IdentifierStr += LastChar;
+ //status tokens
+ tok_eof = -10000,
+ tok_error,
//keywords
- auto found = KeywordMap.find(IdentifierStr);
- if (found != KeywordMap.end())
- return found->second;
+ tok_typedef, //"typedef"
+ tok_struct, //"struct"
+ tok_char, //"char"
+ tok_unsigned, //"unsigned"
+ tok_int, //"int"
+ tok_sizeof, //"sizeof"
+ tok_BYTE, //"BYTE"
+ tok_WORD, //"WORD"
+ tok_DWORD, //"DWORD"
+ tok_ushort, //"ushort"
+ tok_uint, //"uint"
+ tok_byte, //"byte"
+ tok_double, //"double"
+ tok_string, //"string"
+ tok_return, //"return"
+ tok_enum, //"enum"
- return tok_identifier;
+ //others
+ tok_identifier, //[a-zA-Z_][a-zA-Z0-9_]
+ tok_number //(0x[0-9a-fA-F]+)|([0-9]+)
+ };
+
+ unordered_map KeywordMap;
+
+ void SetupKeywordMap()
+ {
+ KeywordMap["typedef"] = tok_typedef;
+ KeywordMap["struct"] = tok_struct;
+ KeywordMap["char"] = tok_char;
+ KeywordMap["unsigned"] = tok_unsigned;
+ KeywordMap["int"] = tok_int;
+ KeywordMap["sizeof"] = tok_sizeof;
+ KeywordMap["BYTE"] = tok_BYTE;
+ KeywordMap["WORD"] = tok_WORD;
+ KeywordMap["DWORD"] = tok_DWORD;
+ KeywordMap["byte"] = tok_byte;
+ KeywordMap["ushort"] = tok_ushort;
+ KeywordMap["uint"] = tok_uint;
+ KeywordMap["double"] = tok_double;
+ KeywordMap["string"] = tok_string;
+ KeywordMap["return"] = tok_return;
+ KeywordMap["enum"] = tok_enum;
}
- //(hex) numbers
- if (isdigit(LastChar)) //[0-9]
+ Token ReportError(const String & error)
{
- string NumStr;
- NumStr = LastChar;
- LastChar = readChar(); //this might not be a digit
+ Error = error;
+ return tok_error;
+ }
- //hexadecimal numbers
- if (NumStr[0] == '0' && LastChar == 'x') //0x
+ String TokString(int tok)
+ {
+ switch (Token(tok))
{
- NumStr = "";
- while (isxdigit(LastChar = readChar())) //[0-9a-fA-F]*
+ case tok_eof: return "tok_eof";
+ case tok_error: return StringUtils::sprintf("tok_error \"%s\"", Error.c_str());
+ case tok_identifier: return StringUtils::sprintf("tok_identifier \"%s\"", IdentifierStr.c_str());
+ case tok_number: return StringUtils::sprintf("tok_number %llu (0x%llX)", NumberVal, NumberVal);
+ default:
+ for (const auto & itr : KeywordMap)
+ {
+ if (tok == itr.second)
+ return "tok_" + itr.first;
+ }
+ if (tok > 0 && tok < 265)
+ {
+ String s;
+ s = tok;
+ return s;
+ }
+ return "";
+ }
+ }
+
+ int PeekChar(int distance = 0)
+ {
+ if (Index + distance >= Input.length())
+ return EOF;
+ return Input[Index + distance];
+ }
+
+ int ReadChar()
+ {
+ if (Index == Input.length())
+ return EOF;
+ ConsumedInput += Input[Index];
+ return uint8_t(Input[Index++]); //do not sign-extend to support UTF-8
+ }
+
+ int GetToken()
+ {
+ //skip whitespace
+ while (isspace(LastChar))
+ LastChar = ReadChar();
+
+ //identifier/keyword
+ if (isalpha(LastChar) || LastChar == '_') //[a-zA-Z_]
+ {
+ IdentifierStr = LastChar;
+ LastChar = ReadChar();
+ while (isalnum(LastChar) || LastChar == '_') //[0-9a-zA-Z_]
+ {
+ IdentifierStr += LastChar;
+ LastChar = ReadChar();
+ }
+
+ //keywords
+ auto found = KeywordMap.find(IdentifierStr);
+ if (found != KeywordMap.end())
+ return found->second;
+
+ return tok_identifier;
+ }
+
+ //hex numbers
+ if (LastChar == '0' && PeekChar() == 'x') //0x
+ {
+ string NumStr;
+ ReadChar(); //consume the 'x'
+
+ while (isxdigit(LastChar = ReadChar())) //[0-9a-fA-F]*
NumStr += LastChar;
if (!NumStr.length()) //check for error condition
@@ -133,78 +164,118 @@ int getToken()
return ReportError("sscanf_s failed on hexadecimal number");
return tok_number;
}
-
- //decimal numbers
- while (isdigit(LastChar)) //[0-9]*
+ if (isdigit(LastChar)) //[0-9]
{
- NumStr += LastChar;
- LastChar = readChar();
+ string NumStr;
+ NumStr = LastChar;
+
+ while (isdigit(LastChar = ReadChar())) //[0-9]*
+ NumStr += LastChar;
+
+ if (sscanf_s(NumStr.c_str(), "%llu", &NumberVal) != 1)
+ return ReportError("sscanf_s failed on decimal number");
+ return tok_number;
}
- if (sscanf_s(NumStr.c_str(), "%llu", &NumberVal) != 1)
- return ReportError("sscanf_s failed on decimal number");
- return tok_number;
- }
-
- //comments
- if (LastChar == '/')
- {
- LastChar = readChar();
-
- //line comment
- if (LastChar == '/')
+ //comments
+ if (LastChar == '/' && PeekChar() == '/') //line comment
{
do
{
- LastChar = readChar();
+ LastChar = ReadChar();
} while (LastChar != EOF && LastChar != '\n');
if (LastChar == '\n')
- return getToken(); //interpret the next line
+ return GetToken(); //interpret the next line
}
- else
- return ReportError("invalid comment");
+ else if (LastChar == '/' && PeekChar() == '*') //block comment
+ {
+ //TODO: implement this
+ }
+
+ //end of file
+ if (LastChar == EOF)
+ return tok_eof;
+
+ //unknown character
+ auto ThisChar = LastChar;
+ LastChar = ReadChar();
+ return ThisChar;
}
- //end of file
- if (LastChar == EOF)
- return tok_eof;
-
- //unknown character
- auto ThisChar = LastChar;
- LastChar = readChar();
- return ThisChar;
-}
-
-bool ReadInputFile(const char* filename)
-{
- return FileHelper::ReadAllText(filename, Input);
-}
-
-void testLex()
-{
- int tok;
- do
+ bool ReadInputFile(const string & filename)
{
- tok = getToken();
- puts(tokString(tok).c_str());
- } while (tok != tok_eof && tok != tok_error);
-}
-
-void test()
-{
- if (!ReadInputFile("test.bt"))
- {
- puts("failed to read input file");
- return;
+ return FileHelper::ReadAllText(filename, Input);
}
- setup();
- testLex();
+
+ void TestLex(function lexEnum)
+ {
+ int tok;
+ do
+ {
+ tok = GetToken();
+ lexEnum(TokString(tok));
+ } while (tok != tok_eof && tok != tok_error);
+ }
+};
+
+bool TestLexer(const string & filename)
+{
+ Lexer lexer;
+ if (!lexer.ReadInputFile("tests\\" + filename))
+ {
+ printf("failed to read \"%s\"\n", filename.c_str());
+ return false;
+ }
+ string expected;
+ if (!FileHelper::ReadAllText(filename + ".lextest", expected)) //don't fail tests that we didn't specify yet
+ return true;
+ StringUtils::ReplaceAll(expected, "\r\n", "\n");
+ expected = StringUtils::Trim(expected);
+ string actual;
+ lexer.TestLex([&](const string & line)
+ {
+ actual += line + "\n";
+ });
+ actual = StringUtils::Trim(actual);
+ if (expected == actual)
+ {
+ printf("lexer test for \"%s\" success!\n", filename.c_str());
+ return true;
+ }
+ printf("lexer test for \"%s\" failed\n", filename.c_str());
+ FileHelper::WriteAllText("expected.out", expected);
+ FileHelper::WriteAllText("actual.out", actual);
+ return false;
+}
+
+void RunLexerTests()
+{
+ for (auto file : testFiles)
+ TestLexer(file);
+}
+
+bool DebugLexer(const string & filename)
+{
+ printf("Debugging \"%s\"\n", filename.c_str());
+ Lexer lexer;
+ if (!lexer.ReadInputFile("tests\\" + filename))
+ {
+ printf("failed to read \"%s\"\n", filename.c_str());
+ return false;
+ }
+ lexer.TestLex([](const string & line)
+ {
+ puts(line.c_str());
+ });
+ puts("");
+ return true;
}
int main()
{
- test();
+ DebugLexer(testFiles[1]);
+ RunLexerTests();
system("pause");
return 0;
}
\ No newline at end of file
diff --git a/cparser/testfiles.h b/cparser/testfiles.h
new file mode 100644
index 0000000..45cf40c
--- /dev/null
+++ b/cparser/testfiles.h
@@ -0,0 +1,95 @@
+static const char* testFiles[] =
+{
+ "test.bt",
+ "CDATemplate.bt",
+ "NetflowVersion5.bt",
+ "SHXTemplate.bt",
+ "WinhexPosTemplate.bt",
+ "Mifare1kTemplate.bt",
+ "PALTemplate.bt",
+ "GocleverTemplate.bt",
+ "OGGTemplate.bt",
+ "STLTemplate.bt",
+ "SinclairMicrodriveImage.bt",
+ "RDBTemplate.bt",
+ "DBFTemplate.bt",
+ "Mifare4kTemplate.bt",
+ "GPTTemplate.bt",
+ "SSPTemplate.bt",
+ "SHPTemplate.bt",
+ "SRecTemplate.bt",
+ "FLVTemplate.bt",
+ "LUKSTemplate.bt",
+ "PCXTemplate.bt",
+ "UTMPTemplate.bt",
+ "ElTorito.bt",
+ "DMPTemplate.bt",
+ "OscarItemTemplate.bt",
+ "EOTTemplate.bt",
+ "ISOTemplate.bt",
+ "CLASSTemplate2.bt",
+ "EVSBTemplate.bt",
+ "BMPTemplate.bt",
+ "TGATemplate.bt",
+ "TOCTemplate.bt",
+ "CABTemplate.bt",
+ "RIFFTemplate.bt",
+ "AndroidManifestTemplate.bt",
+ "InspectorWithMP4DateTime.bt",
+ "FAT16Template.bt",
+ "PNGTemplate.bt",
+ "ICOTemplate.bt",
+ "RegistryPolicyFileTemplate.bt",
+ "VHDTemplate.bt",
+ "ISOBMFTemplate.bt",
+ "PCAPTemplate.bt",
+ "AVITemplate.bt",
+ "ZIPTemplate.bt",
+ "CRXTemplate.bt",
+ "MIDITemplate.bt",
+ "GZipTemplate.bt",
+ "GIFTemplate.bt",
+ "InspectorDates.bt",
+ "WAVTemplate.bt",
+ "RegistryHive.bt",
+ "EMFTemplate.bt",
+ "ROMFS.bt",
+ "OrCad3.20a_SCH.bt",
+ "MP4Template.bt",
+ "CLASSTemplate.bt",
+ "WMFTemplate.bt",
+ "LNKTemplate.bt",
+ "OrCAD3.20a_LIB.bt",
+ "PSFTemplate.bt",
+ "RARTemplate.bt",
+ "PYCTemplate.bt",
+ "EXETemplate.bt",
+ "PNG12Template.bt",
+ "TacxTemplate.bt",
+ "MFTRecord.bt",
+ "MP3Template.bt",
+ "MBRTemplate.bt",
+ "WAVTemplateAdv.bt",
+ "PDFTemplate.bt",
+ "EXETemplate2.bt",
+ "RESTemplate.bt",
+ "ZIPTemplateAdv.bt",
+ "SF2Template.bt",
+ "MOBITemplate.bt",
+ "MBRTemplateFAT.bt",
+ "exFATTemplate.bt",
+ "ELFTemplate.new.bt",
+ "ELFTemplate.bt",
+ "MachOTemplate.bt",
+ "PETemplate.bt",
+ "EDIDTemplate.bt",
+ "GeoTIFTemplate.bt",
+ "CLASSTemplate3.bt",
+ "CAPTemplate.bt",
+ "TIFTemplate.bt",
+ "TTFTemplate.bt",
+ "JPGTemplate.bt",
+ "DEXTemplate.bt",
+ "DEXTemplate.new.bt",
+ "SWFTemplate.bt",
+};
\ No newline at end of file
diff --git a/cparser/AVITemplate.bt b/cparser/tests/AVITemplate.bt
similarity index 100%
rename from cparser/AVITemplate.bt
rename to cparser/tests/AVITemplate.bt
diff --git a/cparser/AndroidManifestTemplate.bt b/cparser/tests/AndroidManifestTemplate.bt
similarity index 100%
rename from cparser/AndroidManifestTemplate.bt
rename to cparser/tests/AndroidManifestTemplate.bt
diff --git a/cparser/BMPTemplate.bt b/cparser/tests/BMPTemplate.bt
similarity index 100%
rename from cparser/BMPTemplate.bt
rename to cparser/tests/BMPTemplate.bt
diff --git a/cparser/CABTemplate.bt b/cparser/tests/CABTemplate.bt
similarity index 100%
rename from cparser/CABTemplate.bt
rename to cparser/tests/CABTemplate.bt
diff --git a/cparser/CAPTemplate.bt b/cparser/tests/CAPTemplate.bt
similarity index 100%
rename from cparser/CAPTemplate.bt
rename to cparser/tests/CAPTemplate.bt
diff --git a/cparser/CDATemplate.bt b/cparser/tests/CDATemplate.bt
similarity index 100%
rename from cparser/CDATemplate.bt
rename to cparser/tests/CDATemplate.bt
diff --git a/cparser/CLASSTemplate.bt b/cparser/tests/CLASSTemplate.bt
similarity index 100%
rename from cparser/CLASSTemplate.bt
rename to cparser/tests/CLASSTemplate.bt
diff --git a/cparser/CLASSTemplate2.bt b/cparser/tests/CLASSTemplate2.bt
similarity index 100%
rename from cparser/CLASSTemplate2.bt
rename to cparser/tests/CLASSTemplate2.bt
diff --git a/cparser/CLASSTemplate3.bt b/cparser/tests/CLASSTemplate3.bt
similarity index 100%
rename from cparser/CLASSTemplate3.bt
rename to cparser/tests/CLASSTemplate3.bt
diff --git a/cparser/CRXTemplate.bt b/cparser/tests/CRXTemplate.bt
similarity index 100%
rename from cparser/CRXTemplate.bt
rename to cparser/tests/CRXTemplate.bt
diff --git a/cparser/DBFTemplate.bt b/cparser/tests/DBFTemplate.bt
similarity index 100%
rename from cparser/DBFTemplate.bt
rename to cparser/tests/DBFTemplate.bt
diff --git a/cparser/DEXTemplate.bt b/cparser/tests/DEXTemplate.bt
similarity index 100%
rename from cparser/DEXTemplate.bt
rename to cparser/tests/DEXTemplate.bt
diff --git a/cparser/DEXTemplate.new.bt b/cparser/tests/DEXTemplate.new.bt
similarity index 100%
rename from cparser/DEXTemplate.new.bt
rename to cparser/tests/DEXTemplate.new.bt
diff --git a/cparser/DMPTemplate.bt b/cparser/tests/DMPTemplate.bt
similarity index 100%
rename from cparser/DMPTemplate.bt
rename to cparser/tests/DMPTemplate.bt
diff --git a/cparser/EDIDTemplate.bt b/cparser/tests/EDIDTemplate.bt
similarity index 100%
rename from cparser/EDIDTemplate.bt
rename to cparser/tests/EDIDTemplate.bt
diff --git a/cparser/ELFTemplate.bt b/cparser/tests/ELFTemplate.bt
similarity index 100%
rename from cparser/ELFTemplate.bt
rename to cparser/tests/ELFTemplate.bt
diff --git a/cparser/ELFTemplate.new.bt b/cparser/tests/ELFTemplate.new.bt
similarity index 100%
rename from cparser/ELFTemplate.new.bt
rename to cparser/tests/ELFTemplate.new.bt
diff --git a/cparser/EMFTemplate.bt b/cparser/tests/EMFTemplate.bt
similarity index 100%
rename from cparser/EMFTemplate.bt
rename to cparser/tests/EMFTemplate.bt
diff --git a/cparser/EOTTemplate.bt b/cparser/tests/EOTTemplate.bt
similarity index 100%
rename from cparser/EOTTemplate.bt
rename to cparser/tests/EOTTemplate.bt
diff --git a/cparser/EVSBTemplate.bt b/cparser/tests/EVSBTemplate.bt
similarity index 100%
rename from cparser/EVSBTemplate.bt
rename to cparser/tests/EVSBTemplate.bt
diff --git a/cparser/EXETemplate.bt b/cparser/tests/EXETemplate.bt
similarity index 100%
rename from cparser/EXETemplate.bt
rename to cparser/tests/EXETemplate.bt
diff --git a/cparser/EXETemplate2.bt b/cparser/tests/EXETemplate2.bt
similarity index 100%
rename from cparser/EXETemplate2.bt
rename to cparser/tests/EXETemplate2.bt
diff --git a/cparser/ElTorito.bt b/cparser/tests/ElTorito.bt
similarity index 100%
rename from cparser/ElTorito.bt
rename to cparser/tests/ElTorito.bt
diff --git a/cparser/FAT16Template.bt b/cparser/tests/FAT16Template.bt
similarity index 100%
rename from cparser/FAT16Template.bt
rename to cparser/tests/FAT16Template.bt
diff --git a/cparser/FLVTemplate.bt b/cparser/tests/FLVTemplate.bt
similarity index 100%
rename from cparser/FLVTemplate.bt
rename to cparser/tests/FLVTemplate.bt
diff --git a/cparser/GIFTemplate.bt b/cparser/tests/GIFTemplate.bt
similarity index 100%
rename from cparser/GIFTemplate.bt
rename to cparser/tests/GIFTemplate.bt
diff --git a/cparser/GPTTemplate.bt b/cparser/tests/GPTTemplate.bt
similarity index 100%
rename from cparser/GPTTemplate.bt
rename to cparser/tests/GPTTemplate.bt
diff --git a/cparser/GZipTemplate.bt b/cparser/tests/GZipTemplate.bt
similarity index 100%
rename from cparser/GZipTemplate.bt
rename to cparser/tests/GZipTemplate.bt
diff --git a/cparser/GeoTIFTemplate.bt b/cparser/tests/GeoTIFTemplate.bt
similarity index 100%
rename from cparser/GeoTIFTemplate.bt
rename to cparser/tests/GeoTIFTemplate.bt
diff --git a/cparser/GocleverTemplate.bt b/cparser/tests/GocleverTemplate.bt
similarity index 100%
rename from cparser/GocleverTemplate.bt
rename to cparser/tests/GocleverTemplate.bt
diff --git a/cparser/ICOTemplate.bt b/cparser/tests/ICOTemplate.bt
similarity index 100%
rename from cparser/ICOTemplate.bt
rename to cparser/tests/ICOTemplate.bt
diff --git a/cparser/ISOBMFTemplate.bt b/cparser/tests/ISOBMFTemplate.bt
similarity index 100%
rename from cparser/ISOBMFTemplate.bt
rename to cparser/tests/ISOBMFTemplate.bt
diff --git a/cparser/ISOTemplate.bt b/cparser/tests/ISOTemplate.bt
similarity index 100%
rename from cparser/ISOTemplate.bt
rename to cparser/tests/ISOTemplate.bt
diff --git a/cparser/InspectorDates.bt b/cparser/tests/InspectorDates.bt
similarity index 100%
rename from cparser/InspectorDates.bt
rename to cparser/tests/InspectorDates.bt
diff --git a/cparser/InspectorWithMP4DateTime.bt b/cparser/tests/InspectorWithMP4DateTime.bt
similarity index 100%
rename from cparser/InspectorWithMP4DateTime.bt
rename to cparser/tests/InspectorWithMP4DateTime.bt
diff --git a/cparser/JPGTemplate.bt b/cparser/tests/JPGTemplate.bt
similarity index 100%
rename from cparser/JPGTemplate.bt
rename to cparser/tests/JPGTemplate.bt
diff --git a/cparser/LNKTemplate.bt b/cparser/tests/LNKTemplate.bt
similarity index 100%
rename from cparser/LNKTemplate.bt
rename to cparser/tests/LNKTemplate.bt
diff --git a/cparser/LUKSTemplate.bt b/cparser/tests/LUKSTemplate.bt
similarity index 100%
rename from cparser/LUKSTemplate.bt
rename to cparser/tests/LUKSTemplate.bt
diff --git a/cparser/MBRTemplate.bt b/cparser/tests/MBRTemplate.bt
similarity index 100%
rename from cparser/MBRTemplate.bt
rename to cparser/tests/MBRTemplate.bt
diff --git a/cparser/MBRTemplateFAT.bt b/cparser/tests/MBRTemplateFAT.bt
similarity index 100%
rename from cparser/MBRTemplateFAT.bt
rename to cparser/tests/MBRTemplateFAT.bt
diff --git a/cparser/MFTRecord.bt b/cparser/tests/MFTRecord.bt
similarity index 100%
rename from cparser/MFTRecord.bt
rename to cparser/tests/MFTRecord.bt
diff --git a/cparser/MIDITemplate.bt b/cparser/tests/MIDITemplate.bt
similarity index 100%
rename from cparser/MIDITemplate.bt
rename to cparser/tests/MIDITemplate.bt
diff --git a/cparser/MOBITemplate.bt b/cparser/tests/MOBITemplate.bt
similarity index 100%
rename from cparser/MOBITemplate.bt
rename to cparser/tests/MOBITemplate.bt
diff --git a/cparser/MP3Template.bt b/cparser/tests/MP3Template.bt
similarity index 100%
rename from cparser/MP3Template.bt
rename to cparser/tests/MP3Template.bt
diff --git a/cparser/MP4Template.bt b/cparser/tests/MP4Template.bt
similarity index 100%
rename from cparser/MP4Template.bt
rename to cparser/tests/MP4Template.bt
diff --git a/cparser/MachOTemplate.bt b/cparser/tests/MachOTemplate.bt
similarity index 100%
rename from cparser/MachOTemplate.bt
rename to cparser/tests/MachOTemplate.bt
diff --git a/cparser/Mifare1kTemplate.bt b/cparser/tests/Mifare1kTemplate.bt
similarity index 100%
rename from cparser/Mifare1kTemplate.bt
rename to cparser/tests/Mifare1kTemplate.bt
diff --git a/cparser/Mifare4kTemplate.bt b/cparser/tests/Mifare4kTemplate.bt
similarity index 100%
rename from cparser/Mifare4kTemplate.bt
rename to cparser/tests/Mifare4kTemplate.bt
diff --git a/cparser/NetflowVersion5.bt b/cparser/tests/NetflowVersion5.bt
similarity index 100%
rename from cparser/NetflowVersion5.bt
rename to cparser/tests/NetflowVersion5.bt
diff --git a/cparser/OGGTemplate.bt b/cparser/tests/OGGTemplate.bt
similarity index 100%
rename from cparser/OGGTemplate.bt
rename to cparser/tests/OGGTemplate.bt
diff --git a/cparser/OrCAD3.20a_LIB.bt b/cparser/tests/OrCAD3.20a_LIB.bt
similarity index 100%
rename from cparser/OrCAD3.20a_LIB.bt
rename to cparser/tests/OrCAD3.20a_LIB.bt
diff --git a/cparser/OrCad3.20a_SCH.bt b/cparser/tests/OrCad3.20a_SCH.bt
similarity index 100%
rename from cparser/OrCad3.20a_SCH.bt
rename to cparser/tests/OrCad3.20a_SCH.bt
diff --git a/cparser/OscarItemTemplate.bt b/cparser/tests/OscarItemTemplate.bt
similarity index 100%
rename from cparser/OscarItemTemplate.bt
rename to cparser/tests/OscarItemTemplate.bt
diff --git a/cparser/PALTemplate.bt b/cparser/tests/PALTemplate.bt
similarity index 100%
rename from cparser/PALTemplate.bt
rename to cparser/tests/PALTemplate.bt
diff --git a/cparser/PCAPTemplate.bt b/cparser/tests/PCAPTemplate.bt
similarity index 100%
rename from cparser/PCAPTemplate.bt
rename to cparser/tests/PCAPTemplate.bt
diff --git a/cparser/PCXTemplate.bt b/cparser/tests/PCXTemplate.bt
similarity index 100%
rename from cparser/PCXTemplate.bt
rename to cparser/tests/PCXTemplate.bt
diff --git a/cparser/PDFTemplate.bt b/cparser/tests/PDFTemplate.bt
similarity index 100%
rename from cparser/PDFTemplate.bt
rename to cparser/tests/PDFTemplate.bt
diff --git a/cparser/PETemplate.bt b/cparser/tests/PETemplate.bt
similarity index 100%
rename from cparser/PETemplate.bt
rename to cparser/tests/PETemplate.bt
diff --git a/cparser/PNG12Template.bt b/cparser/tests/PNG12Template.bt
similarity index 100%
rename from cparser/PNG12Template.bt
rename to cparser/tests/PNG12Template.bt
diff --git a/cparser/PNGTemplate.bt b/cparser/tests/PNGTemplate.bt
similarity index 100%
rename from cparser/PNGTemplate.bt
rename to cparser/tests/PNGTemplate.bt
diff --git a/cparser/PSFTemplate.bt b/cparser/tests/PSFTemplate.bt
similarity index 100%
rename from cparser/PSFTemplate.bt
rename to cparser/tests/PSFTemplate.bt
diff --git a/cparser/PYCTemplate.bt b/cparser/tests/PYCTemplate.bt
similarity index 100%
rename from cparser/PYCTemplate.bt
rename to cparser/tests/PYCTemplate.bt
diff --git a/cparser/RARTemplate.bt b/cparser/tests/RARTemplate.bt
similarity index 100%
rename from cparser/RARTemplate.bt
rename to cparser/tests/RARTemplate.bt
diff --git a/cparser/RDBTemplate.bt b/cparser/tests/RDBTemplate.bt
similarity index 100%
rename from cparser/RDBTemplate.bt
rename to cparser/tests/RDBTemplate.bt
diff --git a/cparser/RESTemplate.bt b/cparser/tests/RESTemplate.bt
similarity index 100%
rename from cparser/RESTemplate.bt
rename to cparser/tests/RESTemplate.bt
diff --git a/cparser/RIFFTemplate.bt b/cparser/tests/RIFFTemplate.bt
similarity index 100%
rename from cparser/RIFFTemplate.bt
rename to cparser/tests/RIFFTemplate.bt
diff --git a/cparser/ROMFS.bt b/cparser/tests/ROMFS.bt
similarity index 100%
rename from cparser/ROMFS.bt
rename to cparser/tests/ROMFS.bt
diff --git a/cparser/RegistryHive.bt b/cparser/tests/RegistryHive.bt
similarity index 100%
rename from cparser/RegistryHive.bt
rename to cparser/tests/RegistryHive.bt
diff --git a/cparser/RegistryPolicyFileTemplate.bt b/cparser/tests/RegistryPolicyFileTemplate.bt
similarity index 100%
rename from cparser/RegistryPolicyFileTemplate.bt
rename to cparser/tests/RegistryPolicyFileTemplate.bt
diff --git a/cparser/SF2Template.bt b/cparser/tests/SF2Template.bt
similarity index 100%
rename from cparser/SF2Template.bt
rename to cparser/tests/SF2Template.bt
diff --git a/cparser/SHPTemplate.bt b/cparser/tests/SHPTemplate.bt
similarity index 100%
rename from cparser/SHPTemplate.bt
rename to cparser/tests/SHPTemplate.bt
diff --git a/cparser/SHXTemplate.bt b/cparser/tests/SHXTemplate.bt
similarity index 100%
rename from cparser/SHXTemplate.bt
rename to cparser/tests/SHXTemplate.bt
diff --git a/cparser/SRecTemplate.bt b/cparser/tests/SRecTemplate.bt
similarity index 100%
rename from cparser/SRecTemplate.bt
rename to cparser/tests/SRecTemplate.bt
diff --git a/cparser/SSPTemplate.bt b/cparser/tests/SSPTemplate.bt
similarity index 100%
rename from cparser/SSPTemplate.bt
rename to cparser/tests/SSPTemplate.bt
diff --git a/cparser/STLTemplate.bt b/cparser/tests/STLTemplate.bt
similarity index 100%
rename from cparser/STLTemplate.bt
rename to cparser/tests/STLTemplate.bt
diff --git a/cparser/SWFTemplate.bt b/cparser/tests/SWFTemplate.bt
similarity index 100%
rename from cparser/SWFTemplate.bt
rename to cparser/tests/SWFTemplate.bt
diff --git a/cparser/SinclairMicrodriveImage.bt b/cparser/tests/SinclairMicrodriveImage.bt
similarity index 100%
rename from cparser/SinclairMicrodriveImage.bt
rename to cparser/tests/SinclairMicrodriveImage.bt
diff --git a/cparser/TGATemplate.bt b/cparser/tests/TGATemplate.bt
similarity index 100%
rename from cparser/TGATemplate.bt
rename to cparser/tests/TGATemplate.bt
diff --git a/cparser/TIFTemplate.bt b/cparser/tests/TIFTemplate.bt
similarity index 100%
rename from cparser/TIFTemplate.bt
rename to cparser/tests/TIFTemplate.bt
diff --git a/cparser/TOCTemplate.bt b/cparser/tests/TOCTemplate.bt
similarity index 100%
rename from cparser/TOCTemplate.bt
rename to cparser/tests/TOCTemplate.bt
diff --git a/cparser/TTFTemplate.bt b/cparser/tests/TTFTemplate.bt
similarity index 100%
rename from cparser/TTFTemplate.bt
rename to cparser/tests/TTFTemplate.bt
diff --git a/cparser/TacxTemplate.bt b/cparser/tests/TacxTemplate.bt
similarity index 100%
rename from cparser/TacxTemplate.bt
rename to cparser/tests/TacxTemplate.bt
diff --git a/cparser/UTMPTemplate.bt b/cparser/tests/UTMPTemplate.bt
similarity index 100%
rename from cparser/UTMPTemplate.bt
rename to cparser/tests/UTMPTemplate.bt
diff --git a/cparser/VHDTemplate.bt b/cparser/tests/VHDTemplate.bt
similarity index 100%
rename from cparser/VHDTemplate.bt
rename to cparser/tests/VHDTemplate.bt
diff --git a/cparser/WAVTemplate.bt b/cparser/tests/WAVTemplate.bt
similarity index 100%
rename from cparser/WAVTemplate.bt
rename to cparser/tests/WAVTemplate.bt
diff --git a/cparser/WAVTemplateAdv.bt b/cparser/tests/WAVTemplateAdv.bt
similarity index 100%
rename from cparser/WAVTemplateAdv.bt
rename to cparser/tests/WAVTemplateAdv.bt
diff --git a/cparser/WMFTemplate.bt b/cparser/tests/WMFTemplate.bt
similarity index 100%
rename from cparser/WMFTemplate.bt
rename to cparser/tests/WMFTemplate.bt
diff --git a/cparser/WinhexPosTemplate.bt b/cparser/tests/WinhexPosTemplate.bt
similarity index 100%
rename from cparser/WinhexPosTemplate.bt
rename to cparser/tests/WinhexPosTemplate.bt
diff --git a/cparser/ZIPTemplate.bt b/cparser/tests/ZIPTemplate.bt
similarity index 100%
rename from cparser/ZIPTemplate.bt
rename to cparser/tests/ZIPTemplate.bt
diff --git a/cparser/ZIPTemplateAdv.bt b/cparser/tests/ZIPTemplateAdv.bt
similarity index 100%
rename from cparser/ZIPTemplateAdv.bt
rename to cparser/tests/ZIPTemplateAdv.bt
diff --git a/cparser/exFATTemplate.bt b/cparser/tests/exFATTemplate.bt
similarity index 100%
rename from cparser/exFATTemplate.bt
rename to cparser/tests/exFATTemplate.bt
diff --git a/cparser/test.bt b/cparser/tests/test.bt
similarity index 100%
rename from cparser/test.bt
rename to cparser/tests/test.bt
diff --git a/cparser/tests/test.bt.lextest b/cparser/tests/test.bt.lextest
new file mode 100644
index 0000000..27969b0
--- /dev/null
+++ b/cparser/tests/test.bt.lextest
@@ -0,0 +1,53 @@
+tok_struct
+tok_identifier "DBZ"
+{
+tok_struct
+tok_identifier "HEADER"
+{
+tok_char
+tok_identifier "magic"
+[
+tok_number 4 (0x4)
+]
+;
+tok_unsigned
+tok_int
+tok_identifier "size"
+;
+tok_unsigned
+tok_int
+tok_identifier "dataStart"
+;
+tok_unsigned
+tok_int
+tok_identifier "numEntries"
+;
+}
+tok_identifier "header"
+;
+tok_char
+tok_identifier "empty"
+[
+tok_identifier "header"
+.
+tok_identifier "size"
+-
+tok_sizeof
+(
+tok_identifier "HEADER"
+)
+]
+;
+tok_unsigned
+tok_int
+tok_identifier "entryOffsets"
+[
+tok_identifier "header"
+.
+tok_identifier "numEntries"
+]
+;
+}
+tok_identifier "dbz"
+;
+tok_eof
\ No newline at end of file