Das Projekt ist ein Compiler, der ein in C# geschriebenes Quellprogramm (Eingabe) nimmt und es dann in ein in Visual Basic geschriebenes Zielprogramm (Ausgabe) übersetzt. Dieser Prozess erfolgt durch das Durchlaufen von drei Modulen ( Tokenizer
, Parser
und Translator
). Jedes Modul wird in diesem Bericht separat erläutert.
Tokenizer/Lexical Analyzer ist ein Programm, das eine Folge von Zeichen (Eingabe) nimmt und eine Folge von Token ausgibt (Ausgabe).
Der Tokenizer verfügt über eine Liste mit Definitionen für jedes mögliche Token, das er durch Gruppieren einer Zeichenfolge erzeugen kann. Jede Token-Definition besteht aus:
Die folgenden Tabellen stellen alle im Projekt verwendeten Definitionen dar, mit einem Beispiel für übereinstimmende Werte für jede einzelne.
Typ | Regulärer Ausdruck | Übereinstimmende(r) Wert(e) |
---|---|---|
Benutzen | verwenden | using |
Klasse | Klasse | class |
Wenn | Wenn | if |
Anders | anders | else |
Für | für | for |
Tun | Tun | do |
Während | während | while |
Schalten | schalten | switch |
Fall | Fall | case |
Brechen | brechen | break |
Standard | Standard | default |
Zurückkehren | zurückkehren | return |
Null | null | null |
WAHR | WAHR | true |
FALSCH | FALSCH | false |
FALSCH | (void | var) | (bool | char | short | int | long | float | double | decimal | string | String) ([] | ?)? | void bool char? int[] |
Typ | Regulärer Ausdruck | Übereinstimmende(r) Wert(e) |
---|---|---|
Nummer | d*.d+ | d+ | 77 .25 3.14 |
Zeichenfolge | „[^“]*“ | "This is string" |
Kennung | [a-zA-Z_]w* | fact _private iD_1 |
Kommentar | (?<=//) .*? (?=(r | n | //)) | // inline comment |
Mehrzeiliger Kommentar | (?<=/*) (?:(?!*/)(?:.|[rn]))* (?=*/) | /*multi line comment */ |
Typ | Regulärer Ausdruck | Übereinstimmende(r) Wert(e) |
---|---|---|
Und | && | & | && & |
Oder | || | | | || | |
Nicht | ! | ! |
Gleich | = | = |
PlusGleich | += | += |
MinusGleich | -= | -= |
DoubleEquals | == | == |
Nicht gleich | != | != |
Weniger als | < | < |
Größer als | > | > |
LessThanOrEqual | <= | <= |
Größer als oder gleich | >= | >= |
Typ | Regulärer Ausdruck | Übereinstimmende(r) Wert(e) |
---|---|---|
OpenRoundBracket | ( | ( |
CloseRoundBracket | ) | ) |
OpenCurlyBracket | { | { |
CloseCurlyBracket | } | } |
OpenSquareBracket | [ | [ |
CloseSquareBracket | ] | ] |
Plus | + | + |
Minus | - | - |
DoublePluses | ++ | ++ |
DoubleMinuses | -- | -- |
Prozent | % | % |
Sternchen | * | * |
Backslash | \ |
|
Schrägstrich | / | / |
DoubleForwardSlashes | // | // |
ForwardSlashAsterisk | /* | /* |
AsteriskForwardSlash | */ | */ |
Punkt | . | . |
Komma | , | , |
Doppelpunkt | : | : |
Semikolon | ; | ; |
Alle diese Tokentypen sind in der Datei TokenType.cs als Enumeration gruppiert.
public enum TokenType
{
// Keywords
Using , // using
Class , // class
If , // if
Else , // else
For , // for
Do , // do
While , // while
Switch , // switch
Case , // case
Break , // break
Default , // default
Return , // return
Null , // null
True , // true
False , // false
DataType , // void | bool | char? | int[]
// Values
Number , // 77 | .25 | 3.14
String , // "I am 'Moaz'"
Comment , // Any Character After (//) and Before (r | n | //)
Identifier , // fact | _private | iD_1
MultilineComment , // Any Character After (/*) and Before (*/)
// Operators
And , // && | &
Or , // || | |
Not , // !
Equal , // =
PlusEqual , // +=
MinusEqual , // -=
DoubleEquals , // ==
NotEqual , // !=
LessThan , // <
GreaterThan , // >
LessThanOrEqual , // <=
GreaterThanOrEqual , // >=
// Symbols
OpenRoundBracket , // (
CloseRoundBracket , // )
OpenCurlyBracket , // {
CloseCurlyBracket , // }
OpenSquareBracket , // [
CloseSquareBracket , // ]
Plus , // +
Minus , // -
DoublePluses , // ++
DoubleMinuses , // --
Percent , // %
Asterisk , // *
BackSlash , //
ForwardSlash , // /
DoubleForwardSlashes , // //
ForwardSlashAsterisk , // /*
AsteriskForwardSlash , // */
Dot , // .
Comma , // ,
Colon , // :
Semicolon // ;
}
und ihre Definitionen werden unter List<TokenDefinition> in der Datei Tokenizer.cs erstellt und gespeichert.
private readonly List < TokenDefinition > _tokenDefinitions = new List < TokenDefinition >
{
// Keywords
new TokenDefinition ( TokenType . Using , @"using" ) ,
new TokenDefinition ( TokenType . Class , @"class" ) ,
new TokenDefinition ( TokenType . If , @"if" ) ,
new TokenDefinition ( TokenType . Else , @"else" ) ,
new TokenDefinition ( TokenType . For , @"for" ) ,
new TokenDefinition ( TokenType . Do , @"do" , 1 ) ,
new TokenDefinition ( TokenType . While , @"while" ) ,
new TokenDefinition ( TokenType . Switch , @"switch" ) ,
new TokenDefinition ( TokenType . Case , @"case" ) ,
new TokenDefinition ( TokenType . Default , @"default" ) ,
new TokenDefinition ( TokenType . Break , @"break" ) ,
new TokenDefinition ( TokenType . Return , @"return" ) ,
new TokenDefinition ( TokenType . Null , @"null" ) ,
new TokenDefinition ( TokenType . True , @"true" ) ,
new TokenDefinition ( TokenType . False , @"false" ) ,
new TokenDefinition ( TokenType . DataType , @"(void|var)|(bool|char|short|int|long|float|double|decimal|String|string)([]|?)?" ) ,
// Values
new TokenDefinition ( TokenType . Number , @"d*.d+|d+" ) ,
new TokenDefinition ( TokenType . String , @"""[^""]*""" ) ,
new TokenDefinition ( TokenType . Identifier , @"[a-zA-Z_]w*" , 1 ) ,
new TokenDefinition ( TokenType . Comment , @"(?<=//).*?(?=(r|n|//))" ) ,
new TokenDefinition ( TokenType . MultilineComment , @"(?<=/*)(?:(?!*/)(?:.|[rn]))*(?=*/)" ) ,
// Operators
new TokenDefinition ( TokenType . And , @"&&|&" ) ,
new TokenDefinition ( TokenType . Or , @"||||" ) ,
new TokenDefinition ( TokenType . Not , @"!" , 1 ) ,
new TokenDefinition ( TokenType . Equal , @"=" , 1 ) ,
new TokenDefinition ( TokenType . PlusEqual , @"+=" ) ,
new TokenDefinition ( TokenType . MinusEqual , @"-=" ) ,
new TokenDefinition ( TokenType . DoubleEquals , @"==" ) ,
new TokenDefinition ( TokenType . NotEqual , @"!=" ) ,
new TokenDefinition ( TokenType . LessThan , @"<" , 1 ) ,
new TokenDefinition ( TokenType . GreaterThan , @">" , 1 ) ,
new TokenDefinition ( TokenType . LessThanOrEqual , @"<=" ) ,
new TokenDefinition ( TokenType . GreaterThanOrEqual , @">=" ) ,
// Symbols
new TokenDefinition ( TokenType . OpenRoundBracket , @"(" ) ,
new TokenDefinition ( TokenType . CloseRoundBracket , @")" ) ,
new TokenDefinition ( TokenType . OpenCurlyBracket , @"{" ) ,
new TokenDefinition ( TokenType . CloseCurlyBracket , @"}" ) ,
new TokenDefinition ( TokenType . OpenSquareBracket , @"[" ) ,
new TokenDefinition ( TokenType . CloseSquareBracket , @"]" ) ,
new TokenDefinition ( TokenType . Plus , @"+" , 1 ) ,
new TokenDefinition ( TokenType . Minus , @"-" , 1 ) ,
new TokenDefinition ( TokenType . DoublePluses , @"++" ) ,
new TokenDefinition ( TokenType . DoubleMinuses , @"--" ) ,
new TokenDefinition ( TokenType . Percent , @"%" ) ,
new TokenDefinition ( TokenType . Asterisk , @"*" , 1 ) ,
new TokenDefinition ( TokenType . BackSlash , @"\" ) ,
new TokenDefinition ( TokenType . ForwardSlash , @"/" , 1 ) ,
new TokenDefinition ( TokenType . DoubleForwardSlashes , @"//" ) ,
new TokenDefinition ( TokenType . ForwardSlashAsterisk , @"/*" ) ,
new TokenDefinition ( TokenType . AsteriskForwardSlash , @"*/" ) ,
new TokenDefinition ( TokenType . Dot , @"." ) ,
new TokenDefinition ( TokenType . Comma , @"," ) ,
new TokenDefinition ( TokenType . Colon , @":" ) ,
new TokenDefinition ( TokenType . Semicolon , @";" ) ,
} ;
.. .
Wenn der Tokenizer auf eine Zeichenfolge wie ++
stößt, wird er verwirrt. Handelt es sich um ein Token vom Typ DoublePluses ? Oder zwei aufeinanderfolgende Token vom Typ Plus ? Dieses Problem gilt auch für andere überlappende Token wie: { +
, +=
} & { -
, --
} & { -
, -=
} & { /
, //
}
Lösung:
Jedem Token wird eine Priority- Eigenschaft mit dem Standardwert 0 (höchste Priorität) zugewiesen, und wenn sich zwei Token wie +
und +=
überlappen, verringern wir die Priorität des Tokens mit der kürzeren Länge +
auf 1 .
Jetzt wird der Tokenizer nicht mehr zwischen +
und +=
verwechselt und nimmt das mit der höheren Priorität +=
.
Wenn der Tokenizer mit einer Zeichenfolge wie "String + String = String"
konfrontiert wird, werden drei Arten von Token erzeugt:
"String + String = String"
+
=
aber wir brauchen nur den Token vom Typ String !!
Lösung:
Jedem Token werden die Eigenschaften „Startindex“ und „Endindex“ zugewiesen, sodass vorherige Token Folgendes haben:
Typ | Wert | Index starten | Endindex |
---|---|---|---|
Zeichenfolge | "String + String = String" | 0 | 25 |
Plus | + | 8 | 9 |
Gleich | = | 17 | 18 |
und wir ignorieren alle Token-Starts im Bereich eines anderen.
Jetzt erzeugt der Tokenizer nur ein Token vom Typ String und ignoriert die darin enthaltenen.
Parser/Syntaxanalysator ist ein Programm, das eine vom Tokenizer generierte Folge von Tokens aufnimmt und sie gruppiert, um Strukturen zu bilden, die durch die Produktionen der verwendeten kontextfreien Grammatik (CFG) spezifiziert werden.
Zusammenfassung:
CAPITAL_CASE
: Nicht terminalsmall_case
: Terminal|
: Stellvertreter (oder)ε
: Leer PROGRAM --> IMPORTS CLASSES
IMPORTS --> IMPORT_STATEMENT IMPORTS | ε
IMPORT_STATEMENT --> using IDS;
CLASSES --> CLASS_STATEMENT CLASSES | ε
CLASS_STATEMENT --> class id { SUPER_STATEMENTS }
SUPER_STATEMENTS --> SUPER_STATEMENT SUPER_STATEMENTS | ε
SUPER_STATEMENT --> COMMENT_STATEMENT | FUNCTION_STATEMENT | INLINE_STATEMENT ;
COMMENT_STATEMENT --> // comment | /* multiline_comment */
FUNCTION_STATEMENT --> data_type id (DECLARES) { STATEMENTS }
INLINE_STATEMENT --> DECSIGN_STATEMENT | DECLARE_STATEMENT | INC_DEC_STATEMENT | ASSIGN_STATEMENT | CALL_STATEMENT
DECSIGN_STATEMENT --> data_type id = EXPRESSION
DECLARE_STATEMENT --> data_type id
INC_DEC_STATEMENT --> id INC_DEC_OPERATOR
ASSIGN_STATEMENT --> id ASSIGN_OPERATOR EXPRESSION
CALL_STATEMENT --> IDS(EXPRESSIONS)
STATEMENTS --> STATEMENT STATEMENTS | ε
STATEMENT --> SUPER_STATEMENT | STRUCT_STATEMENT
STRUCT_STATEMENT --> IF_STATEMENT | WHILE_STATEMENT | DO_WHILE_STATEMENT | FOR_STATEMENT | BLOCK_STATEMENT | RETURN_STATEMENT | SWITCH_STATEMENT
IF_STATEMENT --> if (CONDITION) STATEMENT ELSE_STATEMENT
ELSE_STATEMENT --> else STATEMENT | ε
WHILE_STATEMENT --> while (CONDITION) STATEMENT
DO_WHILE_STATEMENT --> do STATEMENT while (CONDITION);
FOR_STATEMENT --> for (INLINE_STATEMENT; CONDITION; INLINE_STATEMENT) STATEMENT
BLOCK_STATEMENT --> { STATEMENTS }
RETURN_STATEMENT --> return RETURN_STATEMENT_REST;
RETURN_STATEMENT_REST --> EXPRESSION | ε
SWITCH_STATEMENT --> switch (EXPRESSION) { CASES }
CASES --> CASE CASES | ε
CASE --> CASE_STATEMENT | DEFAULT_STATEMENT
CASE_STATEMENT --> case VALUE: STATEMENT break;
DEFAULT_STATEMENT --> default: STATEMENT break;
CONDITION --> EXPRESSION REL_OPERATOR EXPRESSION | true | false
EXPRESSION --> VALUE | id | ( EXPRESSION )
VALUE --> string | number | true | false | null
IDS --> id MORE_IDS
MORE_IDS --> .IDS | ε
DECLARES --> DECLARE_STATEMENT MORE_DECLARES | ε
MORE_DECLARES --> , DECLARES | ε
EXPRESSIONS --> EXPRESSION MORE_EXPRESSIONS | ε
MORE_EXPRESSIONS --> , EXPRESSIONS | ε
INC_DEC_OPERATOR --> ++ | --
ASSIGN_OPERATOR --> = | += | -=
REL_OPERATOR --> == | != | > | >= | < | <=
In der Informatik ist die Backus-Naur-Form (BNF oder Backus-Normalform) eine Notation zur Beschreibung der Syntax von Programmiersprachen oder anderen formalen Sprachen. Es wurde von John Backus und Peter Naur entwickelt. BNF kann als Metasyntax-Notation für kontextfreie Grammatiken beschrieben werden.
-- Backus-Naur-Formular @ Wikipedia
referenziert von:
referenziert von:
referenziert von:
referenziert von:
referenziert von:
referenziert von:
referenziert von:
referenziert von:
referenziert von:
referenziert von:
referenziert von:
referenziert von:
referenziert von:
referenziert von:
referenziert von:
referenziert von:
referenziert von:
referenziert von:
referenziert von:
referenziert von:
referenziert von:
referenziert von:
referenziert von:
referenziert von:
referenziert von:
referenziert von:
referenziert von:
referenziert von:
referenziert von:
referenziert von:
referenziert von:
referenziert von:
referenziert von:
referenziert von:
referenziert von: