Browse Source
git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/branches/vbnet@5828 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61pull/1/head
4 changed files with 408 additions and 343 deletions
@ -0,0 +1,398 @@ |
|||||||
|
// <file>
|
||||||
|
// <copyright see="prj:///doc/copyright.txt"/>
|
||||||
|
// <license see="prj:///doc/license.txt"/>
|
||||||
|
// <owner name="Siegfried Pammer" email="siegfriedpammer@gmail.com" />
|
||||||
|
// <version>$Revision$</version>
|
||||||
|
// </file>
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Diagnostics; |
||||||
|
using System.IO; |
||||||
|
using System.Linq; |
||||||
|
using System.Security.Principal; |
||||||
|
using System.Text; |
||||||
|
using System.Text.RegularExpressions; |
||||||
|
using System.Threading.Tasks; |
||||||
|
using NRefactoryASTGenerator.Ast; |
||||||
|
|
||||||
|
namespace NRefactoryASTGenerator |
||||||
|
{ |
||||||
|
static class KeywordGenerator |
||||||
|
{ |
||||||
|
static readonly string baseDir = "../../../Project/Src/Lexer/"; |
||||||
|
static readonly string testBaseDir = "../../../Test/Lexer/"; |
||||||
|
static readonly string parserBaseDir = "../../../Project/Src/Parser/"; |
||||||
|
|
||||||
|
public static void Generate() |
||||||
|
{ |
||||||
|
Generate("CSharp"); |
||||||
|
Generate("VBNet"); |
||||||
|
} |
||||||
|
|
||||||
|
static void Generate(string language) |
||||||
|
{ |
||||||
|
try { |
||||||
|
Dictionary<string, string> properties = new Dictionary<string, string>(); |
||||||
|
Dictionary<string, string[]> sets = new Dictionary<string, string[]>(); |
||||||
|
List<string> keywords = new List<string>(); |
||||||
|
List<string> terminals = new List<string>(); |
||||||
|
Dictionary<string, string> specialChars = new Dictionary<string, string>(); |
||||||
|
|
||||||
|
ReadFile(properties, sets, keywords, terminals, specialChars, language); |
||||||
|
|
||||||
|
GenerateFiles(properties, sets, keywords, terminals, specialChars, language); |
||||||
|
} catch (Exception e) { |
||||||
|
Debug.Print(e.ToString()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static void GenerateFiles(Dictionary<string, string> properties, Dictionary<string, string[]> sets, |
||||||
|
List<string> keywords, List<string> terminals, Dictionary<string, string> specialChars, |
||||||
|
string language) |
||||||
|
{ |
||||||
|
GenerateKeywords(properties, keywords, language); |
||||||
|
GenerateTokens(properties, sets, keywords, terminals, specialChars, language); |
||||||
|
GenerateTests(keywords, specialChars, language); |
||||||
|
GenerateKeywordSection(keywords, terminals, specialChars, language); |
||||||
|
} |
||||||
|
|
||||||
|
static void GenerateKeywordSection(List<string> keywords, List<string> terminals, Dictionary<string, string> specialChars, string language) |
||||||
|
{ |
||||||
|
string sourceDir = Path.Combine(parserBaseDir, language, (language == "CSharp" ? "cs" : language) + ".atg"); |
||||||
|
StringBuilder builder = new StringBuilder(); |
||||||
|
|
||||||
|
builder.AppendLine("/* START AUTOGENERATED TOKENS SECTION */"); |
||||||
|
builder.AppendLine("TOKENS"); |
||||||
|
builder.AppendLine("\t/* ----- terminal classes ----- */"); |
||||||
|
builder.AppendLine("\t/* EOF is 0 */"); |
||||||
|
|
||||||
|
foreach (string terminal in terminals) { |
||||||
|
if (terminal == "EOF") |
||||||
|
continue; |
||||||
|
if (terminal == "Identifier") { |
||||||
|
builder.AppendLine("\tident"); |
||||||
|
continue; |
||||||
|
} |
||||||
|
builder.AppendLine("\t" + terminal); |
||||||
|
} |
||||||
|
|
||||||
|
builder.AppendLine(); |
||||||
|
builder.AppendLine("\t/* ----- special character ----- */"); |
||||||
|
foreach (string specialChar in specialChars.Values) { |
||||||
|
builder.AppendLine("\t" + specialChar); |
||||||
|
} |
||||||
|
|
||||||
|
builder.AppendLine(); |
||||||
|
builder.AppendLine("\t/* ----- keywords ----- */"); |
||||||
|
foreach (string keyword in keywords) { |
||||||
|
builder.AppendLine("\t\"" + keyword + "\""); |
||||||
|
} |
||||||
|
|
||||||
|
builder.AppendLine("/* END AUTOGENERATED TOKENS SECTION */"); |
||||||
|
|
||||||
|
string[] generatedLines = builder.ToString().Split(new string[] { Environment.NewLine }, StringSplitOptions.None); |
||||||
|
string[] lines = File.ReadAllLines(sourceDir); |
||||||
|
|
||||||
|
var newContent = lines |
||||||
|
.TakeWhile(l => l != "/* START AUTOGENERATED TOKENS SECTION */") |
||||||
|
.Concat(generatedLines) |
||||||
|
.Concat(lines.SkipWhile(l => l != "/* END AUTOGENERATED TOKENS SECTION */").Skip(2)) |
||||||
|
.ToArray(); |
||||||
|
|
||||||
|
File.WriteAllLines(sourceDir, newContent); |
||||||
|
} |
||||||
|
|
||||||
|
static void GenerateTests(List<string> keywords, Dictionary<string, string> specialChars, string language) |
||||||
|
{ |
||||||
|
string sourceDir = Path.Combine(testBaseDir, language, "LexerTests.cs"); |
||||||
|
using (StreamWriter writer = new StreamWriter(new FileStream(sourceDir, FileMode.Create))) { |
||||||
|
writer.WriteLine("using System;"); |
||||||
|
writer.WriteLine("using System.IO;"); |
||||||
|
writer.WriteLine("using NUnit.Framework;"); |
||||||
|
writer.WriteLine("using ICSharpCode.NRefactory.Parser;"); |
||||||
|
writer.WriteLine("using ICSharpCode.NRefactory.Parser.{0};", language == "VBNet" ? "VB" : language); |
||||||
|
writer.WriteLine("using ICSharpCode.NRefactory.PrettyPrinter;\n"); |
||||||
|
writer.WriteLine(); |
||||||
|
writer.WriteLine("namespace ICSharpCode.NRefactory.Tests.Lexer.{0}", language == "VBNet" ? "VB" : language); |
||||||
|
writer.WriteLine("{"); |
||||||
|
writer.WriteLine("\t[TestFixture]"); |
||||||
|
writer.WriteLine("\tpublic sealed class LexerTests"); |
||||||
|
writer.WriteLine("\t{"); |
||||||
|
writer.WriteLine("\t\tILexer GenerateLexer(StringReader sr)"); |
||||||
|
writer.WriteLine("\t\t{"); |
||||||
|
writer.WriteLine("\t\t\treturn ParserFactory.CreateLexer(SupportedLanguage.CSharp, sr);"); |
||||||
|
writer.WriteLine("\t\t}"); |
||||||
|
for (int i = 0; i < specialChars.Values.Count; i++) { |
||||||
|
writer.WriteLine(); |
||||||
|
writer.WriteLine("\t\t[Test]"); |
||||||
|
writer.WriteLine("\t\tpublic void Test{0}()", specialChars.Keys.ElementAt(i)); |
||||||
|
writer.WriteLine("\t\t{"); |
||||||
|
writer.WriteLine("\t\t\tILexer lexer = GenerateLexer(new StringReader({0}));", specialChars.Values.ElementAt(i)); |
||||||
|
writer.WriteLine("\t\t\tAssert.AreEqual(Tokens.{0}, lexer.NextToken().Kind);", specialChars.Keys.ElementAt(i)); |
||||||
|
writer.WriteLine("\t\t}"); |
||||||
|
} |
||||||
|
foreach (string keyword in keywords) { |
||||||
|
writer.WriteLine(); |
||||||
|
writer.WriteLine("\t\t[Test]"); |
||||||
|
writer.WriteLine("\t\tpublic void Test{0}()", UpperCaseFirst(keyword)); |
||||||
|
writer.WriteLine("\t\t{"); |
||||||
|
writer.WriteLine("\t\t\tILexer lexer = GenerateLexer(new StringReader(\"{0}\"));", keyword); |
||||||
|
writer.WriteLine("\t\t\tAssert.AreEqual(Tokens.{0}, lexer.NextToken().Kind);", UpperCaseFirst(keyword)); |
||||||
|
writer.WriteLine("\t\t}"); |
||||||
|
} |
||||||
|
writer.WriteLine("\t}"); |
||||||
|
writer.WriteLine("}"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static void GenerateTokens(Dictionary<string, string> properties, Dictionary<string, string[]> sets, List<string> keywords, List<string> terminals, Dictionary<string, string> specialChars, string language) |
||||||
|
{ |
||||||
|
string sourceDir = Path.Combine(baseDir, language, "Tokens.cs"); |
||||||
|
using (StreamWriter writer = new StreamWriter(new FileStream(sourceDir, FileMode.Create))) { |
||||||
|
writer.WriteLine("// this file was autogenerated by a tool."); |
||||||
|
writer.WriteLine("using System;"); |
||||||
|
writer.WriteLine("using System.Collections;"); |
||||||
|
writer.WriteLine(); |
||||||
|
writer.WriteLine("namespace {0}", properties["Namespace"]); |
||||||
|
writer.WriteLine("{"); |
||||||
|
writer.WriteLine("\tpublic static class Tokens"); |
||||||
|
writer.WriteLine("\t{"); |
||||||
|
writer.WriteLine("\t\t// ----- terminal classes -----"); |
||||||
|
int tokenValue = 0; |
||||||
|
foreach (string terminal in terminals) |
||||||
|
writer.WriteToken(terminal, ref tokenValue); |
||||||
|
writer.WriteLine(); |
||||||
|
writer.WriteLine("\t\t// ----- special character -----"); |
||||||
|
foreach (string specialChar in specialChars.Keys) |
||||||
|
writer.WriteToken(specialChar, ref tokenValue); |
||||||
|
writer.WriteLine(); |
||||||
|
writer.WriteLine("\t\t// ----- keywords -----"); |
||||||
|
foreach (string keyword in keywords) |
||||||
|
writer.WriteToken(keyword, ref tokenValue); |
||||||
|
writer.WriteLine(); |
||||||
|
writer.WriteLine("\t\tpublic const int MaxToken = {0};", tokenValue); |
||||||
|
if (sets.Any()) { |
||||||
|
writer.WriteLine("\t\tstatic BitArray NewSet(params int[] values)"); |
||||||
|
writer.WriteLine("\t\t{"); |
||||||
|
writer.WriteLine("\t\t\tBitArray bitArray = new BitArray(MaxToken);"); |
||||||
|
writer.WriteLine("\t\t\tforeach (int val in values) {"); |
||||||
|
writer.WriteLine("\t\t\tbitArray[val] = true;"); |
||||||
|
writer.WriteLine("\t\t\t}"); |
||||||
|
writer.WriteLine("\t\t\treturn bitArray;"); |
||||||
|
writer.WriteLine("\t\t}"); |
||||||
|
foreach (var pair in sets) { |
||||||
|
StringBuilder builder = new StringBuilder(); |
||||||
|
PrintList(pair.Value, builder, sets, specialChars); |
||||||
|
writer.WriteLine("\t\tpublic static BitArray {0} = NewSet({1});", pair.Key, builder.ToString()); |
||||||
|
} |
||||||
|
writer.WriteLine(); |
||||||
|
} |
||||||
|
|
||||||
|
// write token number --> string function.
|
||||||
|
writer.WriteLine("\t\tstatic string[] tokenList = new string[] {"); |
||||||
|
|
||||||
|
writer.WriteLine("\t\t\t// ----- terminal classes -----"); |
||||||
|
foreach (string terminal in terminals) |
||||||
|
writer.WriteLine("\t\t\t\"<{0}>\",", terminal); |
||||||
|
|
||||||
|
writer.WriteLine("\t\t\t// ----- special character -----"); |
||||||
|
foreach (string specialChar in specialChars.Values) |
||||||
|
writer.WriteLine("\t\t\t{0},", specialChar); |
||||||
|
|
||||||
|
writer.WriteLine("\t\t\t// ----- keywords -----"); |
||||||
|
foreach (string keyword in keywords) |
||||||
|
writer.WriteLine("\t\t\t\"{0}\",", keyword); |
||||||
|
|
||||||
|
writer.WriteLine("\t\t};"); |
||||||
|
|
||||||
|
writer.WriteLine("\t\tpublic static string GetTokenString(int token)"); |
||||||
|
writer.WriteLine("\t\t{"); |
||||||
|
writer.WriteLine("\t\t\tif (token >= 0 && token < tokenList.Length) {"); |
||||||
|
writer.WriteLine("\t\t\t\treturn tokenList[token];"); |
||||||
|
writer.WriteLine("\t\t\t}"); |
||||||
|
writer.WriteLine("\t\t\tthrow new System.NotSupportedException(\"Unknown token:\" + token);"); |
||||||
|
writer.WriteLine("\t\t}"); |
||||||
|
|
||||||
|
writer.WriteLine("\t}"); |
||||||
|
writer.WriteLine("}"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static void PrintList(string[] value, StringBuilder builder, Dictionary<string, string[]> sets, Dictionary<string, string> specialChars) |
||||||
|
{ |
||||||
|
for (int i = 0; i < value.Length; i++) { |
||||||
|
string item = value[i]; |
||||||
|
if (Regex.IsMatch(item, "\\\"(\\w+)\\\"")) // keywords
|
||||||
|
builder.Append(UpperCaseFirst(item.Trim('"', ' ', '\t'))); |
||||||
|
else if (Regex.IsMatch(item, "\\\"(\\W+)\\\"")) // special chars
|
||||||
|
builder.Append(specialChars.Keys.ElementAt(specialChars.Values.FindIndex(it => item == it))); |
||||||
|
else if (Regex.IsMatch(item, "@(\\w+)")) // other list
|
||||||
|
PrintList(sets[item.Substring(1)], builder, sets, specialChars); |
||||||
|
else |
||||||
|
builder.Append(item); |
||||||
|
if (i + 1 < value.Length) |
||||||
|
builder.Append(", "); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static int FindIndex<T>(this IEnumerable<T> items, Func<T, bool> f) |
||||||
|
{ |
||||||
|
int index = -1; |
||||||
|
foreach (T item in items) { |
||||||
|
index++; |
||||||
|
if (f(item)) |
||||||
|
return index; |
||||||
|
} |
||||||
|
|
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
static void GenerateKeywords(Dictionary<string, string> properties, List<string> keywords, string language) |
||||||
|
{ |
||||||
|
string sourceDir = Path.Combine(baseDir, language, "Keywords.cs"); |
||||||
|
using (StreamWriter writer = new StreamWriter(new FileStream(sourceDir, FileMode.Create))) { |
||||||
|
writer.WriteLine("// this file was autogenerated by a tool."); |
||||||
|
writer.WriteLine("using System;"); |
||||||
|
writer.WriteLine(); |
||||||
|
writer.WriteLine("namespace {0}", properties["Namespace"]); |
||||||
|
writer.WriteLine("{"); |
||||||
|
writer.WriteLine("\tpublic static class Keywords"); |
||||||
|
writer.WriteLine("\t{"); |
||||||
|
writer.WriteLine("\t\tstatic readonly string[] keywordList = {"); |
||||||
|
for (int i = 0; i < keywords.Count; i++) { |
||||||
|
writer.Write("\t\t\t\"{0}\"", properties["UpperCaseKeywords"] == "True" ? keywords[i].ToUpperInvariant() : keywords[i]); |
||||||
|
if (i + 1 < keywords.Count) |
||||||
|
writer.Write(","); |
||||||
|
writer.WriteLine(); |
||||||
|
} |
||||||
|
writer.WriteLine("\t\t};"); |
||||||
|
writer.WriteLine("\t\t"); |
||||||
|
writer.WriteLine("\t\tstatic LookupTable keywords = new LookupTable({0});", properties["UpperCaseKeywords"] == "True" ? "false" : "true"); |
||||||
|
writer.WriteLine("\t\t"); |
||||||
|
writer.WriteLine("\t\tstatic Keywords()"); |
||||||
|
writer.WriteLine("\t\t{"); |
||||||
|
writer.WriteLine("\t\t\tfor (int i = 0; i < keywordList.Length; ++i) {"); |
||||||
|
writer.WriteLine("\t\t\t\tkeywords[keywordList[i]] = i + Tokens.{0};", UpperCaseFirst(keywords[0])); |
||||||
|
writer.WriteLine("\t\t\t}"); |
||||||
|
writer.WriteLine("\t\t}"); |
||||||
|
writer.WriteLine("\t\t"); |
||||||
|
writer.WriteLine("\t\tpublic static int GetToken(string keyword)"); |
||||||
|
writer.WriteLine("\t\t{"); |
||||||
|
writer.WriteLine("\t\t\treturn keywords[keyword];"); |
||||||
|
writer.WriteLine("\t\t}"); |
||||||
|
writer.WriteLine("\t\t"); |
||||||
|
writer.WriteLine("\t\tpublic static bool IsNonIdentifierKeyword(string word)"); |
||||||
|
writer.WriteLine("\t\t{"); |
||||||
|
writer.WriteLine("\t\t\tint token = GetToken(word);"); |
||||||
|
writer.WriteLine("\t\t\tif (token < 0)"); |
||||||
|
writer.WriteLine("\t\t\t\treturn false;"); |
||||||
|
writer.WriteLine("\t\t\treturn !Tokens.IdentifierTokens[token];"); |
||||||
|
writer.WriteLine("\t\t}"); |
||||||
|
|
||||||
|
writer.WriteLine("\t}"); |
||||||
|
writer.WriteLine("}"); |
||||||
|
|
||||||
|
writer.Close(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#region input
|
||||||
|
static void ReadFile(Dictionary<string, string> properties, Dictionary<string, string[]> sets, |
||||||
|
List<string> keywords, List<string> terminals, Dictionary<string, string> specialChars, |
||||||
|
string language) |
||||||
|
{ |
||||||
|
string sourceDir = Path.Combine(baseDir, language, "KeywordList.txt"); |
||||||
|
|
||||||
|
using (StreamReader reader = new StreamReader(new FileStream(sourceDir, FileMode.Open))) { |
||||||
|
string line = reader.ReadLine(); |
||||||
|
while (line != null) { |
||||||
|
ReadProperty(properties, line); |
||||||
|
ReadKeyword(keywords, line); |
||||||
|
ReadSet(sets, line); |
||||||
|
ReadTerminalSymbol(terminals, line); |
||||||
|
ReadSpecialChar(specialChars, line); |
||||||
|
line = reader.ReadLine(); |
||||||
|
} |
||||||
|
reader.Close(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static void ReadProperty(Dictionary<string, string> properties, string line) |
||||||
|
{ |
||||||
|
// properties form: $PROPERTY = "VALUE"
|
||||||
|
Match match = Regex.Match(line, @"^\s*\$(\w+)\s*=\s*(\S+)\s*$"); |
||||||
|
|
||||||
|
if (match.Success) { |
||||||
|
properties.Add(match.Groups[1].Value, match.Groups[2].Value); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static void ReadKeyword(List<string> keywords, string line) |
||||||
|
{ |
||||||
|
// special keywords form: "VALUE"
|
||||||
|
Match match = Regex.Match(line, "^\\s*\\\"(\\S+)\\s*\\\"\\s*$"); |
||||||
|
|
||||||
|
if (match.Success) { |
||||||
|
keywords.Add(match.Groups[1].Value); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static void ReadSet(Dictionary<string, string[]> sets, string line) |
||||||
|
{ |
||||||
|
// sets form: NAME(comma separated list)
|
||||||
|
Match match = Regex.Match(line, @"^\s*(\w+)\s*\((.*)\)\s*$"); |
||||||
|
|
||||||
|
if (match.Success) { |
||||||
|
sets.Add( |
||||||
|
match.Groups[1].Value, |
||||||
|
match.Groups[2].Value.Split(new[] {", "}, StringSplitOptions.None) |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static void ReadTerminalSymbol(List<string> terminals, string line) |
||||||
|
{ |
||||||
|
// special terminal classes form: name
|
||||||
|
Match match = Regex.Match(line, @"^\s*(\w+)\s*$"); |
||||||
|
|
||||||
|
if (match.Success) { |
||||||
|
terminals.Add(match.Groups[1].Value); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static void ReadSpecialChar(Dictionary<string, string> specialChars, string line) |
||||||
|
{ |
||||||
|
// special characters form: name = "VALUE"
|
||||||
|
Match match = Regex.Match(line, @"^\s*(\w+)\s*=\s*(\S+)\s*$"); |
||||||
|
|
||||||
|
if (match.Success) { |
||||||
|
specialChars.Add(match.Groups[1].Value, match.Groups[2].Value); |
||||||
|
} |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region helpers
|
||||||
|
static string UpperCaseFirst(string keyword) |
||||||
|
{ |
||||||
|
return char.ToUpperInvariant(keyword[0]) + keyword.Substring(1); |
||||||
|
} |
||||||
|
|
||||||
|
static void WriteToken(this StreamWriter writer, string tokenName, ref int tokenValue) |
||||||
|
{ |
||||||
|
string formattedName = UpperCaseFirst(tokenName).PadRight(20); |
||||||
|
if (tokenName == "GetType" || tokenName.ToLowerInvariant() == "equals") |
||||||
|
writer.WriteLine("\t\tnew public const int {0} = {1};", formattedName, tokenValue); |
||||||
|
else |
||||||
|
writer.WriteLine("\t\tpublic const int {0} = {1};", formattedName, tokenValue); |
||||||
|
tokenValue++; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
static void WriteList(this StreamWriter writer, Tuple<string, string[]> data) |
||||||
|
{ |
||||||
|
|
||||||
|
} |
||||||
|
#endregion
|
||||||
|
} |
||||||
|
} |
||||||
@ -1,340 +0,0 @@ |
|||||||
#!/bin/perl |
|
||||||
|
|
||||||
# File names |
|
||||||
$keyword_file = "KeywordList.txt"; |
|
||||||
$keywords_outfile = "Keywords.cs"; |
|
||||||
$tokens_outfile = "Tokens.cs"; |
|
||||||
$unittests_outfile = "LexerTests.cs"; |
|
||||||
$ATGTokensSection = "ATGTokensSection.gen"; |
|
||||||
|
|
||||||
#read infile |
|
||||||
print "\n"; |
|
||||||
print "Reading keyword definition from '$keyword_file'.\n"; |
|
||||||
open(DAT, $keyword_file) || die("Could not open file '$keyword_file': $!"); |
|
||||||
@raw_data=<DAT>; |
|
||||||
close(DAT); |
|
||||||
print "done.\n"; |
|
||||||
|
|
||||||
#analyse infile |
|
||||||
print "starting analysis... this could take a few seconds.\n"; |
|
||||||
|
|
||||||
foreach (@raw_data) { |
|
||||||
if ($_=~/^\s*\$(\w+)\s*=\s*(\S+)\s*$/) { |
|
||||||
#properties form: $PROPERTY = "VALUE" |
|
||||||
$properties{$1} = $2; |
|
||||||
} elsif ($_=~/^\s*(\w+)\s*=\s*(\S+)\s*$/) { |
|
||||||
#special characters form: name = "VALUE" |
|
||||||
$specialCharLookup{$2} = $1; |
|
||||||
$special_chars[$#special_chars + 1] = $1; |
|
||||||
$special_values[$#special_values + 1] = $2; |
|
||||||
} elsif ($_=~/^\s*\"(\S+)\s*\"\s*$/) { |
|
||||||
#special keywords form: "VALUE" |
|
||||||
$keywords[$#keywords + 1] = $1; |
|
||||||
} elsif ($_=~/^\s*(\w+)\s*\((.*)\)\s*$/) { |
|
||||||
$sets[$#sets + 1] = $1; |
|
||||||
#Split set values (comma separated list) |
|
||||||
$_ = $2; |
|
||||||
@vals = split/\s*,\s*/; |
|
||||||
|
|
||||||
push @$setValues, [@vals]; |
|
||||||
} elsif ($_=~/^\s*(\w+)\s*$/) { |
|
||||||
#special terminal classes form: name |
|
||||||
$terminals[$#terminals + 1] = $1 |
|
||||||
} elsif ($_=~/^\s*(#.*)?$/) { |
|
||||||
#ignore empty line |
|
||||||
} else { |
|
||||||
print "unknown line: $_"; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
for ($i=0; $i <= $#keywords; $i++) { |
|
||||||
$upperKeywords[$i] = uc $keywords[$i]; |
|
||||||
} |
|
||||||
sort (ascend @upperKeywords); |
|
||||||
|
|
||||||
|
|
||||||
sort (ascend @keywords); |
|
||||||
print "done.\n"; |
|
||||||
|
|
||||||
#write output |
|
||||||
print "writing output files.\nIf your computer doesn’t respond, then press \"Ctrl-Alt-Delete\"\n"; |
|
||||||
print "\n"; |
|
||||||
&write_keywordfile; |
|
||||||
print "\n"; |
|
||||||
&write_tokensfile; |
|
||||||
print "\n"; |
|
||||||
&write_atgtokensfile; |
|
||||||
print "\n"; |
|
||||||
&write_unittests; |
|
||||||
print "finished.\n"; |
|
||||||
|
|
||||||
sub write_keywordfile |
|
||||||
{ |
|
||||||
print " ->Generating Keywords class to file '$keywords_outfile'\n"; |
|
||||||
open(DAT,">$keywords_outfile") || die("Cannot Open File"); |
|
||||||
print DAT "// this file was autogenerated by a tool.\n"; |
|
||||||
print DAT "using System;\n"; |
|
||||||
print DAT "\n"; |
|
||||||
print DAT "namespace " . $properties{'Namespace'} . "\n"; |
|
||||||
print DAT "{\n"; |
|
||||||
print DAT "\tpublic static class Keywords\n"; |
|
||||||
print DAT "\t{\n"; |
|
||||||
print DAT "\t\tstatic readonly string[] keywordList = {\n"; |
|
||||||
if ($properties{'UpperCaseKeywords'} eq "True") { |
|
||||||
for ($i=0; $i <= $#upperKeywords; $i++) { |
|
||||||
print DAT "\t\t\t\"$upperKeywords[$i]\""; |
|
||||||
if ($i + 1 <= $#upperKeywords) { |
|
||||||
print DAT ","; |
|
||||||
} |
|
||||||
print DAT "\n"; |
|
||||||
} |
|
||||||
} else { |
|
||||||
for ($i=0; $i <= $#keywords; $i++) { |
|
||||||
print DAT "\t\t\t\"$keywords[$i]\""; |
|
||||||
if ($i + 1 <= $#keywords) { |
|
||||||
print DAT ","; |
|
||||||
} |
|
||||||
print DAT "\n"; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
print DAT "\t\t};\n"; |
|
||||||
print DAT "\t\t\n"; |
|
||||||
if ($properties{'UpperCaseKeywords'} eq "True") { |
|
||||||
print DAT "\t\tstatic LookupTable keywords = new LookupTable(false);\n"; |
|
||||||
} else { |
|
||||||
print DAT "\t\tstatic LookupTable keywords = new LookupTable(true);\n"; |
|
||||||
} |
|
||||||
|
|
||||||
print DAT "\t\t\n"; |
|
||||||
print DAT "\t\tstatic Keywords()\n"; |
|
||||||
print DAT "\t\t{\n"; |
|
||||||
print DAT "\t\t\tfor (int i = 0; i < keywordList.Length; ++i) {\n"; |
|
||||||
print DAT "\t\t\t\tkeywords[keywordList[i]] = i + Tokens." . ucfirst $keywords[0] . ";\n"; |
|
||||||
print DAT "\t\t\t}\n"; |
|
||||||
print DAT "\t\t}\n"; |
|
||||||
print DAT "\t\t\n"; |
|
||||||
print DAT "\t\tpublic static int GetToken(string keyword)\n"; |
|
||||||
print DAT "\t\t{\n"; |
|
||||||
print DAT "\t\t\treturn keywords[keyword];\n"; |
|
||||||
print DAT "\t\t}\n"; |
|
||||||
print DAT "\t\t\n"; |
|
||||||
print DAT "\t\tpublic static bool IsNonIdentifierKeyword(string word)\n"; |
|
||||||
print DAT "\t\t{\n"; |
|
||||||
print DAT "\t\t\tint token = GetToken(word);\n"; |
|
||||||
print DAT "\t\t\tif (token < 0)\n"; |
|
||||||
print DAT "\t\t\t\treturn false;\n"; |
|
||||||
print DAT "\t\t\treturn !Tokens.IdentifierTokens[token];\n"; |
|
||||||
print DAT "\t\t}\n"; |
|
||||||
print DAT "\t}\n"; |
|
||||||
print DAT "}\n"; |
|
||||||
close(DAT); |
|
||||||
print " ->done.\n"; |
|
||||||
} |
|
||||||
|
|
||||||
sub write_token { |
|
||||||
$formattedString = sprintf("%-20s", ucfirst $tokenName); |
|
||||||
if (($tokenName eq "GetType") or ($tokenName eq "equals") or ($tokenName eq "Equals")) { |
|
||||||
print DAT "\t\tnew public const int $formattedString = $tokenValue;\n"; |
|
||||||
} else { |
|
||||||
print DAT "\t\tpublic const int $formattedString = $tokenValue;\n"; |
|
||||||
} |
|
||||||
$tokenValue++; |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
sub print_list { |
|
||||||
local ($j, $k, $max, $index); |
|
||||||
|
|
||||||
$index = $_[0]; |
|
||||||
$max = $#{$setValues->[$index]}; |
|
||||||
|
|
||||||
for ($j=0; $j <= $max; $j++) { |
|
||||||
$_ = $setValues->[$index][$j]; |
|
||||||
if (/\"(\w+)\"/) { # Keywords |
|
||||||
print DAT ucfirst $1; |
|
||||||
} elsif (/\"(\W+)\"/) { # special chars |
|
||||||
print DAT $specialCharLookup{$_}; |
|
||||||
} elsif (/@(\w+)/) { # @otherList |
|
||||||
for ($k=0; $k <= $#sets; $k++) { |
|
||||||
if ($sets[$k] eq $1) { |
|
||||||
print_list($k); |
|
||||||
} |
|
||||||
} |
|
||||||
} else { |
|
||||||
print DAT $_; |
|
||||||
} |
|
||||||
|
|
||||||
if ($j + 1 <= $max) { |
|
||||||
print DAT ", "; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
sub write_tokensfile { |
|
||||||
print " ->Generating Tokens class to file '$tokens_outfile'\n"; |
|
||||||
open(DAT,">$tokens_outfile") || die("Cannot Open File"); |
|
||||||
print DAT "// this file was autogenerated by a tool.\n"; |
|
||||||
print DAT "using System;\n"; |
|
||||||
print DAT "using System.Collections;\n"; |
|
||||||
print DAT "\n"; |
|
||||||
print DAT "namespace " . $properties{'Namespace'} . "\n"; |
|
||||||
print DAT "{\n"; |
|
||||||
print DAT "\tpublic static class Tokens\n"; |
|
||||||
print DAT "\t{\n"; |
|
||||||
$tokenValue = 0; |
|
||||||
|
|
||||||
print DAT "\t\t// ----- terminal classes -----\n"; |
|
||||||
foreach (@terminals) { |
|
||||||
$tokenName = $_; |
|
||||||
write_token(); |
|
||||||
} |
|
||||||
print DAT "\n"; |
|
||||||
print DAT "\t\t// ----- special character -----\n"; |
|
||||||
foreach (@special_chars) { |
|
||||||
$tokenName = $_; |
|
||||||
write_token(); |
|
||||||
} |
|
||||||
print DAT "\n"; |
|
||||||
print DAT "\t\t// ----- keywords -----\n"; |
|
||||||
foreach (@keywords) { |
|
||||||
$tokenName = $_; |
|
||||||
write_token(); |
|
||||||
} |
|
||||||
print DAT "\n"; |
|
||||||
|
|
||||||
print DAT "\t\tpublic const int MaxToken = " . $tokenValue . ";\n"; |
|
||||||
|
|
||||||
#write sets. |
|
||||||
if ($#sets > 0) { |
|
||||||
print DAT "\t\tstatic BitArray NewSet(params int[] values)\n"; |
|
||||||
print DAT "\t\t{\n"; |
|
||||||
print DAT "\t\t\tBitArray bitArray = new BitArray(MaxToken);\n"; |
|
||||||
print DAT "\t\t\tforeach (int val in values) {\n"; |
|
||||||
print DAT "\t\t\tbitArray[val] = true;\n"; |
|
||||||
print DAT "\t\t\t}\n"; |
|
||||||
print DAT "\t\t\treturn bitArray;\n"; |
|
||||||
print DAT "\t\t}\n"; |
|
||||||
for ($i=0; $i <= $#sets; $i++) { |
|
||||||
print DAT "\t\tpublic static BitArray ". $sets[$i] . " = NewSet("; |
|
||||||
print_list($i); |
|
||||||
print DAT ");\n"; |
|
||||||
} |
|
||||||
print DAT "\n"; |
|
||||||
} |
|
||||||
|
|
||||||
#write token number --> string function. |
|
||||||
print DAT "\t\tstatic string[] tokenList = new string[] {\n"; |
|
||||||
print DAT "\t\t\t// ----- terminal classes -----\n"; |
|
||||||
foreach (@terminals) { |
|
||||||
print DAT "\t\t\t\"<$_>\",\n"; |
|
||||||
} |
|
||||||
print DAT "\t\t\t// ----- special character -----\n"; |
|
||||||
foreach (@special_values) { |
|
||||||
print DAT "\t\t\t$_,\n"; |
|
||||||
} |
|
||||||
print DAT "\t\t\t// ----- keywords -----\n"; |
|
||||||
foreach (@keywords) { |
|
||||||
print DAT "\t\t\t\"$_\",\n"; |
|
||||||
} |
|
||||||
print DAT "\t\t};\n"; |
|
||||||
|
|
||||||
|
|
||||||
print DAT "\t\tpublic static string GetTokenString(int token)\n"; |
|
||||||
print DAT "\t\t{\n"; |
|
||||||
print DAT "\t\t\tif (token >= 0 && token < tokenList.Length) {\n"; |
|
||||||
print DAT "\t\t\t\treturn tokenList[token];\n"; |
|
||||||
print DAT "\t\t\t}\n"; |
|
||||||
print DAT "\t\t\tthrow new System.NotSupportedException(\"Unknown token:\" + token);\n"; |
|
||||||
print DAT "\t\t}\n"; |
|
||||||
print DAT "\t}\n"; |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
print DAT "}\n"; |
|
||||||
close(DAT); |
|
||||||
print " ->done.\n"; |
|
||||||
} |
|
||||||
|
|
||||||
sub write_unittests { |
|
||||||
open(DAT,">$unittests_outfile") || die("Cannot Open File"); |
|
||||||
print DAT "using System;\n"; |
|
||||||
print DAT "using System.IO;\n"; |
|
||||||
print DAT "using NUnit.Framework;\n"; |
|
||||||
print DAT "using ICSharpCode.NRefactory.Parser;\n"; |
|
||||||
print DAT "using ICSharpCode.NRefactory.PrettyPrinter;\n"; |
|
||||||
|
|
||||||
print DAT "\n"; |
|
||||||
print DAT "namespace ICSharpCode.NRefactory.Tests.Lexer\n"; |
|
||||||
print DAT "{\n"; |
|
||||||
print DAT "\t[TestFixture]\n"; |
|
||||||
print DAT "\tpublic sealed class LexerTests\n"; |
|
||||||
print DAT "\t{\n"; |
|
||||||
print DAT "\t\tILexer GenerateLexer(StringReader sr)\n"; |
|
||||||
print DAT "\t\t{\n"; |
|
||||||
print DAT "\t\t\treturn ParserFactory.CreateLexer(SupportedLanguage.CSharp, sr);\n"; |
|
||||||
print DAT "\t\t}\n\n"; |
|
||||||
|
|
||||||
for ($i=0; $i <= $#special_values; $i++) { |
|
||||||
|
|
||||||
print DAT "\t\t[Test]\n"; |
|
||||||
print DAT "\t\tpublic void Test" . $special_chars[$i] ."()\n"; |
|
||||||
print DAT "\t\t{\n"; |
|
||||||
print DAT "\t\t\tILexer lexer = GenerateLexer(new StringReader(" . $special_values[$i] . "));\n"; |
|
||||||
print DAT "\t\t\tAssert.AreEqual(Tokens." . $special_chars[$i] . ", lexer.NextToken().kind);\n"; |
|
||||||
print DAT "\t\t}\n\n"; |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
foreach (@keywords) { |
|
||||||
print DAT "\t\t[Test()]\n"; |
|
||||||
print DAT "\t\tpublic void Test" . ucfirst $_ ."()\n"; |
|
||||||
print DAT "\t\t{\n"; |
|
||||||
print DAT "\t\t\tILexer lexer = GenerateLexer(new StringReader(\"" . $_ . "\"));\n"; |
|
||||||
print DAT "\t\t\tAssert.AreEqual(Tokens." . ucfirst $_ . ", lexer.NextToken().kind);\n"; |
|
||||||
print DAT "\t\t}\n"; |
|
||||||
} |
|
||||||
|
|
||||||
print DAT "\t}\n"; |
|
||||||
print DAT "}\n"; |
|
||||||
|
|
||||||
|
|
||||||
close(DAT); |
|
||||||
} |
|
||||||
|
|
||||||
sub write_atgtokensfile { |
|
||||||
print " ->Generating ATG TOKENS section and writing it to file '$ATGTokensSection'\n"; |
|
||||||
open(DAT,">$ATGTokensSection") || die("Cannot Open File"); |
|
||||||
print DAT "/* START AUTOGENERATED TOKENS SECTION */\n"; |
|
||||||
print DAT "TOKENS\n"; |
|
||||||
|
|
||||||
print DAT "\t/* ----- terminal classes ----- */\n"; |
|
||||||
print DAT "\t/* EOF is 0 */\n"; |
|
||||||
foreach $term (@terminals) { |
|
||||||
if ($term eq "EOF") { |
|
||||||
} elsif ($term eq "Identifier") { |
|
||||||
print DAT "\tident\n"; |
|
||||||
} else { |
|
||||||
print DAT "\t$term\n"; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
print DAT "\n"; |
|
||||||
print DAT "\t/* ----- special character ----- */\n"; |
|
||||||
foreach (@special_values) { |
|
||||||
print DAT "\t$_\n"; |
|
||||||
} |
|
||||||
print DAT "\n"; |
|
||||||
print DAT "\t/* ----- keywords ----- */\n"; |
|
||||||
foreach (@keywords) { |
|
||||||
print DAT "\t\"$_\"\n"; |
|
||||||
} |
|
||||||
|
|
||||||
print DAT "/* END AUTOGENERATED TOKENS SECTION */\n"; |
|
||||||
close(DAT); |
|
||||||
print " ->done.\n"; |
|
||||||
} |
|
||||||
|
|
||||||
Loading…
Reference in new issue