Timur Sağlam 4 лет назад
Родитель
Сommit
c2a366897d

+ 423 - 0
jplag.frontend.csharp-6/src/main/java/de/jplag/csharp/CSharpListener.java

@@ -0,0 +1,423 @@
+package de.jplag.csharp;
+
+import org.antlr.v4.runtime.Token;
+
+import de.jplag.csharp.grammar.CSharpParser.Array_initializerContext;
+import de.jplag.csharp.grammar.CSharpParser.Assignment_operatorContext;
+import de.jplag.csharp.grammar.CSharpParser.AttributeContext;
+import de.jplag.csharp.grammar.CSharpParser.BreakStatementContext;
+import de.jplag.csharp.grammar.CSharpParser.Catch_clausesContext;
+import de.jplag.csharp.grammar.CSharpParser.CheckedStatementContext;
+import de.jplag.csharp.grammar.CSharpParser.Class_bodyContext;
+import de.jplag.csharp.grammar.CSharpParser.Class_definitionContext;
+import de.jplag.csharp.grammar.CSharpParser.Constant_declaratorContext;
+import de.jplag.csharp.grammar.CSharpParser.Constructor_declarationContext;
+import de.jplag.csharp.grammar.CSharpParser.ContinueStatementContext;
+import de.jplag.csharp.grammar.CSharpParser.Delegate_definitionContext;
+import de.jplag.csharp.grammar.CSharpParser.Destructor_definitionContext;
+import de.jplag.csharp.grammar.CSharpParser.DoStatementContext;
+import de.jplag.csharp.grammar.CSharpParser.Enum_bodyContext;
+import de.jplag.csharp.grammar.CSharpParser.Enum_definitionContext;
+import de.jplag.csharp.grammar.CSharpParser.Enum_member_declarationContext;
+import de.jplag.csharp.grammar.CSharpParser.Event_declarationContext;
+import de.jplag.csharp.grammar.CSharpParser.Finally_clauseContext;
+import de.jplag.csharp.grammar.CSharpParser.FixedStatementContext;
+import de.jplag.csharp.grammar.CSharpParser.ForStatementContext;
+import de.jplag.csharp.grammar.CSharpParser.ForeachStatementContext;
+import de.jplag.csharp.grammar.CSharpParser.GotoStatementContext;
+import de.jplag.csharp.grammar.CSharpParser.IfStatementContext;
+import de.jplag.csharp.grammar.CSharpParser.If_bodyContext;
+import de.jplag.csharp.grammar.CSharpParser.Indexer_declarationContext;
+import de.jplag.csharp.grammar.CSharpParser.Interface_bodyContext;
+import de.jplag.csharp.grammar.CSharpParser.Interface_definitionContext;
+import de.jplag.csharp.grammar.CSharpParser.LockStatementContext;
+import de.jplag.csharp.grammar.CSharpParser.Method_bodyContext;
+import de.jplag.csharp.grammar.CSharpParser.Method_declarationContext;
+import de.jplag.csharp.grammar.CSharpParser.Method_invocationContext;
+import de.jplag.csharp.grammar.CSharpParser.Namespace_bodyContext;
+import de.jplag.csharp.grammar.CSharpParser.Object_creation_expressionContext;
+import de.jplag.csharp.grammar.CSharpParser.Operator_declarationContext;
+import de.jplag.csharp.grammar.CSharpParser.Property_declarationContext;
+import de.jplag.csharp.grammar.CSharpParser.ReturnStatementContext;
+import de.jplag.csharp.grammar.CSharpParser.Struct_bodyContext;
+import de.jplag.csharp.grammar.CSharpParser.Struct_definitionContext;
+import de.jplag.csharp.grammar.CSharpParser.SwitchStatementContext;
+import de.jplag.csharp.grammar.CSharpParser.Switch_expressionContext;
+import de.jplag.csharp.grammar.CSharpParser.ThrowStatementContext;
+import de.jplag.csharp.grammar.CSharpParser.TryStatementContext;
+import de.jplag.csharp.grammar.CSharpParser.UncheckedExpressionContext;
+import de.jplag.csharp.grammar.CSharpParser.UnsafeStatementContext;
+import de.jplag.csharp.grammar.CSharpParser.UsingStatementContext;
+import de.jplag.csharp.grammar.CSharpParser.Using_directivesContext;
+import de.jplag.csharp.grammar.CSharpParser.Variable_declaratorContext;
+import de.jplag.csharp.grammar.CSharpParser.WhileStatementContext;
+import de.jplag.csharp.grammar.CSharpParserBaseListener;
+
+/**
+ * Listener class for visiting the C# ANTLR parse tree. Transforms selected ANTLR token into JPlag tokens.
+ * @author Timur Saglam
+ */
+public class CSharpListener extends CSharpParserBaseListener implements CSharpTokenConstants {
+
+    private final CSharpParserAdapter parserAdapter;
+
+    /**
+     * Creates the listener.
+     * @param parserAdapter is the JPlag parser adapter which receives the transformed tokens.
+     */
+    public CSharpListener(CSharpParserAdapter parserAdapter) {
+        this.parserAdapter = parserAdapter;
+    }
+
+    /**
+     * Transforms an ANTLR Token into a JPlag token and transfers it to the token adapter.
+     * @param targetType is the type of the JPlag token to be created.
+     * @param token is the ANTLR token.
+     */
+    private void transformToken(int targetType, Token token) {
+        parserAdapter.addToken(targetType, token.getLine(), token.getCharPositionInLine() + 1, token.getText().length());
+    }
+
+    @Override
+    public void enterMethod_invocation(Method_invocationContext context) {
+        transformToken(INVOCATION, context.getStart());
+        super.enterMethod_invocation(context);
+    }
+
+    @Override
+    public void enterObject_creation_expression(Object_creation_expressionContext context) {
+        transformToken(OBJECT_CREATION, context.getStart());
+        super.enterObject_creation_expression(context);
+    }
+
+    @Override
+    public void enterArray_initializer(Array_initializerContext context) {
+        transformToken(ARRAY_CREATION, context.getStart());
+        super.enterArray_initializer(context);
+    }
+
+    @Override
+    public void enterAssignment_operator(Assignment_operatorContext context) {
+        transformToken(ASSIGNMENT, context.getStart());
+        super.enterAssignment_operator(context);
+    }
+
+    @Override
+    public void enterVariable_declarator(Variable_declaratorContext context) {
+        transformToken(DECLARE_VAR, context.getStart());
+        super.enterVariable_declarator(context);
+    }
+
+    @Override
+    public void enterConstant_declarator(Constant_declaratorContext context) {
+        transformToken(DECLARE_CONST, context.getStart());
+        super.enterConstant_declarator(context);
+    }
+
+    @Override
+    public void enterIfStatement(IfStatementContext context) {
+        transformToken(IF, context.getStart());
+        super.enterIfStatement(context);
+    }
+
+    @Override
+    public void enterIf_body(If_bodyContext context) {
+        transformToken(IF_BEGIN, context.getStart());
+        super.enterIf_body(context);
+    }
+
+    @Override
+    public void exitIf_body(If_bodyContext context) {
+        transformToken(END_IF, context.getStop());
+        super.exitIf_body(context);
+    }
+
+    @Override
+    public void enterSwitch_expression(Switch_expressionContext context) {
+        transformToken(SWITCH_BEGIN, context.getStart());
+        super.enterSwitch_expression(context);
+    }
+
+    @Override
+    public void exitSwitch_expression(Switch_expressionContext context) {
+        transformToken(SWITCH_END, context.getStop());
+        super.exitSwitch_expression(context);
+    }
+
+    @Override
+    public void enterSwitchStatement(SwitchStatementContext context) {
+        transformToken(CASE, context.getStart());
+        super.enterSwitchStatement(context);
+    }
+
+    @Override
+    public void enterDoStatement(DoStatementContext context) {
+        transformToken(DO, context.getStart());
+        super.enterDoStatement(context);
+    }
+
+    @Override
+    public void enterWhileStatement(WhileStatementContext context) {
+        transformToken(WHILE, context.getStart());
+        super.enterWhileStatement(context);
+    }
+
+    @Override
+    public void enterForStatement(ForStatementContext context) {
+        transformToken(FOR, context.getStart());
+        super.enterForStatement(context);
+    }
+
+    @Override
+    public void enterForeachStatement(ForeachStatementContext context) {
+        transformToken(FOREACH, context.getStart());
+        super.enterForeachStatement(context);
+    }
+
+    @Override
+    public void enterBreakStatement(BreakStatementContext context) {
+        transformToken(BREAK, context.getStart());
+        super.enterBreakStatement(context);
+    }
+
+    @Override
+    public void enterContinueStatement(ContinueStatementContext context) {
+        transformToken(CONTINUE, context.getStart());
+        super.enterContinueStatement(context);
+    }
+
+    @Override
+    public void enterGotoStatement(GotoStatementContext context) {
+        transformToken(GOTO, context.getStart());
+        super.enterGotoStatement(context);
+    }
+
+    @Override
+    public void enterReturnStatement(ReturnStatementContext context) {
+        transformToken(RETURN, context.getStart());
+        super.enterReturnStatement(context);
+    }
+
+    @Override
+    public void enterThrowStatement(ThrowStatementContext context) {
+        transformToken(THROW, context.getStart());
+        super.enterThrowStatement(context);
+    }
+
+    @Override
+    public void enterCheckedStatement(CheckedStatementContext context) {
+        transformToken(CHECKED, context.getStart());
+        super.enterCheckedStatement(context);
+    }
+
+    @Override
+    public void enterUncheckedExpression(UncheckedExpressionContext context) {
+        transformToken(UNCHECKED, context.getStart());
+        super.enterUncheckedExpression(context);
+    }
+
+    @Override
+    public void enterLockStatement(LockStatementContext context) {
+        transformToken(LOCK, context.getStart());
+        super.enterLockStatement(context);
+    }
+
+    @Override
+    public void enterUsingStatement(UsingStatementContext context) {
+        transformToken(USING, null);
+        super.enterUsingStatement(context);
+    }
+
+    @Override
+    public void enterTryStatement(TryStatementContext context) {
+        transformToken(TRY, context.getStart());
+        super.enterTryStatement(context);
+    }
+
+    @Override
+    public void enterCatch_clauses(Catch_clausesContext context) {
+        transformToken(CATCH, context.getStart());
+        super.enterCatch_clauses(context);
+    }
+
+    @Override
+    public void enterFinally_clause(Finally_clauseContext context) {
+        transformToken(FINALLY, context.getStart());
+        super.enterFinally_clause(context);
+    }
+
+    @Override
+    public void enterNamespace_body(Namespace_bodyContext context) {
+        transformToken(NAMESPACE_BEGIN, context.getStart());
+        super.enterNamespace_body(context);
+    }
+
+    @Override
+    public void exitNamespace_body(Namespace_bodyContext context) {
+        transformToken(NAMESPACE_END, context.getStop());
+        super.exitNamespace_body(context);
+    }
+
+    @Override
+    public void enterUsing_directives(Using_directivesContext context) {
+        transformToken(USING_DIRECTIVE, context.getStart());
+        super.enterUsing_directives(context);
+    }
+
+    @Override
+    public void enterClass_definition(Class_definitionContext context) {
+        transformToken(CLASS, context.getStart());
+        super.enterClass_definition(context);
+    }
+
+    @Override
+    public void enterClass_body(Class_bodyContext context) {
+        transformToken(CLASS_BEGIN, context.getStart());
+        super.enterClass_body(context);
+    }
+
+    @Override
+    public void exitClass_body(Class_bodyContext context) {
+        transformToken(CLASS_END, context.getStop());
+        super.exitClass_body(context);
+    }
+
+    @Override
+    public void enterMethod_declaration(Method_declarationContext context) {
+        transformToken(METHOD, context.getStart());
+        super.enterMethod_declaration(context);
+    }
+
+    @Override
+    public void enterMethod_body(Method_bodyContext context) {
+        transformToken(METHOD_BEGIN, context.getStart());
+        super.enterMethod_body(context);
+    }
+
+    @Override
+    public void exitMethod_body(Method_bodyContext context) {
+        transformToken(METHOD_END, context.getStop());
+        super.exitMethod_body(context);
+    }
+
+    @Override
+    public void enterProperty_declaration(Property_declarationContext context) {
+        transformToken(PROPERTY, context.getStart());
+        super.enterProperty_declaration(context);
+    }
+
+    @Override
+    public void enterEvent_declaration(Event_declarationContext context) {
+        transformToken(EVENT, context.getStart());
+        super.enterEvent_declaration(context);
+    }
+
+    @Override
+    public void enterIndexer_declaration(Indexer_declarationContext context) {
+        transformToken(INDEXER, context.getStart());
+        super.enterIndexer_declaration(context);
+    }
+
+    @Override
+    public void enterOperator_declaration(Operator_declarationContext context) {
+        transformToken(OPERATOR, context.getStart());
+        super.enterOperator_declaration(context);
+    }
+
+    @Override
+    public void enterConstructor_declaration(Constructor_declarationContext context) {
+        transformToken(CONSTRUCTOR, context.getStart());
+        super.enterConstructor_declaration(context);
+    }
+
+    @Override
+    public void enterDestructor_definition(Destructor_definitionContext context) {
+        transformToken(DESTRUCTOR, context.getStart());
+        super.enterDestructor_definition(context);
+    }
+
+    @Override
+    public void enterStruct_definition(Struct_definitionContext context) {
+        transformToken(STRUCT, context.getStart());
+        super.enterStruct_definition(context);
+    }
+
+    @Override
+    public void enterStruct_body(Struct_bodyContext context) {
+        transformToken(STRUCT_BEGIN, context.getStart());
+        super.enterStruct_body(context);
+    }
+
+    @Override
+    public void exitStruct_body(Struct_bodyContext context) {
+        transformToken(STRUCT_END, context.getStop());
+        super.exitStruct_body(context);
+    }
+
+    @Override
+    public void enterInterface_definition(Interface_definitionContext context) {
+        transformToken(INTERFACE, context.getStart());
+        super.enterInterface_definition(context);
+    }
+
+    @Override
+    public void enterInterface_body(Interface_bodyContext context) {
+        transformToken(INTERFACE_BEGIN, context.getStart());
+        super.enterInterface_body(context);
+    }
+
+    @Override
+    public void exitInterface_body(Interface_bodyContext context) {
+        transformToken(INTERFACE_END, context.getStart());
+        super.exitInterface_body(context);
+    }
+
+    @Override
+    public void enterEnum_definition(Enum_definitionContext context) {
+        transformToken(ENUM, context.getStart());
+        super.enterEnum_definition(context);
+    }
+
+    @Override
+    public void enterEnum_body(Enum_bodyContext context) {
+        transformToken(ENUM_BEGIN, context.getStart());
+        super.enterEnum_body(context);
+    }
+
+    @Override
+    public void exitEnum_body(Enum_bodyContext context) {
+        transformToken(ENUM_END, context.getStop());
+        super.exitEnum_body(context);
+    }
+
+    @Override
+    public void enterEnum_member_declaration(Enum_member_declarationContext context) {
+        transformToken(ENUMERAL, context.getStart());
+        super.enterEnum_member_declaration(context);
+    }
+
+    @Override
+    public void enterAttribute(AttributeContext context) {
+        transformToken(ATTRIBUTE, context.getStart());
+        super.enterAttribute(context);
+    }
+
+    @Override
+    public void enterDelegate_definition(Delegate_definitionContext context) {
+        transformToken(DELEGATE, context.getStart());
+        super.enterDelegate_definition(context);
+    }
+
+    @Override
+    public void enterUnsafeStatement(UnsafeStatementContext context) {
+        transformToken(UNSAFE, context.getStart());
+        super.enterUnsafeStatement(context);
+    }
+
+    @Override
+    public void enterFixedStatement(FixedStatementContext context) {
+        transformToken(FIXED, context.getStart());
+        super.enterFixedStatement(context);
+    }
+
+}

