java -jar .\compilerbau-dmvp.jar .\example-code-1.dmvp
The first step to writing a compiler for a new programming language in Java is to create the Lexer. The Lexer is responsible for taking the source code of the programming language and transforming it into tokens. The Lexer will use a lexical analyzer, also known as a scanner, to scan through the characters of the source code and create tokens.
Once the Lexer has created the tokens, the next step is to create the Parser. The Parser is responsible for taking the tokens and constructing an Abstract Syntax Tree (AST). The AST is a tree-like structure that captures the structure of the source code. The Parser will use a context-free grammar to determine the structure of the source code and create the AST.
Once the Parser has created the AST, the next step is to create the Semantic Analyzer. The Semantic Analyzer is responsible for performing semantic analysis on the AST to ensure that the source code is semantically correct. This includes checking for type compatibility, variable declarations, and other semantic checks.
The final step to compiling the source code is to generate the executable code. The Code Generator is responsible for taking the AST and generating the executable code. The Code Generator can generate code for any target platform, such as x86, ARM, or any other platform.
The final step to writing a compiler for a new programming language in Java is to test and debug the compiler. This includes testing the Lexer, Parser, Semantic Analyzer, and Code Generator to ensure that the compiler is working correctly. Additionally, any bugs or errors that are found should be fixed.
-
parse(): This is the entry point of the parser. It calls the expression() method, which starts the parsing process. It returns a Node object, which is the result of parsing the input tokens.
-
expression(): This method is used to parse expressions in the input. It starts by calling the term() method to get the left operand, then it looks for any plus or minus operators, and if found, it calls the term() method again to get the right operand. It then creates a new BinaryNode object with the left and right operands and the operator and sets it as the left operand for the next iteration. It returns the final Node object that represents the parsed expression.
-
term(): This method is used to parse terms in the input. It works similar to the expression() method but it looks for any multiply or divide operators.
-
factor(): This method is used to parse factors in the input. It starts by checking if the current token is a unary operator (plus or minus), if yes, it calls the factor() method again to get the right operand and creates a new UnaryNode object with the operator and the right operand. If the current token is an integer or float, it creates a new ValueNode object with the token's value. If the current token is a left parenthesis, it calls the expression() method to get the expression inside the parenthesis and returns it.
-
match(): This method is used to match the current token with a list of expected types. If a match is found, it advances the current token pointer and returns true, otherwise it returns false.
-
consume(): This method is used to consume a specific token and throw an exception if it is not found.
-
check(): This method is used to check if the current token is of a specific type.
-
advance(): This method is used to advance the current token pointer.
-
isAtEnd(): This method is used to check if the end of the token list has been reached.
-
peek(): This method is used to get the current token without advancing the current token pointer.
-
previous(): This method is used to get the previous token.
java -jar .\target\libs\compilerbau-1.0-SNAPSHOT-jar-with-dependencies.jar .\example-code-4.dmvp