+ 84 - 0
jplag.frontend.csharp-6/src/main/java/de/jplag/csharp/CSharpParserAdapter.java

@@ -0,0 +1,84 @@
+package de.jplag.csharp;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.List;
+
+import org.antlr.v4.runtime.CharStreams;
+import org.antlr.v4.runtime.CommonTokenStream;
+import org.antlr.v4.runtime.ParserRuleContext;
+import org.antlr.v4.runtime.tree.ParseTree;
+import org.antlr.v4.runtime.tree.ParseTreeWalker;
+
+import de.jplag.AbstractParser;
+import de.jplag.ErrorConsumer;
+import de.jplag.TokenList;
+import de.jplag.csharp.grammar.CSharpLexer;
+import de.jplag.csharp.grammar.CSharpParser;
+
+/**
+ * Parser adapter for the ANTLR 4 CSharp Parser and Lexer. It receives file to parse and passes them to the ANTLR
+ * pipeline. Then it walks the produced parse tree and creates JPlag token with the {@link CSharpListener}.
+ * @author Timur Saglam
+ */
+public class CSharpParserAdapter extends AbstractParser {
+    private TokenList tokens;
+    private String currentFile;
+
+    /**
+     * Creates the parser adapter.
+     * @param errorConsumer is the consumer for any occurring errors.
+     */
+    public CSharpParserAdapter(ErrorConsumer errorConsumer) {
+        super(errorConsumer);
+    }
+
+    /**
+     * Parses all tokens form a list of files.
+     * @param directory is the base directory.
+     * @param fileNames is the list of file names.
+     * @return the list of parsed tokens.
+     */
+    public TokenList parse(File directory, List<String> fileNames) {
+        tokens = new TokenList();
+        errors = 0;
+        for (String fileName : fileNames) {
+            if (!parseFile(directory, fileName)) {
+                errors++;
+            }
+            tokens.addToken(new CSharpToken(CSharpTokenConstants.FILE_END, fileName, -1, -1, -1));
+        }
+        return tokens;
+    }
+
+    private boolean parseFile(File directory, String fileName) {
+        File file = new File(directory, fileName);
+        try (FileInputStream inputStream = new FileInputStream(file);) {
+            currentFile = fileName;
+
+            // create a lexer, a parser and a buffer between them.
+            CSharpLexer lexer = new CSharpLexer(CharStreams.fromStream(inputStream));
+            CommonTokenStream tokens = new CommonTokenStream(lexer);
+            CSharpParser parser = new CSharpParser(tokens);
+
+            // Create a tree walker and rule context
+            ParserRuleContext ruleContext = parser.getRuleContext();
+            ParseTreeWalker treeWalker = new ParseTreeWalker();
+
+            // Walk over the parse tree:
+            for (int i = 0; i < ruleContext.getChildCount(); i++) {
+                ParseTree parseTree = ruleContext.getChild(i);
+                treeWalker.walk(new CSharpListener(this), parseTree);
+            }
+        } catch (IOException exception) {
+            getErrorConsumer().addError("Parsing Error in '" + fileName + "':" + File.separator + exception.toString());
+            return false;
+        }
+        return true;
+    }
+
+    /* package-private */ void addToken(int type, int line, int column, int length) {
+        tokens.addToken(new CSharpToken(type, currentFile, line, column, length));
+    }
+}

+ 90 - 0
jplag.frontend.csharp-6/src/main/java/de/jplag/csharp/CSharpToken.java

@@ -0,0 +1,90 @@
+package de.jplag.csharp;
+
+import de.jplag.Token;
+import de.jplag.TokenConstants;
+
+/**
+ * C# token class.
+ * @author Timur Saglam
+ */
+public class CSharpToken extends Token implements CSharpTokenConstants {
+
+    /**
+     * Creates a C# token.
+     * @param type is the corresponding ID of the {@link TokenConstants}.
+     * @param file is the name of the source code file.
+     * @param line is the line index in the source code where the token resides. Cannot be smaller than 1.
+     * @param column is the column index, meaning where the token starts in the line.
+     * @param length is the length of the token in the source code.
+     */
+    public CSharpToken(int type, String file, int line, int column, int length) {
+        super(type, file, line, column, length);
+    }
+
+    @Override
+    protected String type2string() {
+        return switch (type) {
+            case TokenConstants.FILE_END -> "EOF";
+            case INVOCATION -> "INVOC";
+            case OBJECT_CREATION -> "OBJECT";
+            case ARRAY_CREATION -> "ARRAY";
+            case ASSIGNMENT -> "ASSIGN";
+            case DECLARE_VAR -> "VAR";
+            case DECLARE_CONST -> "CONST";
+            case IF -> "IF";
+            case ELSE -> "ELSE";
+            case END_IF -> "}IF";
+            case SWITCH_BEGIN -> "SWITCH{";
+            case SWITCH_END -> "}SWITCH";
+            case CASE -> "CASE";
+            case DO -> "DO";
+            case WHILE -> "WHILE";
+            case FOR -> "FOR";
+            case FOREACH -> "FOREACH";
+            case BREAK -> "BREAK";
+            case CONTINUE -> "CONTINUE";
+            case GOTO -> "GOTO";
+            case RETURN -> "RETURN";
+            case THROW -> "THROW";
+            case CHECKED -> "CHECKED";
+            case UNCHECKED -> "UNCHECKED";
+            case LOCK -> "LOCK";
+            case USING -> "USING";
+            case TRY -> "TRY";
+            case CATCH -> "CATCH";
+            case FINALLY -> "FINALLY";
+            case NAMESPACE_BEGIN -> "NAMESPACE{";
+            case NAMESPACE_END -> "}NAMESPACE";
+            case USING_DIRECTIVE -> "USING";
+            case CLASS_BEGIN -> "CLASS{";
+            case CLASS_END -> "}CLASS";
+            case METHOD -> "METHOD";
+            case PROPERTY -> "PROPERTY";
+            case EVENT -> "EVENT";
+            case INDEXER -> "INDEXER";
+            case OPERATOR -> "OPERATOR";
+            case CONSTRUCTOR -> "CONSTR";
+            case DESTRUCTOR -> "DESTRUCTOR";
+            case STRUCT_BEGIN -> "STRUCT{";
+            case STRUCT_END -> "}STRUCT";
+            case INTERFACE_BEGIN -> "INTERFACE{";
+            case INTERFACE_END -> "}INTERFACE";
+            case ENUM -> "ENUM";
+            case DELEGATE -> "DELEGATE";
+            case ATTRIBUTE -> "ATTRIBUTE";
+            case UNSAFE -> "UNSAFE";
+            case FIXED -> "FIXED";
+            // new:
+            case METHOD_BEGIN -> "METHOD{";
+            case METHOD_END -> "}METHOD";
+            case STRUCT -> "STRUCT";
+            case IF_BEGIN -> "IF{";
+            case CLASS -> "CLASS";
+            case INTERFACE -> "INTERFACE";
+            case ENUM_BEGIN -> "ENUM{";
+            case ENUM_END -> "}ENUM";
+            case ENUMERAL -> "ENUMERAL";
+            default -> "<UNKNOWN>";
+        };
+    }
+}

+ 78 - 0
jplag.frontend.csharp-6/src/main/java/de/jplag/csharp/CSharpTokenConstants.java

@@ -0,0 +1,78 @@
+package de.jplag.csharp;
+
+import de.jplag.TokenConstants;
+
+/**
+ * Based on the legacy CSharp-1.2 constants. The constants L_BRACE, R_BRACE, and STATIC_CONSTR were removed. Moreover,
+ * the following constants were added: METHOD_BEGIN, METHOD_END, STRUCT, IF_BEGIN, CLASS, INTERFACE, ENUM_BEGIN,
+ * ENUM_END and ENUMERAL.
+ * @author Timur Saglam
+ */
+public interface CSharpTokenConstants extends TokenConstants {
+    /*
+     * Token constants:
+     */
+    int INVOCATION = 2;
+    int OBJECT_CREATION = 3;
+    int ARRAY_CREATION = 4;
+    int ASSIGNMENT = 5;
+    int DECLARE_VAR = 6;
+    int DECLARE_CONST = 7;
+    int IF = 8;
+    int ELSE = 9; // TODO TS does not exist
+    int SWITCH_BEGIN = 10;
+    int SWITCH_END = 11;
+    int CASE = 12;
+    int DO = 13;
+    int WHILE = 14;
+    int FOR = 15;
+    int FOREACH = 16;
+    int BREAK = 17;
+    int CONTINUE = 18;
+    int GOTO = 19;
+    int RETURN = 20;
+    int THROW = 21;
+    int CHECKED = 22;
+    int UNCHECKED = 23;
+    int LOCK = 24;
+    int USING = 25;
+    int TRY = 26;
+    int CATCH = 27;
+    int FINALLY = 28;
+    int NAMESPACE_BEGIN = 29;
+    int NAMESPACE_END = 30;
+    int USING_DIRECTIVE = 31;
+    int CLASS_BEGIN = 32;
+    int CLASS_END = 33;
+    int METHOD = 34;
+    int PROPERTY = 35;
+    int EVENT = 36;
+    int INDEXER = 37;
+    int OPERATOR = 38;
+    int CONSTRUCTOR = 39;
+    int DESTRUCTOR = 40;
+    int STRUCT_BEGIN = 41;
+    int STRUCT_END = 42;
+    int INTERFACE_BEGIN = 43;
+    int INTERFACE_END = 44;
+    int ENUM = 45;
+    int DELEGATE = 46;
+    int ATTRIBUTE = 47;
+    int END_IF = 48;
+    int UNSAFE = 49;
+    int FIXED = 50;
+    int METHOD_BEGIN = 51;
+    int METHOD_END = 52;
+    int STRUCT = 53;
+    int IF_BEGIN = 54;
+    int CLASS = 55;
+    int INTERFACE = 56;
+    int ENUM_BEGIN = 57;
+    int ENUM_END = 58;
+    int ENUMERAL = 59;
+
+    /*
+     * Number of token constants:
+     */
+    int NUM_DIFF_TOKENS = 61;
+}

+ 69 - 0
jplag.frontend.csharp-6/src/main/java/de/jplag/csharp/Language.java

@@ -0,0 +1,69 @@
+package de.jplag.csharp;
+
+import java.io.File;
+import java.util.Arrays;
+
+import de.jplag.ErrorConsumer;
+import de.jplag.TokenList;
+
+/**
+ * C# language with full support of C# 6 features and below.
+ * @author Timur Saglam
+ */
+public class Language implements de.jplag.Language {
+    private final CSharpParserAdapter parser;
+
+    public Language(ErrorConsumer program) {
+        parser = new CSharpParserAdapter(program);
+    }
+
+    @Override
+    public String[] suffixes() {
+        return new String[] {".cs", ".CS"};
+    }
+
+    @Override
+    public String getName() {
+        return "C# 6 Parser";
+    }
+
+    @Override
+    public String getShortName() {
+        return "C# 6";
+    }
+
+    @Override
+    public int minimumTokenMatch() {
+        return 8;
+    }
+
+    @Override
+    public TokenList parse(File dir, String[] files) {
+        return this.parser.parse(dir, Arrays.asList(files));
+    }
+
+    @Override
+    public boolean hasErrors() {
+        return parser.hasErrors();
+    }
+
+    @Override
+    public boolean supportsColumns() {
+        return true;
+    }
+
+    @Override
+    public boolean isPreformatted() {
+        return false;
+    }
+
+    @Override
+    public boolean usesIndex() {
+        return false;
+    }
+
+    @Override
+    public int numberOfTokens() {
+        return CSharpTokenConstants.NUM_DIFF_TOKENS;
+    }
+}