├── .gitignore
├── LICENSE
├── README.md
├── _config.yml
├── compiler-examples
├── ck-compiler
│ ├── README.md
│ ├── pom.xml
│ └── src
│ │ ├── main
│ │ └── java
│ │ │ └── com
│ │ │ └── arjunsk
│ │ │ └── compiler
│ │ │ └── ck
│ │ │ ├── domain
│ │ │ ├── token
│ │ │ │ ├── Token.java
│ │ │ │ └── support
│ │ │ │ │ └── TokenType.java
│ │ │ └── tree
│ │ │ │ ├── ParseTree.java
│ │ │ │ ├── Visitable.java
│ │ │ │ └── nodes
│ │ │ │ ├── common
│ │ │ │ └── TerminalNode.java
│ │ │ │ └── grammer
│ │ │ │ ├── ParserRuleContext.java
│ │ │ │ └── impl
│ │ │ │ ├── LetContext.java
│ │ │ │ ├── ProgramContext.java
│ │ │ │ ├── ShowContext.java
│ │ │ │ └── StatementContext.java
│ │ │ ├── exceptions
│ │ │ ├── LexerException.java
│ │ │ ├── ParserException.java
│ │ │ └── SemanticException.java
│ │ │ ├── lexer
│ │ │ └── Lexer.java
│ │ │ ├── parser
│ │ │ └── Parser.java
│ │ │ └── visitor
│ │ │ ├── SimplerLangBaseVisitor.java
│ │ │ ├── Visitor.java
│ │ │ ├── codegenerator
│ │ │ └── CodeGeneratorVisitor.java
│ │ │ ├── interpreter
│ │ │ └── InterpreterVisitor.java
│ │ │ └── semantic
│ │ │ └── SemanticAnalyzer.java
│ │ └── test
│ │ ├── java
│ │ └── com
│ │ │ └── arjunsk
│ │ │ └── compiler
│ │ │ ├── ck
│ │ │ ├── CkCompilerTest.java
│ │ │ ├── lexer
│ │ │ │ └── LexerTest.java
│ │ │ ├── parser
│ │ │ │ └── ParserTest.java
│ │ │ └── visitor
│ │ │ │ └── semantic
│ │ │ │ └── SemanticAnalyzerTest.java
│ │ │ └── utils
│ │ │ └── FileReaderUtil.java
│ │ └── resources
│ │ └── input
│ │ └── CgSample.ck
├── lisp-compiler
│ ├── pom.xml
│ └── src
│ │ ├── main
│ │ └── java
│ │ │ └── com
│ │ │ └── arjunsk
│ │ │ └── compiler
│ │ │ └── lisp
│ │ │ ├── core
│ │ │ ├── emitter
│ │ │ │ └── .gitkeep
│ │ │ ├── lexer
│ │ │ │ └── Lexer.java
│ │ │ ├── parser
│ │ │ │ └── Parser.java
│ │ │ ├── transformer
│ │ │ │ └── Transformer.java
│ │ │ └── visitor
│ │ │ │ └── .gitkeep
│ │ │ ├── domain
│ │ │ ├── ast
│ │ │ │ ├── AstNode.java
│ │ │ │ └── LispAstNode.java
│ │ │ └── lexer
│ │ │ │ ├── Token.java
│ │ │ │ └── support
│ │ │ │ └── TokenType.java
│ │ │ └── exceptions
│ │ │ ├── LexerException.java
│ │ │ └── ParserException.java
│ │ └── test
│ │ ├── java
│ │ └── com
│ │ │ └── arjunsk
│ │ │ └── compiler
│ │ │ ├── lisp
│ │ │ └── core
│ │ │ │ ├── lexer
│ │ │ │ └── LexerTest.java
│ │ │ │ └── parser
│ │ │ │ └── ParserTest.java
│ │ │ └── utils
│ │ │ └── FileReaderUtil.java
│ │ └── resources
│ │ └── input
│ │ └── code.lsp
├── pom.xml
└── svg-compiler
│ ├── pom.xml
│ └── src
│ ├── main
│ └── java
│ │ └── com
│ │ └── arjunsk
│ │ └── compiler
│ │ └── svg
│ │ ├── core
│ │ ├── generation
│ │ │ └── CodeGenerator.java
│ │ ├── parsing
│ │ │ ├── Lexer.java
│ │ │ └── Parser.java
│ │ └── transforming
│ │ │ └── Transformer.java
│ │ ├── domain
│ │ ├── lexer
│ │ │ ├── ast
│ │ │ │ ├── AstNode.java
│ │ │ │ └── support
│ │ │ │ │ └── AstNodeClass.java
│ │ │ └── token
│ │ │ │ ├── Token.java
│ │ │ │ └── support
│ │ │ │ └── TokenType.java
│ │ └── transformer
│ │ │ └── ast
│ │ │ └── SvgAstNode.java
│ │ └── exceptions
│ │ ├── LexerException.java
│ │ ├── ParserException.java
│ │ └── TransformerException.java
│ └── test
│ ├── java
│ └── com
│ │ └── arjunsk
│ │ └── compiler
│ │ ├── svg
│ │ └── core
│ │ │ ├── generation
│ │ │ └── CodeGeneratorTest.java
│ │ │ ├── parsing
│ │ │ ├── LexerTest.java
│ │ │ └── ParserTest.java
│ │ │ └── transforming
│ │ │ └── TransformerTest.java
│ │ └── utils
│ │ └── FileReaderUtil.java
│ └── resources
│ ├── lexer
│ └── code.ck
│ └── output
│ └── code.svg
├── parser-examples
├── antlr-examples
│ ├── antlr-listener-example
│ │ ├── pom.xml
│ │ └── src
│ │ │ └── main
│ │ │ ├── antlr4
│ │ │ └── com
│ │ │ │ └── arjunsk
│ │ │ │ └── parser
│ │ │ │ └── antlr
│ │ │ │ └── SimplerLang.g4
│ │ │ └── java
│ │ │ └── com
│ │ │ └── arjunsk
│ │ │ └── parser
│ │ │ └── antlr
│ │ │ └── listener
│ │ │ ├── AntlrListenerDriver.java
│ │ │ └── support
│ │ │ └── SimplerLangListenerImpl.java
│ ├── antlr-visitor-example1
│ │ ├── pom.xml
│ │ └── src
│ │ │ └── main
│ │ │ ├── antlr4
│ │ │ └── com
│ │ │ │ └── arjunsk
│ │ │ │ └── parser
│ │ │ │ └── antlr
│ │ │ │ └── Calculator.g4
│ │ │ └── java
│ │ │ └── com
│ │ │ └── arjunsk
│ │ │ └── parser
│ │ │ └── antlr
│ │ │ └── visitor
│ │ │ ├── AntlrVisitorDriver1.java
│ │ │ └── support
│ │ │ └── CalculatorVisitorImpl.java
│ ├── antlr-visitor.example2
│ │ ├── pom.xml
│ │ └── src
│ │ │ └── main
│ │ │ ├── antlr4
│ │ │ └── com
│ │ │ │ └── arjunsk
│ │ │ │ └── parser
│ │ │ │ └── antlr
│ │ │ │ └── SimplerLang.g4
│ │ │ └── java
│ │ │ └── com
│ │ │ └── arjunsk
│ │ │ └── parser
│ │ │ └── antlr
│ │ │ └── listener
│ │ │ ├── AntlrVisitorDriver2.java
│ │ │ └── support
│ │ │ └── SimplerLangVisitorImpl.java
│ └── pom.xml
├── javaparser-example
│ ├── pom.xml
│ └── src
│ │ └── main
│ │ ├── java
│ │ └── com
│ │ │ └── arjunsk
│ │ │ └── parser
│ │ │ └── javaparser
│ │ │ └── JavaparserDriver.java
│ │ └── resources
│ │ └── input
│ │ └── SimpleProgram.java
├── jdt-example
│ ├── pom.xml
│ └── src
│ │ └── main
│ │ ├── java
│ │ └── com
│ │ │ └── arjunsk
│ │ │ └── parser
│ │ │ └── jdt
│ │ │ ├── JdtDriver.java
│ │ │ └── ast
│ │ │ └── JdtAstVisitor.java
│ │ └── resources
│ │ └── input
│ │ └── SimpleProgram.java
└── pom.xml
└── pom.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | ##############################
2 | ## Java
3 | ##############################
4 | .mtj.tmp/
5 | *.class
6 | *.jar
7 | *.war
8 | *.ear
9 | *.nar
10 | hs_err_pid*
11 |
12 | ##############################
13 | ## Maven
14 | ##############################
15 | target/
16 | pom.xml.tag
17 | pom.xml.releaseBackup
18 | pom.xml.versionsBackup
19 | pom.xml.next
20 | pom.xml.bak
21 | release.properties
22 | dependency-reduced-pom.xml
23 | buildNumber.properties
24 | .mvn/timing.properties
25 | .mvn/wrapper/maven-wrapper.jar
26 |
27 | ##############################
28 | ## Gradle
29 | ##############################
30 | bin/
31 | build/
32 | .gradle
33 | .gradletasknamecache
34 | gradle-app.setting
35 | !gradle-wrapper.jar
36 |
37 | ##############################
38 | ## IntelliJ
39 | ##############################
40 | out/
41 | .idea/
42 | .idea_modules/
43 | *.iml
44 | *.ipr
45 | *.iws
46 |
47 | ##############################
48 | ## Eclipse
49 | ##############################
50 | .settings/
51 | bin/
52 | tmp/
53 | .metadata
54 | .classpath
55 | .project
56 | *.tmp
57 | *.bak
58 | *.swp
59 | *~.nib
60 | local.properties
61 | .loadpath
62 | .factorypath
63 |
64 | ##############################
65 | ## NetBeans
66 | ##############################
67 | nbproject/private/
68 | build/
69 | nbbuild/
70 | dist/
71 | nbdist/
72 | nbactions.xml
73 | nb-configuration.xml
74 |
75 | ##############################
76 | ## OS X
77 | ##############################
78 | .DS_Store
79 |
80 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Arjun SK
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Codekrypt Compiler
2 | This repo contains sub modules which helped me understand compilers better.
3 |
4 | ## Project Modules
5 |
6 | ### Compiler Examples
7 |
8 | #### CK(Codekrypt) Compiler
9 | This compiler was developed ground up as a part of learning. This is adapted from `ANLR Examples` module.
10 | 1. [CK Compiler src](/compiler-examples/ck-compiler)
11 | 2. [ASM Code Generation](https://github.com/arjunsk/java-bytecode/tree/master/java-asm/ow2-asm-example/src/main/java/com/arjunsk/asm/asmifier)
12 |
13 | #### SVG Compiler (needs review)
14 | 1. [Web App](https://kosamari.github.io/sbn/)
15 | 2. [Medium Article](https://medium.com/@kosamari/how-to-be-a-compiler-make-a-compiler-with-javascript-4a8a13d473b4)
16 |
17 | #### LISP Compiler (on hold)
18 | Trying to port [Tiny-Compiler](https://github.com/jamiebuilds/the-super-tiny-compiler) to Java.
19 | 1. [Github](https://github.com/jamiebuilds/the-super-tiny-compiler/blob/master/the-super-tiny-compiler.js)
20 |
21 | ### Parser Examples
22 |
23 | #### ANTLR Examples
24 | 1. [Visitor](https://www.javahelps.com/2019/04/antlr-hello-world-arithmetic-expression.html)
25 | 2. [Listener](https://shalithasuranga.medium.com/build-your-own-programming-language-with-antlr-5201955537a5)
26 |
27 | #### Javaparser Example
28 | 1. [StackOverflow](https://stackoverflow.com/questions/58611706/javaparser-parsing-and-generating-java-code)
29 |
30 | #### JDT Example
31 | Functions similar to what is provided by Eclipse IDE. (project, workspace, code)
32 | 1. [ProgramCreek](https://www.programcreek.com/2011/01/best-java-development-tooling-jdt-and-astparser-tutorials/)
33 |
34 |
35 | ## Trouble Shooting
36 | 1. If the project is failing in the `ANTLR Examples` submodules, please build the project first using.
37 | ```shell script
38 | mvn clean install
39 | ```
40 |
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-hacker
--------------------------------------------------------------------------------
/compiler-examples/ck-compiler/README.md:
--------------------------------------------------------------------------------
1 | ## CK Compiler
2 | This is a project I created for learning internals of compilers. The `SimplerLang` grammar is taken from [this](https://shalithasuranga.medium.com/build-your-own-programming-language-with-antlr-5201955537a5) post.
3 |
4 | ### To compile `.ck` to `.class`
5 | 1. Open [CompilerTest.java](src/test/java/com/arjunsk/compiler/ck/CkCompilerTest.java)
6 | 2. Run `compile()`
7 | 3. Look for the `output/CgSample.class` generated under root.
8 | 4. To see the source code of `CgSample.class`, use IntelliJ decompiler.
9 |
10 | ### Grammar
11 | ```antlrv4
12 | grammar simplerlang;
13 |
14 | program : statement+;
15 | statement : let | show ;
16 |
17 | let : VAR '=' INT ;
18 | show : 'show' (INT | VAR) ;
19 |
20 | VAR : [a-z]+ ;
21 | INT : [0–9]+ ;
22 | WS : [ \n\t]+ -> skip;
23 | ```
24 |
25 | ### Features
26 | 1. Used a simple grammar to focus more on `compiler phases` rather than `language support`.
27 | 2. Took `ANTLR` generated code as a reference.
28 | 2. Implemented [Parse Tree](src/main/java/com/arjunsk/compiler/ck/domain/tree/ParseTree.java) & created [Visitable](src/main/java/com/arjunsk/compiler/ck/domain/tree/Visitable.java) Grammar Nodes.
29 | 3. Implemented [Visitor](src/main/java/com/arjunsk/compiler/ck/visitor/Visitor.java) for writing business logic on Tree nodes.
30 | 4. Implemented [CodeGeneration](src/main/java/com/arjunsk/compiler/ck/visitor/codegenerator/CodeGeneratorVisitor.java) using `Java ASM`.
31 | 5. Implemented [Interpreter](src/main/java/com/arjunsk/compiler/ck/visitor/interpreter/InterpreterVisitor.java) & [Semantic Analyzer](src/main/java/com/arjunsk/compiler/ck/visitor/semantic/SemanticAnalyzer.java).
32 |
33 | ### TODO
34 | * ~~Implement Semantic Analyser.~~
35 | * ~~Implement custom filename.(Unsupported)~~
36 | * ~~Implement Parse Tree.~~
37 | * ~~Implement Visitor Pattern.~~
38 | * ~~Implement byte code generation~~
39 |
40 | ### Compiler Phases
41 | 1. Lexical Analysis [Done]
42 | 2. Syntactic Analysis (ie Parsing) [Done]
43 | 3. Semantic analysis [Done] & Intermediate Code Generation [NA]
44 | 4. Optimization (optional)
45 | 5. Code Generation [Done]
46 |
47 | Intermediate Code Generation: code gets converted to independent intermediate code. We are not doing this in `ck-compiler`.
48 | We could use `LLVM` as Backend for implementing this feature.
49 |
50 | ### Reference:
51 | 1. [Java ASM](https://github.com/arjunsk/java-bytecode/tree/master/java-asm/ow2-asm-example/src/main/java/com/arjunsk/asm/asmifier)
52 | 2. [Ops Code](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html)
53 | 3. [Lecture Note](https://www.radford.edu/~nokie/classes/380/phases.html)
54 | 4. [LLVM Backend](https://llvm.org/docs/WritingAnLLVMBackend.html)
55 |
56 | > Do check out other modules in this project for better understanding.️
--------------------------------------------------------------------------------
/compiler-examples/ck-compiler/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 |
8 | com.arjunsk
9 | compiler-examples
10 | 1.0-SNAPSHOT
11 |
12 |
13 | ck-compiler
14 | Codekrypt Compiler
15 |
16 |
17 |
18 | arjunsk
19 | Arjun SK
20 | https://github.com/arjunsk
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | org.ow2.asm
29 | asm
30 | ${ow2-asm.version}
31 |
32 |
33 |
34 |
35 | org.ow2.asm
36 | asm-util
37 | ${ow2-asm.version}
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/compiler-examples/ck-compiler/src/main/java/com/arjunsk/compiler/ck/domain/token/Token.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.ck.domain.token;
2 |
3 | import com.arjunsk.compiler.ck.domain.token.support.TokenType;
4 |
5 | /** Output of Lexer. Contains TokenType and Token Value. */
6 | public class Token {
7 |
8 | private final TokenType type;
9 |
10 | private final String value;
11 |
12 | public Token(TokenType type) {
13 | this.type = type;
14 | this.value = null;
15 | }
16 |
17 | public Token(TokenType type, String value) {
18 | this.type = type;
19 | this.value = value;
20 | }
21 |
22 | public TokenType getType() {
23 | return type;
24 | }
25 |
26 | public String getValue() {
27 | return value;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/compiler-examples/ck-compiler/src/main/java/com/arjunsk/compiler/ck/domain/token/support/TokenType.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.ck.domain.token.support;
2 |
3 | /**
4 | * Our code will contain only SHOW, VARIABLE, EQUALS_OPERATOR or NUMBER
5 | *
6 | *
7 | * a = 10
8 | * show a
9 | * show 20
10 | *
11 | *
12 | */
13 | public enum TokenType {
14 | SHOW, // Key word
15 |
16 | EQUALS_OPERATOR, // The only operator
17 |
18 | // Terminal Nodes
19 | NUMBER,
20 | VARIABLE,
21 | }
22 |
--------------------------------------------------------------------------------
/compiler-examples/ck-compiler/src/main/java/com/arjunsk/compiler/ck/domain/tree/ParseTree.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.ck.domain.tree;
2 |
3 | import com.arjunsk.compiler.ck.visitor.Visitor;
4 |
5 | /**
6 | * Base for implementing a parse tree.
7 | *
8 | * Since this is the domain object which will have custom business logic in future, we use {@link
9 | * Visitable#accept(Visitor)} to implement the same.
10 | *
11 | *
You might be wondering, in the {@link
12 | * com.arjunsk.compiler.ck.domain.tree.nodes.grammer.ParserRuleContext} we already have the
13 | * parent-child relationship. Then how is this class helpful. We use this class for generic
14 | * traversal of parent-child paths. Mainly used to propagate accept() and generate toString() of the
15 | * tree.
16 | */
17 | public interface ParseTree extends Visitable {
18 |
19 | ParseTree getParent();
20 |
21 | void setParent(ParseTree parent);
22 |
23 | /**
24 | * @return concatenation of all the children.getText() or return the Token value for Terminal
25 | * nodes.
26 | */
27 | String getText();
28 |
29 | /** @return this Object or Token entry. */
30 | Object getPayload();
31 |
32 | /** Add child to the tree. */
33 | void addChild(ParseTree child);
34 |
35 | /** Get child at the given index. */
36 | ParseTree getChild(int i);
37 |
38 | /** @return count of children */
39 | int getChildCount();
40 |
41 | /** @return bracket matched flattened string of the tree. */
42 | String toStringTree();
43 | }
44 |
--------------------------------------------------------------------------------
/compiler-examples/ck-compiler/src/main/java/com/arjunsk/compiler/ck/domain/tree/Visitable.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.ck.domain.tree;
2 |
3 | import com.arjunsk.compiler.ck.visitor.Visitor;
4 |
5 | /** visitor pattern, 'Visitable' allows business logic to be separated from domain entities. */
6 | public interface Visitable {
7 |
8 | /**
9 | * @param visitor Base Visitor or Custom Visitor Implementation.
10 | * @param Output Type Generic present in the Visitor Implementation.
11 | * @return the output based on the datatype passed in Visitor implementation
12 | * Eg:- public class SimplerLangCustomVisitor extends SimplerLangBaseVisitor
13 | * Here T = Void, visitor is of type SimplerLangBaseVisitor
14 | */
15 | T accept(Visitor extends T> visitor);
16 | }
17 |
--------------------------------------------------------------------------------
/compiler-examples/ck-compiler/src/main/java/com/arjunsk/compiler/ck/domain/tree/nodes/common/TerminalNode.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.ck.domain.tree.nodes.common;
2 |
3 | import com.arjunsk.compiler.ck.domain.token.Token;
4 | import com.arjunsk.compiler.ck.domain.tree.ParseTree;
5 | import com.arjunsk.compiler.ck.visitor.Visitor;
6 |
7 | /**
8 | * Terminal node or Leaf node.
9 | *
10 | * Eg:- VAR or INT
11 | */
12 | public class TerminalNode implements ParseTree {
13 |
14 | public ParseTree parent;
15 |
16 | public Token symbol;
17 |
18 | @Override
19 | public ParseTree getParent() {
20 | return this.parent;
21 | }
22 |
23 | @Override
24 | public void setParent(ParseTree parent) {
25 | this.parent = parent;
26 | }
27 |
28 | /**
29 | * Terminal nodes will have Token as the payload. (ie VAR or INT)
30 | *
31 | * @param symbol Token value for the terminal node
32 | */
33 | public void setSymbol(Token symbol) {
34 | this.symbol = symbol;
35 | }
36 |
37 | /**
38 | * Terminal node will have Token as the payload. (ie VAR or INT). We have it as Object return type
39 | * because for ContextNodes, it can be that node itself.
40 | *
41 | * @return Token value.
42 | */
43 | @Override
44 | public Object getPayload() {
45 | return this.symbol;
46 | }
47 |
48 | /**
49 | * Terminal node will have the Text as Token value.
50 | *
51 | * @return Token Value
52 | */
53 | @Override
54 | public String getText() {
55 | return this.symbol.getValue();
56 | }
57 |
58 | /** {@inheritDoc} */
59 | @Override
60 | public void addChild(ParseTree child) {}
61 |
62 | /** {@inheritDoc} */
63 | @Override
64 | public ParseTree getChild(int i) {
65 | return null;
66 | }
67 |
68 | /** {@inheritDoc} */
69 | @Override
70 | public int getChildCount() {
71 | return 0;
72 | }
73 |
74 | /**
75 | * Implementation of toStringTree for terminal node return only the Token Value.
76 | *
77 | * @return Token Value
78 | */
79 | @Override
80 | public String toStringTree() {
81 | return getText();
82 | }
83 |
84 | /**
85 | * {@inheritDoc}
86 | *
87 | *
Invoke visitTerminal function in the Visitor Implementation.
88 | */
89 | @Override
90 | public T accept(Visitor extends T> visitor) {
91 | return visitor.visitTerminal(this);
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/compiler-examples/ck-compiler/src/main/java/com/arjunsk/compiler/ck/domain/tree/nodes/grammer/ParserRuleContext.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.ck.domain.tree.nodes.grammer;
2 |
3 | import com.arjunsk.compiler.ck.domain.tree.ParseTree;
4 | import com.arjunsk.compiler.ck.visitor.Visitor;
5 | import java.util.ArrayList;
6 | import java.util.List;
7 |
8 | /** Base implementation for our Grammar Elements. */
9 | public class ParserRuleContext implements ParseTree {
10 |
11 | public ParseTree parent;
12 |
13 | public List children;
14 |
15 | /** {@inheritDoc} */
16 | @Override
17 | public ParseTree getParent() {
18 | return this.parent;
19 | }
20 |
21 | /** {@inheritDoc} */
22 | @Override
23 | public void setParent(ParseTree parent) {
24 | this.parent = parent;
25 | }
26 |
27 | /** {@inheritDoc} */
28 | @Override
29 | public String getText() {
30 | if (getChildCount() == 0) {
31 | return "";
32 | }
33 |
34 | StringBuilder builder = new StringBuilder();
35 | for (int i = 0; i < getChildCount(); i++) {
36 | builder.append(getChild(i).getText());
37 | }
38 |
39 | return builder.toString();
40 | }
41 |
42 | /** {@inheritDoc} */
43 | @Override
44 | public Object getPayload() {
45 | return this;
46 | }
47 |
48 | /** {@inheritDoc} */
49 | public void addChild(ParseTree child) {
50 | child.setParent(this);
51 | if (children == null) children = new ArrayList<>();
52 | children.add(child);
53 | }
54 |
55 | /** {@inheritDoc} */
56 | @Override
57 | public ParseTree getChild(int i) {
58 | return this.children.get(i);
59 | }
60 |
61 | /** {@inheritDoc} */
62 | @Override
63 | public int getChildCount() {
64 | return children != null ? children.size() : 0;
65 | }
66 |
67 | /** {@inheritDoc} */
68 | @Override
69 | public String toStringTree() {
70 | if (getChildCount() == 0) {
71 | return "";
72 | }
73 |
74 | StringBuilder sb = new StringBuilder();
75 |
76 | sb.append("( ");
77 | sb.append(this.getClass().getSimpleName());
78 | sb.append("(");
79 | for (int i = 0; i < getChildCount(); i++) {
80 | sb.append(" ").append(getChild(i).toStringTree()).append(" ");
81 | }
82 | sb.append(")");
83 | sb.append(" )");
84 |
85 | return sb.toString();
86 | }
87 |
88 | /** To be overridden in child implementations. */
89 | @Override
90 | public T accept(Visitor extends T> visitor) {
91 | return null;
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/compiler-examples/ck-compiler/src/main/java/com/arjunsk/compiler/ck/domain/tree/nodes/grammer/impl/LetContext.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.ck.domain.tree.nodes.grammer.impl;
2 |
3 | import com.arjunsk.compiler.ck.domain.tree.nodes.common.TerminalNode;
4 | import com.arjunsk.compiler.ck.domain.tree.nodes.grammer.ParserRuleContext;
5 | import com.arjunsk.compiler.ck.visitor.Visitor;
6 |
7 | /**
8 | * `Let` Syntax ParseRuleContext.
9 | *
10 | * Eg:- a = 10 ( VAR = INT)
11 | */
12 | public class LetContext extends ParserRuleContext {
13 |
14 | private final TerminalNode variableName;
15 |
16 | private final TerminalNode variableValue;
17 |
18 | public LetContext(TerminalNode variableName, TerminalNode variableValue) {
19 | this.variableName = variableName;
20 | this.variableValue = variableValue;
21 |
22 | // Add the arguments as children to this node.
23 | this.addChild(variableName);
24 | this.addChild(variableValue);
25 | }
26 |
27 | public TerminalNode getVariableName() {
28 | return variableName;
29 | }
30 |
31 | public TerminalNode getVariableValue() {
32 | return variableValue;
33 | }
34 |
35 | @Override
36 | public T accept(Visitor extends T> visitor) {
37 | return visitor.visitLet(this);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/compiler-examples/ck-compiler/src/main/java/com/arjunsk/compiler/ck/domain/tree/nodes/grammer/impl/ProgramContext.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.ck.domain.tree.nodes.grammer.impl;
2 |
3 | import com.arjunsk.compiler.ck.domain.tree.nodes.grammer.ParserRuleContext;
4 | import com.arjunsk.compiler.ck.visitor.Visitor;
5 | import java.util.List;
6 |
7 | /**
8 | * `Program` Syntax ParseRuleContext.
9 | *
10 | * Eg:- Statement+ // ie program consists of multiple statements.
11 | *
12 | *
NOTE: This is a simple compiler. Ideally we should be having the `package name` and `Class
13 | * Name` as part of ProgramContext. This `package name` and `Class Name` could be later used in
14 | * {@link
15 | * com.arjunsk.compiler.ck.visitor.codegenerator.CodeGeneratorVisitor#visitProgram(ProgramContext)}
16 | * to write the corresponding `.class` in the correct `target package` with the correct `class
17 | * name`.
18 | */
19 | public class ProgramContext extends ParserRuleContext {
20 |
21 | private final List statements;
22 |
23 | public ProgramContext(List statements) {
24 | this.statements = statements;
25 |
26 | // Add the statements as children to this node.
27 | for (StatementContext statement : statements) {
28 | this.addChild(statement);
29 | }
30 | }
31 |
32 | public List getStatements() {
33 | return statements;
34 | }
35 |
36 | public StatementContext getStatements(int i) {
37 | return statements.get(i);
38 | }
39 |
40 | @Override
41 | public T accept(Visitor extends T> visitor) {
42 | return visitor.visitProgram(this);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/compiler-examples/ck-compiler/src/main/java/com/arjunsk/compiler/ck/domain/tree/nodes/grammer/impl/ShowContext.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.ck.domain.tree.nodes.grammer.impl;
2 |
3 | import com.arjunsk.compiler.ck.domain.tree.nodes.common.TerminalNode;
4 | import com.arjunsk.compiler.ck.domain.tree.nodes.grammer.ParserRuleContext;
5 | import com.arjunsk.compiler.ck.visitor.Visitor;
6 |
7 | /**
8 | * `Show` Syntax ParseRuleContext.
9 | *
10 | * Eg:- show INT or show VAR
11 | */
12 | public class ShowContext extends ParserRuleContext {
13 |
14 | private final TerminalNode integerValue;
15 |
16 | private final TerminalNode variableName;
17 |
18 | public ShowContext(TerminalNode integerValue, TerminalNode variableName) {
19 | this.integerValue = integerValue;
20 | this.variableName = variableName;
21 |
22 | // Conditionally add child node
23 | if (integerValue != null) {
24 | this.addChild(integerValue);
25 | } else {
26 | this.addChild(variableName);
27 | }
28 | }
29 |
30 | public TerminalNode getIntegerValue() {
31 | return integerValue;
32 | }
33 |
34 | public TerminalNode getVariableName() {
35 | return variableName;
36 | }
37 |
38 | @Override
39 | public T accept(Visitor extends T> visitor) {
40 | return visitor.visitShow(this);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/compiler-examples/ck-compiler/src/main/java/com/arjunsk/compiler/ck/domain/tree/nodes/grammer/impl/StatementContext.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.ck.domain.tree.nodes.grammer.impl;
2 |
3 | import com.arjunsk.compiler.ck.domain.tree.nodes.grammer.ParserRuleContext;
4 | import com.arjunsk.compiler.ck.visitor.Visitor;
5 |
6 | /**
7 | * `Statement` Syntax ParseRuleContext.
8 | *
9 | * Eg:- LET | SHOW // ie either Let or Show statement would be the value of statement.
10 | */
11 | public class StatementContext extends ParserRuleContext {
12 |
13 | private final LetContext letContext;
14 |
15 | private final ShowContext showContext;
16 |
17 | public StatementContext(LetContext letContext, ShowContext showContext) {
18 | this.letContext = letContext;
19 | this.showContext = showContext;
20 |
21 | // Conditionally add child node
22 | if (letContext != null) {
23 | this.addChild(letContext);
24 | } else {
25 | this.addChild(showContext);
26 | }
27 | }
28 |
29 | public LetContext getLetContext() {
30 | return letContext;
31 | }
32 |
33 | public ShowContext getShowContext() {
34 | return showContext;
35 | }
36 |
37 | @Override
38 | public T accept(Visitor extends T> visitor) {
39 | return visitor.visitStatement(this);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/compiler-examples/ck-compiler/src/main/java/com/arjunsk/compiler/ck/exceptions/LexerException.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.ck.exceptions;
2 |
3 | public class LexerException extends RuntimeException {
4 |
5 | public LexerException() {
6 | super("Exception While Lexical Tokenizing");
7 | }
8 |
9 | public LexerException(String message) {
10 | super(message);
11 | }
12 |
13 | public LexerException(String message, Throwable cause) {
14 | super(message, cause);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/compiler-examples/ck-compiler/src/main/java/com/arjunsk/compiler/ck/exceptions/ParserException.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.ck.exceptions;
2 |
3 | public class ParserException extends RuntimeException {
4 |
5 | public ParserException() {
6 | super("Exception While Parsing");
7 | }
8 |
9 | public ParserException(String message) {
10 | super(message);
11 | }
12 |
13 | public ParserException(String message, Throwable cause) {
14 | super(message, cause);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/compiler-examples/ck-compiler/src/main/java/com/arjunsk/compiler/ck/exceptions/SemanticException.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.ck.exceptions;
2 |
3 | public class SemanticException extends RuntimeException {
4 |
5 | public SemanticException() {
6 | super("Exception While performing semantic checks.");
7 | }
8 |
9 | public SemanticException(String message) {
10 | super(message);
11 | }
12 |
13 | public SemanticException(String message, Throwable cause) {
14 | super(message, cause);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/compiler-examples/ck-compiler/src/main/java/com/arjunsk/compiler/ck/lexer/Lexer.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.ck.lexer;
2 |
3 | import com.arjunsk.compiler.ck.domain.token.Token;
4 | import com.arjunsk.compiler.ck.domain.token.support.TokenType;
5 | import com.arjunsk.compiler.ck.exceptions.LexerException;
6 | import java.util.Arrays;
7 |
8 | public class Lexer {
9 |
10 | private final String code;
11 | private final int codeLength;
12 |
13 | private int currentIndex;
14 |
15 | private Token currentToken;
16 | private Token previousToken;
17 |
18 | public Lexer(String code) {
19 | this.code = code;
20 | this.currentIndex = 0;
21 | this.codeLength = code.length();
22 | }
23 |
24 | /**
25 | * Updates currentToken to the next valid Token if it is available.
26 | *
27 | * @return true, if a valid token is available next.
28 | */
29 | public boolean nextToken() {
30 |
31 | while (!isEndOfCode()) { // while loop is to fetch nextToken, if a skipWS occurs.
32 |
33 | previousToken = currentToken; // in case you need the previous token
34 |
35 | final char currentChar = code.charAt(currentIndex);
36 |
37 | if (Arrays.asList(' ', '\r', '\t', '\n').contains(currentChar)) { // 1. WS
38 | skipWhiteSpace();
39 | continue;
40 | } else if (currentChar == '=') { // 2. LET
41 | currentToken = new Token(TokenType.EQUALS_OPERATOR);
42 | currentIndex++;
43 | } else if (Character.isDigit(currentChar)) { // 3. INT
44 | currentToken = new Token(TokenType.NUMBER, readNumber());
45 | } else if (Character.isLetter(currentChar)) {
46 | String variableName = readVariable();
47 | if (variableName.equalsIgnoreCase("show")) { // 4. SHOW
48 | currentToken = new Token(TokenType.SHOW);
49 | } else { // 5. VAR
50 | currentToken = new Token(TokenType.VARIABLE, variableName);
51 | }
52 | } else {
53 | throw new LexerException("Token not defined.");
54 | }
55 | return true;
56 | }
57 | return false;
58 | }
59 |
60 | /**
61 | * Read Integer as String
62 | *
63 | * @return String value of Integer Number.
64 | */
65 | private String readNumber() {
66 | StringBuilder sb = new StringBuilder();
67 | char currentChar = code.charAt(currentIndex);
68 | while (!isEndOfCode() && Character.isDigit(currentChar)) {
69 | sb.append(currentChar);
70 | currentIndex++;
71 | if (isEndOfCode()) break;
72 | currentChar = code.charAt(currentIndex);
73 | }
74 | return sb.toString();
75 | }
76 |
77 | /** @return String read from current index. */
78 | private String readVariable() {
79 | StringBuilder sb = new StringBuilder();
80 | char currentChar = code.charAt(currentIndex);
81 | while (!isEndOfCode() && Character.isLetter(currentChar)) {
82 | sb.append(currentChar);
83 | currentIndex++;
84 | if (isEndOfCode()) break;
85 | currentChar = code.charAt(currentIndex);
86 | }
87 | return sb.toString();
88 | }
89 |
90 | /** Skip WhiteSpace(WS) */
91 | private void skipWhiteSpace() {
92 | while (!isEndOfCode()) {
93 | if (Arrays.asList(' ', '\r', '\t', '\n').contains(code.charAt(currentIndex))) {
94 | currentIndex++;
95 | } else {
96 | break;
97 | }
98 | }
99 | }
100 |
101 | /** Check if End of Code is reached. */
102 | private boolean isEndOfCode() {
103 | return currentIndex >= codeLength;
104 | }
105 |
106 | /**
107 | * Get previous Token.
108 | *
109 | * NOTE: for SimplerLang grammar we don't have much use of previous token. But it will be
110 | * useful when implementing complex Grammar.
111 | */
112 | public Token getPreviousToken() {
113 | return previousToken;
114 | }
115 |
116 | /** Get current Token. */
117 | public Token getCurrentToken() {
118 | return currentToken;
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/compiler-examples/ck-compiler/src/main/java/com/arjunsk/compiler/ck/parser/Parser.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.ck.parser;
2 |
3 | import com.arjunsk.compiler.ck.domain.token.Token;
4 | import com.arjunsk.compiler.ck.domain.token.support.TokenType;
5 | import com.arjunsk.compiler.ck.domain.tree.nodes.common.TerminalNode;
6 | import com.arjunsk.compiler.ck.domain.tree.nodes.grammer.impl.LetContext;
7 | import com.arjunsk.compiler.ck.domain.tree.nodes.grammer.impl.ProgramContext;
8 | import com.arjunsk.compiler.ck.domain.tree.nodes.grammer.impl.ShowContext;
9 | import com.arjunsk.compiler.ck.domain.tree.nodes.grammer.impl.StatementContext;
10 | import com.arjunsk.compiler.ck.exceptions.ParserException;
11 | import com.arjunsk.compiler.ck.lexer.Lexer;
12 | import java.util.ArrayList;
13 | import java.util.List;
14 |
15 | public class Parser {
16 |
17 | private final Lexer lexer;
18 |
19 | public Parser(Lexer lexer) {
20 | this.lexer = lexer;
21 | }
22 |
23 | /**
24 | * Parse Logic for Program.
25 | *
26 | *
NOTE: We will use if-else to create a Deterministic Finite Automata (DFA).
27 | */
28 | public ProgramContext parseProgram() {
29 | List statements = new ArrayList<>();
30 | do {
31 | statements.add(parseStatement());
32 | } while (lexer.nextToken());
33 | return new ProgramContext(statements);
34 | }
35 |
36 | /** Parse Logic for Statement. Creates a LET or SHOW statement based on the Tokens passed. */
37 | public StatementContext parseStatement() {
38 |
39 | if (lexer.getCurrentToken() == null) {
40 | lexer.nextToken(); // Current Token = LET | SHOW
41 | }
42 |
43 | Token token = lexer.getCurrentToken(); // LET | SHOW
44 |
45 | if (token.getType() == TokenType.VARIABLE) { // LET
46 | return new StatementContext(parseLet(), null);
47 | } else if (token.getType() == TokenType.SHOW) { // SHOW
48 | return new StatementContext(null, parseShow());
49 | } else {
50 | throw new ParserException("Not of type LET or SHOW.");
51 | }
52 | }
53 |
54 | /** Parse Logic for Let. */
55 | public LetContext parseLet() {
56 | if (lexer.getCurrentToken() == null) {
57 | lexer.nextToken(); // Current Token = VAR
58 | }
59 | TerminalNode variableNameToken = parseTerminalNode(); // VAR
60 |
61 | lexer.nextToken(); // move to : =
62 | lexer.nextToken(); // move to : INT
63 |
64 | TerminalNode valueToken = parseTerminalNode(); // INT
65 |
66 | return new LetContext(variableNameToken, valueToken);
67 | }
68 |
69 | /** Parse Logic for Show. */
70 | public ShowContext parseShow() {
71 |
72 | if (lexer.getCurrentToken() == null) {
73 | lexer.nextToken(); // Current Token = SHOW
74 | }
75 |
76 | lexer.nextToken(); // Current Token = VAR | INT
77 |
78 | TerminalNode terminal = parseTerminalNode(); // VAR | INT
79 | final Token token = (Token) terminal.getPayload();
80 |
81 | if (token.getType() == TokenType.NUMBER) {
82 | return new ShowContext(terminal, null);
83 | } else if (token.getType() == TokenType.VARIABLE) {
84 | return new ShowContext(null, terminal);
85 | } else {
86 | throw new ParserException("Show not preceded with var or int");
87 | }
88 | }
89 |
90 | /** Parse Logic for Terminal Node. */
91 | public TerminalNode parseTerminalNode() {
92 |
93 | if (lexer.getCurrentToken() == null) {
94 | lexer.nextToken(); // Current Token = VAR | INT
95 | }
96 |
97 | TerminalNode token = new TerminalNode();
98 | token.setSymbol(lexer.getCurrentToken());
99 | return token;
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/compiler-examples/ck-compiler/src/main/java/com/arjunsk/compiler/ck/visitor/SimplerLangBaseVisitor.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.ck.visitor;
2 |
3 | import com.arjunsk.compiler.ck.domain.tree.ParseTree;
4 | import com.arjunsk.compiler.ck.domain.tree.nodes.common.TerminalNode;
5 | import com.arjunsk.compiler.ck.domain.tree.nodes.grammer.impl.LetContext;
6 | import com.arjunsk.compiler.ck.domain.tree.nodes.grammer.impl.ProgramContext;
7 | import com.arjunsk.compiler.ck.domain.tree.nodes.grammer.impl.ShowContext;
8 | import com.arjunsk.compiler.ck.domain.tree.nodes.grammer.impl.StatementContext;
9 |
10 | public class SimplerLangBaseVisitor implements Visitor {
11 |
12 | @Override
13 | public T visitProgram(ProgramContext context) {
14 | return visitChildren(context);
15 | }
16 |
17 | @Override
18 | public T visitStatement(StatementContext context) {
19 | return visitChildren(context);
20 | }
21 |
22 | @Override
23 | public T visitLet(LetContext context) {
24 | return visitChildren(context);
25 | }
26 |
27 | @Override
28 | public T visitShow(ShowContext context) {
29 | return visitChildren(context);
30 | }
31 |
32 | /** There is no child to propagate. */
33 | @Override
34 | public T visitTerminal(TerminalNode context) {
35 | return defaultResult();
36 | }
37 |
38 | /**
39 | * Propagate visitor to the children.
40 | *
41 | * So when you call invoke something like this
42 | *
43 | *
44 | * ParseTree tree = parser.parseProgram();
45 | * SimplerLangCustomVisitor visitor = new SimplerLangCustomVisitor();
46 | * tree.accept(visitor);
47 | *
48 | *
49 | * The accept(visitor) `visitor` is propagated to the children of that tree node.
50 | *
51 | * @param node Visitable implementation
52 | */
53 | public T visitChildren(ParseTree node) {
54 | T result = defaultResult();
55 | for (int i = 0; i < node.getChildCount(); i++) {
56 | ParseTree c = node.getChild(i);
57 | result = c.accept(this);
58 | }
59 |
60 | return result; // return the last accept result of the children list.
61 | }
62 |
63 | protected T defaultResult() {
64 | return null;
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/compiler-examples/ck-compiler/src/main/java/com/arjunsk/compiler/ck/visitor/Visitor.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.ck.visitor;
2 |
3 | import com.arjunsk.compiler.ck.domain.tree.nodes.common.TerminalNode;
4 | import com.arjunsk.compiler.ck.domain.tree.nodes.grammer.impl.LetContext;
5 | import com.arjunsk.compiler.ck.domain.tree.nodes.grammer.impl.ProgramContext;
6 | import com.arjunsk.compiler.ck.domain.tree.nodes.grammer.impl.ShowContext;
7 | import com.arjunsk.compiler.ck.domain.tree.nodes.grammer.impl.StatementContext;
8 |
9 | /**
10 | * Visitor Pattern used for separating Business logic from domain class code.
11 | *
12 | * @param Return type of visitXXX. Could be Void, Boolean etc.
13 | */
14 | public interface Visitor {
15 |
16 | T visitProgram(ProgramContext context);
17 |
18 | T visitStatement(StatementContext context);
19 |
20 | T visitLet(LetContext context);
21 |
22 | T visitShow(ShowContext context);
23 |
24 | T visitTerminal(TerminalNode context);
25 | }
26 |
--------------------------------------------------------------------------------
/compiler-examples/ck-compiler/src/main/java/com/arjunsk/compiler/ck/visitor/codegenerator/CodeGeneratorVisitor.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.ck.visitor.codegenerator;
2 |
3 | import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
4 | import static org.objectweb.asm.Opcodes.ACC_STATIC;
5 | import static org.objectweb.asm.Opcodes.ACC_SUPER;
6 | import static org.objectweb.asm.Opcodes.ALOAD;
7 | import static org.objectweb.asm.Opcodes.ASTORE;
8 | import static org.objectweb.asm.Opcodes.BIPUSH;
9 | import static org.objectweb.asm.Opcodes.GETSTATIC;
10 | import static org.objectweb.asm.Opcodes.INVOKESTATIC;
11 | import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
12 | import static org.objectweb.asm.Opcodes.V1_8;
13 |
14 | import com.arjunsk.compiler.ck.domain.tree.nodes.grammer.impl.LetContext;
15 | import com.arjunsk.compiler.ck.domain.tree.nodes.grammer.impl.ProgramContext;
16 | import com.arjunsk.compiler.ck.domain.tree.nodes.grammer.impl.ShowContext;
17 | import com.arjunsk.compiler.ck.visitor.SimplerLangBaseVisitor;
18 | import java.io.File;
19 | import java.io.FileOutputStream;
20 | import java.util.HashMap;
21 | import java.util.Map;
22 | import org.objectweb.asm.ClassWriter;
23 | import org.objectweb.asm.MethodVisitor;
24 | import org.objectweb.asm.Type;
25 |
26 | /**
27 | * Visitor that converts AST to .class java byte code.
28 | *
29 | * NOTE 1: To generate ASM code from Java Class you can use ASMifier. This will help you write
30 | * complex ASM codes. Ref:- @see Java
32 | * ASMifier
33 | *
34 | *
NOTE 2: Ops Code reference: @see Java Ops Code
36 | */
37 | public class CodeGeneratorVisitor extends SimplerLangBaseVisitor {
38 |
39 | // Class Writer
40 | private final ClassWriter classWriter;
41 |
42 | // For assigning correct variable index from LET to SHOW.
43 | private final Map variableIndexMap;
44 | private int variableIndex;
45 |
46 | // Main Method visitor used across LET and SHOW.
47 | private MethodVisitor mainMethodVisitor;
48 |
49 | public CodeGeneratorVisitor() {
50 | this.classWriter = new ClassWriter(0);
51 | variableIndexMap = new HashMap<>();
52 |
53 | // Variable0 is reserved for args[] in : `main(String[] var0)`
54 | variableIndex = 1;
55 | }
56 |
57 | /** Called when the program node is visited. The main entry point. */
58 | @Override
59 | public Void visitProgram(ProgramContext context) {
60 |
61 | /** ASM = CODE : public class CgSample. */
62 | // BEGIN 1: creates a ClassWriter for the `CgSample.class` public class,
63 | classWriter.visit(
64 | V1_8, // Java 1.8
65 | ACC_PUBLIC + ACC_SUPER, // public static
66 | "CgSample", // Class Name
67 | null, // Generics
68 | "java/lang/Object", // Interface extends Object (Super Class),
69 | null // interface names
70 | );
71 |
72 | /** ASM = CODE : public static void main(String args[]). */
73 | // BEGIN 2: creates a MethodVisitor for the 'main' method
74 | mainMethodVisitor =
75 | classWriter.visitMethod(
76 | ACC_PUBLIC + ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null);
77 |
78 | super.visitProgram(context);
79 |
80 | // END 2: Close main()
81 | mainMethodVisitor.visitEnd();
82 |
83 | // END 1: Close class()
84 | classWriter.visitEnd();
85 |
86 | byte[] code = classWriter.toByteArray();
87 | writeToFile(code, "output/CgSample.class");
88 |
89 | return null;
90 | }
91 |
92 | @Override
93 | public Void visitLet(LetContext context) {
94 |
95 | /** ASM = BIPUSH : Push bytes. */
96 | int variableIntegerVal = Integer.parseInt(context.getVariableValue().getText());
97 | mainMethodVisitor.visitIntInsn(BIPUSH, variableIntegerVal);
98 |
99 | /** ASM = CODE : Integer.valueOf( ) . */
100 | mainMethodVisitor.visitMethodInsn(
101 | INVOKESTATIC,
102 | Type.getType(Integer.class).getInternalName(),
103 | "valueOf",
104 | "(I)Ljava/lang/Integer;",
105 | false);
106 |
107 | /**
108 | * ASM = ASTORE : Store reference into local variable.
109 | *
110 | * This stores the above valueOf(INT) as Integer Variable.
111 | */
112 | // STORE to Variable Pool at variableIndex
113 | mainMethodVisitor.visitVarInsn(ASTORE, variableIndex);
114 |
115 | // Saving the variableIndex for reference in SHOW()
116 | variableIndexMap.put(context.getVariableName().getText(), variableIndex);
117 | variableIndex++;
118 |
119 | return null;
120 | }
121 |
122 | @Override
123 | public Void visitShow(ShowContext context) {
124 |
125 | /** ASM = CODE : System.out */
126 | mainMethodVisitor.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
127 |
128 | if (context.getVariableName() != null) {
129 |
130 | /**
131 | * ASM = LOAD Variable: ALOAD variable
132 | *
133 | *
ALOAD: Load reference from local variable
134 | */
135 | // Fetch index from VariablePool
136 | int index = variableIndexMap.get(context.getVariableName().getText());
137 | // LOAD from variable pool
138 | mainMethodVisitor.visitVarInsn(ALOAD, index);
139 |
140 | /** ASM = INVOKE: println(Object) with variable loaded via ALOAD. */
141 | mainMethodVisitor.visitMethodInsn(
142 | INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/Object;)V", false);
143 | } else if (context.getIntegerValue() != null) {
144 |
145 | /** ASM = BIPUSH: Push byte. */
146 |
147 | // Get integer value of the constant.
148 | int integerVal = Integer.parseInt(context.getIntegerValue().getText());
149 | // PUSH integerValue
150 | mainMethodVisitor.visitIntInsn(BIPUSH, integerVal);
151 |
152 | /** ASM = INVOKE: println(I) with variable loaded via ALOAD. */
153 | mainMethodVisitor.visitMethodInsn(
154 | INVOKEVIRTUAL, "java/io/PrintStream", "println", "(I)V", false);
155 | }
156 | return null;
157 | }
158 |
159 | /**
160 | * Writes Byte Array to a file
161 | *
162 | * @param code Byte Array of Source code.
163 | * @param filePath File Path to write. Eg:- "Example.class"
164 | */
165 | private void writeToFile(byte[] code, String filePath) {
166 |
167 | File file = new File(filePath);
168 | file.getParentFile().mkdirs();
169 |
170 | try (FileOutputStream fos = new FileOutputStream(filePath)) {
171 | fos.write(code);
172 | } catch (Exception ex) {
173 | ex.printStackTrace();
174 | }
175 | }
176 | }
177 |
--------------------------------------------------------------------------------
/compiler-examples/ck-compiler/src/main/java/com/arjunsk/compiler/ck/visitor/interpreter/InterpreterVisitor.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.ck.visitor.interpreter;
2 |
3 | import com.arjunsk.compiler.ck.domain.tree.nodes.grammer.impl.LetContext;
4 | import com.arjunsk.compiler.ck.domain.tree.nodes.grammer.impl.ShowContext;
5 | import com.arjunsk.compiler.ck.visitor.SimplerLangBaseVisitor;
6 | import java.util.HashMap;
7 | import java.util.Map;
8 |
9 | /**
10 | * SimplerLang Interpreter Implementation. Interpreter executes code line by line.
11 | *
12 | *
NOTE: Here we write the logic for storing the `let` variable and displaying the `show` output.
13 | */
14 | public class InterpreterVisitor extends SimplerLangBaseVisitor {
15 |
16 | private final Map variableMap;
17 |
18 | public InterpreterVisitor() {
19 | super();
20 | variableMap = new HashMap<>();
21 | }
22 |
23 | @Override
24 | public Void visitLet(LetContext context) {
25 | this.variableMap.put(context.getVariableName().getText(), context.getVariableValue().getText());
26 | return super.visitLet(context);
27 | }
28 |
29 | @Override
30 | public Void visitShow(ShowContext context) {
31 | if (context.getIntegerValue() != null) {
32 | System.out.println(context.getIntegerValue().getText());
33 | } else if (context.getVariableName() != null) {
34 | System.out.println(this.variableMap.get(context.getVariableName().getText()));
35 | }
36 | return super.visitShow(context);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/compiler-examples/ck-compiler/src/main/java/com/arjunsk/compiler/ck/visitor/semantic/SemanticAnalyzer.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.ck.visitor.semantic;
2 |
3 | import com.arjunsk.compiler.ck.domain.tree.nodes.common.TerminalNode;
4 | import com.arjunsk.compiler.ck.domain.tree.nodes.grammer.impl.LetContext;
5 | import com.arjunsk.compiler.ck.domain.tree.nodes.grammer.impl.ShowContext;
6 | import com.arjunsk.compiler.ck.domain.tree.nodes.grammer.impl.StatementContext;
7 | import com.arjunsk.compiler.ck.exceptions.SemanticException;
8 | import com.arjunsk.compiler.ck.visitor.SimplerLangBaseVisitor;
9 | import java.util.HashMap;
10 | import java.util.Map;
11 |
12 | /**
13 | * `Syntax` is the concept that concerns itself only whether or not the sentence is valid for the
14 | * grammar of the language. `Semantics` is about whether or not the sentence has a valid meaning.
15 | *
16 | * NOTE: checking whether the variable is declared before "SHOW VAR" is an example of `Semantic`
17 | * check.
18 | */
19 | public class SemanticAnalyzer extends SimplerLangBaseVisitor {
20 |
21 | private final Map variableMap;
22 |
23 | public SemanticAnalyzer() {
24 | super();
25 | this.variableMap = new HashMap<>();
26 | }
27 |
28 | /** Validate Statement Semantics. */
29 | @Override
30 | public Void visitStatement(StatementContext context) {
31 | if (context.getLetContext() == null && context.getShowContext() == null) {
32 | throw new SemanticException("Statement should of type LET or SHOW.");
33 | } else if (context.getLetContext() != null && context.getShowContext() != null) {
34 | throw new SemanticException("Statement should be either of type LET or SHOW & not both.");
35 | }
36 |
37 | return super.visitStatement(context);
38 | }
39 |
40 | /** Validate LET Semantics. */
41 | @Override
42 | public Void visitLet(LetContext context) {
43 |
44 | String variableName = context.getVariableName().getText();
45 | String variableValue = context.getVariableValue().getText();
46 |
47 | if (variableName == null || variableName.isEmpty()) {
48 | throw new SemanticException("Variable name cannot be empty.");
49 | } else if (variableValue == null || variableValue.isEmpty()) {
50 | throw new SemanticException("Variable value cannot be empty.");
51 | }
52 |
53 | // Check if variable value is Integer. In our case, this will be already handled in the
54 | // Tokenizer.
55 | try {
56 | Integer.parseInt(variableValue);
57 | } catch (NumberFormatException | NullPointerException ex) {
58 | throw new SemanticException("Variable value should be integer.", ex);
59 | }
60 |
61 | // This will be used to check whether variable is declared using LET before invoking SHOW for
62 | // the variable.
63 | variableMap.put(variableName, variableValue);
64 |
65 | return super.visitLet(context);
66 | }
67 |
68 | /**
69 | * Validate SHOW Semantics.
70 | *
71 | * NOTE: We validate if the variable is previously declared using LET.
72 | */
73 | @Override
74 | public Void visitShow(ShowContext context) {
75 |
76 | TerminalNode variableNameTN = context.getVariableName();
77 | TerminalNode integerValueTN = context.getIntegerValue();
78 |
79 | /* 1. Checking whether either of VAR | INT is present.*/
80 | boolean isVarPresent = variableNameTN != null && !variableNameTN.getText().isEmpty();
81 | boolean isIntPresent = integerValueTN != null && !integerValueTN.getText().isEmpty();
82 |
83 | if (!isVarPresent && !isIntPresent) {
84 | throw new SemanticException("SHOW should have integer or variable as argument");
85 | } else if (isVarPresent && isIntPresent) {
86 | throw new SemanticException("SHOW should have either integer or variable as argument");
87 | }
88 |
89 | /* 2. If SHOW Argument is Number, check if it is an integer. In our case, this will be
90 | already handled in the Tokenizer.*/
91 | if (integerValueTN != null) {
92 | try {
93 | Integer.parseInt(integerValueTN.getText());
94 | } catch (NumberFormatException | NullPointerException ex) {
95 | throw new SemanticException("SHOW argument is not a valid integer.", ex);
96 | }
97 | }
98 |
99 | /* 3. if SHOW Argument is Variable, check if the variable is declared previously.*/
100 | if (variableNameTN != null && !variableMap.containsKey(variableNameTN.getText())) {
101 | throw new SemanticException("SHOW argument variable is not declared.");
102 | }
103 |
104 | return super.visitShow(context);
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/compiler-examples/ck-compiler/src/test/java/com/arjunsk/compiler/ck/CkCompilerTest.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.ck;
2 |
3 | import com.arjunsk.compiler.ck.domain.tree.ParseTree;
4 | import com.arjunsk.compiler.ck.lexer.Lexer;
5 | import com.arjunsk.compiler.ck.parser.Parser;
6 | import com.arjunsk.compiler.ck.visitor.codegenerator.CodeGeneratorVisitor;
7 | import com.arjunsk.compiler.ck.visitor.interpreter.InterpreterVisitor;
8 | import com.arjunsk.compiler.ck.visitor.semantic.SemanticAnalyzer;
9 | import com.arjunsk.compiler.utils.FileReaderUtil;
10 | import org.junit.Assert;
11 | import org.junit.Test;
12 |
13 | public class CkCompilerTest {
14 |
15 | @Test
16 | public void test_e2e() {
17 | // 0. Input Code
18 | final String sourceCode = FileReaderUtil.getResourceFileAsString("input/CgSample.ck");
19 |
20 | // 1. Lexer
21 | assert sourceCode != null;
22 | Lexer lexer = new Lexer(sourceCode);
23 |
24 | // 2. Parser
25 | Parser parser = new Parser(lexer);
26 | ParseTree tree = parser.parseProgram();
27 |
28 | Assert.assertNotNull(tree);
29 |
30 | // 3. Semantic Analyzer Visitor
31 | tree.accept(new SemanticAnalyzer());
32 |
33 | // 4.1 Interpreter Visitor
34 | tree.accept(new InterpreterVisitor());
35 |
36 | // 4.2 Compiler Visitor
37 | tree.accept(new CodeGeneratorVisitor());
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/compiler-examples/ck-compiler/src/test/java/com/arjunsk/compiler/ck/lexer/LexerTest.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.ck.lexer;
2 |
3 | import com.arjunsk.compiler.ck.domain.token.support.TokenType;
4 | import org.junit.Assert;
5 | import org.junit.Test;
6 |
7 | public class LexerTest {
8 |
9 | @Test
10 | public void test_tokenizer() {
11 |
12 | // 1. Arrange
13 | String sourceCode = "a = 10\n" + "show a";
14 |
15 | // 2. Act
16 | Lexer lexer = new Lexer(sourceCode);
17 |
18 | // 3. Assert
19 | Assert.assertTrue(lexer.nextToken());
20 | Assert.assertEquals(TokenType.VARIABLE, lexer.getCurrentToken().getType());
21 | Assert.assertEquals("a", lexer.getCurrentToken().getValue());
22 | Assert.assertNull(lexer.getPreviousToken());
23 |
24 | Assert.assertTrue(lexer.nextToken());
25 | Assert.assertEquals(TokenType.EQUALS_OPERATOR, lexer.getCurrentToken().getType());
26 | Assert.assertEquals(TokenType.VARIABLE, lexer.getPreviousToken().getType());
27 | Assert.assertEquals("a", lexer.getPreviousToken().getValue());
28 |
29 | Assert.assertTrue(lexer.nextToken());
30 | Assert.assertEquals(TokenType.NUMBER, lexer.getCurrentToken().getType());
31 | Assert.assertEquals("10", lexer.getCurrentToken().getValue());
32 | Assert.assertEquals(TokenType.EQUALS_OPERATOR, lexer.getPreviousToken().getType());
33 |
34 | Assert.assertTrue(lexer.nextToken());
35 | Assert.assertEquals(TokenType.SHOW, lexer.getCurrentToken().getType());
36 | Assert.assertEquals(TokenType.NUMBER, lexer.getPreviousToken().getType());
37 | Assert.assertEquals("10", lexer.getPreviousToken().getValue());
38 |
39 | Assert.assertTrue(lexer.nextToken());
40 | Assert.assertEquals(TokenType.VARIABLE, lexer.getCurrentToken().getType());
41 | Assert.assertEquals("a", lexer.getCurrentToken().getValue());
42 | Assert.assertEquals(TokenType.SHOW, lexer.getPreviousToken().getType());
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/compiler-examples/ck-compiler/src/test/java/com/arjunsk/compiler/ck/parser/ParserTest.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.ck.parser;
2 |
3 | import com.arjunsk.compiler.ck.domain.tree.ParseTree;
4 | import com.arjunsk.compiler.ck.lexer.Lexer;
5 | import org.junit.Assert;
6 | import org.junit.Test;
7 |
8 | public class ParserTest {
9 |
10 | @Test
11 | public void test_parser() {
12 |
13 | // 1. Arrange
14 | String sourceCode = "a = 10\n" + "show a\n" + "show 20";
15 | Lexer lexer = new Lexer(sourceCode);
16 |
17 | // 2. Act
18 | Parser parser = new Parser(lexer);
19 | ParseTree tree = parser.parseProgram();
20 |
21 | // 3. Assert
22 | Assert.assertEquals(3, tree.getChildCount());
23 | Assert.assertEquals(1, tree.getChild(0).getChildCount()); // Statement
24 | Assert.assertEquals(2, tree.getChild(0).getChild(0).getChildCount()); // LET a=10
25 |
26 | Assert.assertEquals(1, tree.getChild(1).getChildCount()); // Statement
27 | Assert.assertEquals(1, tree.getChild(1).getChild(0).getChildCount()); // SHOW show a
28 |
29 | Assert.assertEquals(1, tree.getChild(2).getChildCount()); // Statement
30 | Assert.assertEquals(1, tree.getChild(2).getChild(0).getChildCount()); // SHOW show 23
31 |
32 | Assert.assertEquals(
33 | "( ProgramContext( ( StatementContext( ( LetContext( a 10 ) ) ) ) ( StatementContext( ( ShowContext( a ) ) ) ) ( StatementContext( ( ShowContext( 20 ) ) ) ) ) )",
34 | tree.toStringTree());
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/compiler-examples/ck-compiler/src/test/java/com/arjunsk/compiler/ck/visitor/semantic/SemanticAnalyzerTest.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.ck.visitor.semantic;
2 |
3 | import static org.hamcrest.CoreMatchers.startsWith;
4 |
5 | import com.arjunsk.compiler.ck.domain.tree.ParseTree;
6 | import com.arjunsk.compiler.ck.exceptions.SemanticException;
7 | import com.arjunsk.compiler.ck.lexer.Lexer;
8 | import com.arjunsk.compiler.ck.parser.Parser;
9 | import org.junit.Rule;
10 | import org.junit.Test;
11 | import org.junit.rules.ExpectedException;
12 |
13 | public class SemanticAnalyzerTest {
14 |
15 | @Rule public final ExpectedException exceptionCatcher = ExpectedException.none();
16 |
17 | @Test
18 | public void test_variable_not_declared() {
19 | // 1. Arrange
20 | String sourceCode = "a = 10\n" + "show b";
21 | Lexer lexer = new Lexer(sourceCode);
22 |
23 | Parser parser = new Parser(lexer);
24 | ParseTree tree = parser.parseProgram();
25 |
26 | // 3. Assert
27 | exceptionCatcher.expect(SemanticException.class);
28 | exceptionCatcher.expectMessage(startsWith("SHOW argument variable is not declared."));
29 |
30 | // 2. Act
31 | tree.accept(new SemanticAnalyzer());
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/compiler-examples/ck-compiler/src/test/java/com/arjunsk/compiler/utils/FileReaderUtil.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.utils;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.InputStream;
5 | import java.io.InputStreamReader;
6 | import java.util.stream.Collectors;
7 |
8 | /** File Reader for reading files from test resource. */
9 | public class FileReaderUtil {
10 |
11 | /**
12 | * Reads given resource file as a string.
13 | *
14 | * @param fileName path to the resource file
15 | * @return the file's content in String
16 | */
17 | public static String getResourceFileAsString(String fileName) {
18 | ClassLoader classLoader = ClassLoader.getSystemClassLoader();
19 | try (InputStream is = classLoader.getResourceAsStream(fileName)) {
20 | if (is == null) return null;
21 | try (InputStreamReader isr = new InputStreamReader(is);
22 | BufferedReader reader = new BufferedReader(isr)) {
23 | return reader.lines().collect(Collectors.joining(System.lineSeparator()));
24 | }
25 | } catch (Exception ex) {
26 | throw new RuntimeException("Error reading file", ex);
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/compiler-examples/ck-compiler/src/test/resources/input/CgSample.ck:
--------------------------------------------------------------------------------
1 | a = 10
2 | show a
3 | show 20
4 | b = 30
5 | show b
6 | show a
--------------------------------------------------------------------------------
/compiler-examples/lisp-compiler/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 |
8 | com.arjunsk
9 | compiler-examples
10 | 1.0-SNAPSHOT
11 |
12 |
13 | lisp-compiler
14 |
15 |
16 |
--------------------------------------------------------------------------------
/compiler-examples/lisp-compiler/src/main/java/com/arjunsk/compiler/lisp/core/emitter/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dborchard/tiny-compiler/cda17b3ac617e8270c3f1358635f8052a012165a/compiler-examples/lisp-compiler/src/main/java/com/arjunsk/compiler/lisp/core/emitter/.gitkeep
--------------------------------------------------------------------------------
/compiler-examples/lisp-compiler/src/main/java/com/arjunsk/compiler/lisp/core/lexer/Lexer.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.lisp.core.lexer;
2 |
3 | import com.arjunsk.compiler.lisp.domain.lexer.Token;
4 | import com.arjunsk.compiler.lisp.domain.lexer.support.TokenType;
5 | import com.arjunsk.compiler.lisp.exceptions.LexerException;
6 | import java.util.ArrayList;
7 | import java.util.List;
8 |
9 | public class Lexer {
10 |
11 | /**
12 | * Convert code to token stream.
13 | *
14 | * @param input High Level Code
15 | * @return List of tokens
16 | */
17 | public List tokenize(String input) {
18 | List result = new ArrayList<>();
19 |
20 | int currentIndex = 0;
21 | char currentChar;
22 |
23 | while (currentIndex < input.length()) {
24 |
25 | currentChar = input.charAt(currentIndex);
26 |
27 | if (currentChar == '(' || currentChar == ')') {
28 | result.add(new Token(TokenType.PAREN, currentChar + ""));
29 | currentIndex++;
30 | } else if (currentChar == '\n' || currentChar == '\r' || currentChar == ' ') {
31 | currentIndex++;
32 | } else if (currentChar == '"') {
33 |
34 | // Iterate till ending double quote.
35 | currentChar = input.charAt(++currentIndex);
36 | StringBuilder value = new StringBuilder();
37 | while (currentChar != '"') {
38 | value.append(currentChar);
39 | currentChar = input.charAt(++currentIndex);
40 | }
41 | result.add(new Token(TokenType.STRING, value.toString()));
42 | } else if (Character.isDigit(currentChar)) {
43 |
44 | // Iterate till last digit of the number
45 | StringBuilder value = new StringBuilder();
46 | while (Character.isDigit(currentChar)) {
47 | value.append(currentChar);
48 | currentChar = input.charAt(++currentIndex);
49 | }
50 | result.add(new Token(TokenType.NUMBER, value.toString()));
51 | } else if (Character.isLetter(currentChar)) {
52 |
53 | // Iterate till last character of the word.
54 | StringBuilder value = new StringBuilder();
55 | while (Character.isLetter(currentChar)) {
56 | value.append(currentChar);
57 | currentChar = input.charAt(++currentIndex);
58 | }
59 | result.add(new Token(TokenType.NAME, value.toString()));
60 | } else {
61 | throw new LexerException();
62 | }
63 | }
64 |
65 | return result;
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/compiler-examples/lisp-compiler/src/main/java/com/arjunsk/compiler/lisp/core/parser/Parser.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.lisp.core.parser;
2 |
3 | import com.arjunsk.compiler.lisp.domain.ast.AstNode;
4 | import com.arjunsk.compiler.lisp.domain.lexer.Token;
5 | import com.arjunsk.compiler.lisp.domain.lexer.support.TokenType;
6 | import com.arjunsk.compiler.lisp.exceptions.ParserException;
7 | import java.util.List;
8 |
9 | public class Parser {
10 |
11 | private final List tokens;
12 |
13 | private int current = 0;
14 |
15 | public Parser(List tokens) {
16 | this.tokens = tokens;
17 | }
18 |
19 | public AstNode parse() {
20 | AstNode root = new AstNode("Program");
21 |
22 | while (current < tokens.size()) {
23 | root.appendParams(walk());
24 | }
25 |
26 | return root;
27 | }
28 |
29 | private AstNode walk() {
30 | Token token = tokens.get(current);
31 |
32 | if (token.getType() == TokenType.NUMBER) { // 1. Number
33 | current++;
34 | return new AstNode("NumberLiteral", token.getValue());
35 | } else if (token.getType() == TokenType.STRING) { // 2. Variable Name
36 | current++;
37 | return new AstNode("StringLiteral", token.getValue());
38 | } else if (token.getType() == TokenType.PAREN
39 | && token.getValue().equals("(")) { // 3. Expression
40 |
41 | token = tokens.get(++current);
42 | final String expressionName = token.getValue();
43 |
44 | // Base Node
45 | AstNode node = new AstNode("CallExpression", expressionName);
46 |
47 | token = tokens.get(++current);
48 |
49 | while ((token.getType() != TokenType.PAREN)
50 | || (token.getType() == TokenType.PAREN && !token.getValue().equals(")"))) {
51 |
52 | node.appendParams(walk());
53 | token = tokens.get(current);
54 | }
55 | current++;
56 | return node;
57 | } else {
58 | throw new ParserException();
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/compiler-examples/lisp-compiler/src/main/java/com/arjunsk/compiler/lisp/core/transformer/Transformer.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.lisp.core.transformer;
2 |
3 | import com.arjunsk.compiler.lisp.domain.ast.AstNode;
4 | import com.arjunsk.compiler.lisp.domain.ast.LispAstNode;
5 |
6 | // TODO: Continue from here
7 | public class Transformer {
8 |
9 | public LispAstNode transform(AstNode root) {
10 | LispAstNode newAst = new LispAstNode("Program");
11 | return newAst;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/compiler-examples/lisp-compiler/src/main/java/com/arjunsk/compiler/lisp/core/visitor/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dborchard/tiny-compiler/cda17b3ac617e8270c3f1358635f8052a012165a/compiler-examples/lisp-compiler/src/main/java/com/arjunsk/compiler/lisp/core/visitor/.gitkeep
--------------------------------------------------------------------------------
/compiler-examples/lisp-compiler/src/main/java/com/arjunsk/compiler/lisp/domain/ast/AstNode.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.lisp.domain.ast;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Iterator;
5 | import java.util.List;
6 |
7 | /** Input AST. */
8 | public class AstNode {
9 |
10 | private final String type; // CallExpression or NumberLiteral or StringLiteral
11 |
12 | private final String value; // Node Value
13 |
14 | private final List params;
15 |
16 | public AstNode(String type) {
17 | this.type = type;
18 | this.value = "";
19 | this.params = new ArrayList<>();
20 | }
21 |
22 | public AstNode(String type, String value) {
23 | this.type = type;
24 | this.value = value;
25 | this.params = new ArrayList<>();
26 | }
27 |
28 | public void appendParams(AstNode node) {
29 | this.params.add(node);
30 | }
31 |
32 | public String getType() {
33 | return type;
34 | }
35 |
36 | public String getValue() {
37 | return value;
38 | }
39 |
40 | public Iterator getParams() {
41 | return this.params.iterator();
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/compiler-examples/lisp-compiler/src/main/java/com/arjunsk/compiler/lisp/domain/ast/LispAstNode.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.lisp.domain.ast;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Iterator;
5 | import java.util.List;
6 |
7 | /** Transformed AST */
8 | public class LispAstNode {
9 |
10 | private final String type;
11 |
12 | private final String value;
13 |
14 | private final List arguments;
15 |
16 | public LispAstNode(String type) {
17 | this.type = type;
18 | this.value = "";
19 | this.arguments = new ArrayList<>();
20 | }
21 |
22 | public LispAstNode(String type, String value) {
23 | this.type = type;
24 | this.value = value;
25 | this.arguments = new ArrayList<>();
26 | }
27 |
28 | public void appendParams(LispAstNode node) {
29 | this.arguments.add(node);
30 | }
31 |
32 | public String getType() {
33 | return type;
34 | }
35 |
36 | public String getValue() {
37 | return value;
38 | }
39 |
40 | public Iterator getArguments() {
41 | return this.arguments.iterator();
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/compiler-examples/lisp-compiler/src/main/java/com/arjunsk/compiler/lisp/domain/lexer/Token.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.lisp.domain.lexer;
2 |
3 | import com.arjunsk.compiler.lisp.domain.lexer.support.TokenType;
4 |
5 | public class Token {
6 |
7 | private final TokenType type;
8 |
9 | private final String value;
10 |
11 | public Token(TokenType type, String value) {
12 | this.type = type;
13 | this.value = value;
14 | }
15 |
16 | public TokenType getType() {
17 | return type;
18 | }
19 |
20 | public String getValue() {
21 | return value;
22 | }
23 |
24 | @Override
25 | public String toString() {
26 | return this.type + " " + this.value;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/compiler-examples/lisp-compiler/src/main/java/com/arjunsk/compiler/lisp/domain/lexer/support/TokenType.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.lisp.domain.lexer.support;
2 |
3 | public enum TokenType {
4 | PAREN,
5 | NUMBER,
6 | STRING,
7 | NAME
8 | }
9 |
--------------------------------------------------------------------------------
/compiler-examples/lisp-compiler/src/main/java/com/arjunsk/compiler/lisp/exceptions/LexerException.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.lisp.exceptions;
2 |
3 | public class LexerException extends RuntimeException {
4 |
5 | public LexerException() {
6 | super("Exception in Lexer");
7 | }
8 |
9 | public LexerException(String message) {
10 | super(message);
11 | }
12 |
13 | public LexerException(String message, Throwable cause) {
14 | super(message, cause);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/compiler-examples/lisp-compiler/src/main/java/com/arjunsk/compiler/lisp/exceptions/ParserException.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.lisp.exceptions;
2 |
3 | public class ParserException extends RuntimeException {
4 |
5 | public ParserException() {
6 | super("Exception in Parsing");
7 | }
8 |
9 | public ParserException(String message) {
10 | super(message);
11 | }
12 |
13 | public ParserException(String message, Throwable cause) {
14 | super(message, cause);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/compiler-examples/lisp-compiler/src/test/java/com/arjunsk/compiler/lisp/core/lexer/LexerTest.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.lisp.core.lexer;
2 |
3 | import static org.junit.Assert.assertEquals;
4 |
5 | import com.arjunsk.compiler.lisp.domain.lexer.Token;
6 | import com.arjunsk.compiler.utils.FileReaderUtil;
7 | import java.util.List;
8 | import java.util.Objects;
9 | import org.junit.Test;
10 |
11 | public class LexerTest {
12 |
13 | @Test
14 | public void test_tokenize() {
15 |
16 | // 1. Arrange
17 | String hllCode =
18 | Objects.requireNonNull(FileReaderUtil.getResourceFileAsString("input/code.lsp"));
19 |
20 | // 2. Act
21 | List tokens = new Lexer().tokenize(hllCode);
22 |
23 | // 3. Assert
24 | assertEquals(9, tokens.size());
25 |
26 | // 4. Log
27 | tokens.forEach(System.out::println);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/compiler-examples/lisp-compiler/src/test/java/com/arjunsk/compiler/lisp/core/parser/ParserTest.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.lisp.core.parser;
2 |
3 | import static org.junit.Assert.assertNotNull;
4 |
5 | import com.arjunsk.compiler.lisp.core.lexer.Lexer;
6 | import com.arjunsk.compiler.lisp.domain.ast.AstNode;
7 | import com.arjunsk.compiler.lisp.domain.lexer.Token;
8 | import com.arjunsk.compiler.utils.FileReaderUtil;
9 | import java.util.ArrayList;
10 | import java.util.List;
11 | import java.util.Objects;
12 | import org.junit.Test;
13 |
14 | public class ParserTest {
15 |
16 | @Test
17 | public void test_parse() {
18 |
19 | // 1. Arrange
20 | String hllCode =
21 | Objects.requireNonNull(FileReaderUtil.getResourceFileAsString("input/code.lsp"));
22 | List tokens = new Lexer().tokenize(hllCode);
23 |
24 | // 2. Act
25 | AstNode root = new Parser(tokens).parse();
26 |
27 | // 3. Assert
28 | assertNotNull(root);
29 |
30 | // 4. Log
31 | System.out.println(printAst(root));
32 | }
33 |
34 | private String printAst(AstNode root) {
35 |
36 | if (root == null) return "";
37 |
38 | StringBuilder sb = new StringBuilder();
39 | sb.append(" Type: ")
40 | .append(root.getType())
41 | .append(" Value: ")
42 | .append(root.getValue())
43 | .append("\n");
44 |
45 | List children = new ArrayList<>();
46 | root.getParams()
47 | .forEachRemaining(
48 | item -> {
49 | String child = printAst(item);
50 | if (!child.isEmpty()) children.add(child);
51 | });
52 | if (!children.isEmpty()) {
53 | sb.append("[").append("\n");
54 | children.forEach(sb::append);
55 | sb.append("]").append("\n");
56 | }
57 |
58 | return sb.toString();
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/compiler-examples/lisp-compiler/src/test/java/com/arjunsk/compiler/utils/FileReaderUtil.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.utils;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.InputStream;
5 | import java.io.InputStreamReader;
6 | import java.util.stream.Collectors;
7 |
8 | /** File Reader for reading files from test resource. */
9 | public class FileReaderUtil {
10 |
11 | /**
12 | * Reads given resource file as a string.
13 | *
14 | * @param fileName path to the resource file
15 | * @return the file's content in String
16 | */
17 | public static String getResourceFileAsString(String fileName) {
18 | ClassLoader classLoader = ClassLoader.getSystemClassLoader();
19 | try (InputStream is = classLoader.getResourceAsStream(fileName)) {
20 | if (is == null) return null;
21 | try (InputStreamReader isr = new InputStreamReader(is);
22 | BufferedReader reader = new BufferedReader(isr)) {
23 | return reader.lines().collect(Collectors.joining(System.lineSeparator()));
24 | }
25 | } catch (Exception ex) {
26 | throw new RuntimeException("Error reading file", ex);
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/compiler-examples/lisp-compiler/src/test/resources/input/code.lsp:
--------------------------------------------------------------------------------
1 | (add 2 (subtract 4 2))
--------------------------------------------------------------------------------
/compiler-examples/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 |
8 | com.arjunsk
9 | codekrypt-compiler
10 | 1.0-SNAPSHOT
11 |
12 |
13 | compiler-examples
14 | pom
15 |
16 |
17 | svg-compiler
18 | lisp-compiler
19 | ck-compiler
20 |
21 |
22 |
--------------------------------------------------------------------------------
/compiler-examples/svg-compiler/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 |
8 | com.arjunsk
9 | compiler-examples
10 | 1.0-SNAPSHOT
11 |
12 |
13 | svg-compiler
14 |
15 |
16 |
--------------------------------------------------------------------------------
/compiler-examples/svg-compiler/src/main/java/com/arjunsk/compiler/svg/core/generation/CodeGenerator.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.svg.core.generation;
2 |
3 | import com.arjunsk.compiler.svg.domain.transformer.ast.SvgAstNode;
4 |
5 | /** Convert to SVG based on Transformed AST. */
6 | public class CodeGenerator {
7 |
8 | public String generate(SvgAstNode node) {
9 | return printAst(node);
10 | }
11 |
12 | /** using recursion to process transformed AST. */
13 | private String printAst(SvgAstNode root) {
14 |
15 | if (root == null) return "";
16 |
17 | StringBuilder sb = new StringBuilder();
18 |
19 | sb.append("<").append(root.getTag());
20 |
21 | root.getAttributes()
22 | .forEachRemaining(
23 | item ->
24 | sb.append(" ")
25 | .append(item.getKey())
26 | .append("=")
27 | .append("\"")
28 | .append(item.getValue())
29 | .append("\""));
30 |
31 | sb.append(">");
32 |
33 | root.getBody().forEachRemaining(item -> sb.append("\n").append(printAst(item)));
34 |
35 | sb.append("\n").append("").append(root.getTag()).append(">");
36 |
37 | return sb.toString();
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/compiler-examples/svg-compiler/src/main/java/com/arjunsk/compiler/svg/core/parsing/Lexer.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.svg.core.parsing;
2 |
3 | import com.arjunsk.compiler.svg.domain.lexer.token.Token;
4 | import com.arjunsk.compiler.svg.domain.lexer.token.support.TokenType;
5 | import com.arjunsk.compiler.svg.exceptions.LexerException;
6 | import java.util.Arrays;
7 | import java.util.List;
8 | import java.util.stream.Collectors;
9 |
10 | /*
11 |
12 | Input:
13 | Paper 100
14 |
15 | Output:
16 | WORD Paper
17 | NUMBER 100
18 |
19 | */
20 |
21 | /** Convert Input Code to Token's. */
22 | public final class Lexer {
23 |
24 | private Lexer() {}
25 |
26 | public static List tokenize(String hllCode) {
27 |
28 | return Arrays.stream(hllCode.split("\\s+"))
29 | .filter(element -> !element.trim().isEmpty())
30 | .map(
31 | element -> {
32 | char firstChar = element.charAt(0);
33 | if (Character.isLetter(firstChar)) {
34 | return new Token(TokenType.WORD, element);
35 | } else if (isNumeric(element)) {
36 | return new Token(TokenType.NUMBER, element);
37 | } else {
38 | throw new LexerException();
39 | }
40 | })
41 | .collect(Collectors.toList());
42 | }
43 |
44 | private static boolean isNumeric(String num) {
45 | return num.chars().allMatch(Character::isDigit);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/compiler-examples/svg-compiler/src/main/java/com/arjunsk/compiler/svg/core/parsing/Parser.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.svg.core.parsing;
2 |
3 | import com.arjunsk.compiler.svg.domain.lexer.ast.AstNode;
4 | import com.arjunsk.compiler.svg.domain.lexer.ast.support.AstNodeClass;
5 | import com.arjunsk.compiler.svg.domain.lexer.token.Token;
6 | import com.arjunsk.compiler.svg.domain.lexer.token.support.TokenType;
7 | import com.arjunsk.compiler.svg.exceptions.ParserException;
8 | import java.util.ArrayList;
9 | import java.util.List;
10 |
11 | public class Parser {
12 |
13 | private final List tokens;
14 |
15 | private int currentTokenIndex;
16 |
17 | public Parser(List tokens) {
18 | this.tokens = tokens;
19 | this.currentTokenIndex = 0;
20 | }
21 |
22 | public AstNode parse() {
23 |
24 | AstNode ast = new AstNode(AstNodeClass.BLOCK);
25 |
26 | boolean isPaperDefined = false;
27 | boolean isPenDefined = false;
28 |
29 | while (currentTokenIndex < tokens.size()) {
30 | Token currentToken = tokens.get(currentTokenIndex);
31 |
32 | if (currentToken.getType() == TokenType.WORD) {
33 | AstNode expression;
34 |
35 | switch (currentToken.getValue()) {
36 | case "Paper":
37 | if (isPaperDefined) throw new ParserException("Paper already defined");
38 |
39 | expression = new AstNode(AstNodeClass.CALL_EXPRESSION, "Paper");
40 | findNumericalArguments(1).forEach(expression::appendNode);
41 | ast.appendNode(expression);
42 | isPaperDefined = true;
43 | break;
44 | case "Pen":
45 | if (isPenDefined) throw new ParserException("Pen already defined");
46 |
47 | expression = new AstNode(AstNodeClass.CALL_EXPRESSION, "Pen");
48 | findNumericalArguments(1).forEach(expression::appendNode);
49 | ast.appendNode(expression);
50 | isPenDefined = true;
51 | break;
52 | case "Line":
53 | if (!(isPaperDefined && isPenDefined))
54 | throw new ParserException("No Paper & Pen defined");
55 |
56 | expression = new AstNode(AstNodeClass.CALL_EXPRESSION, "Line");
57 | findNumericalArguments(4).forEach(expression::appendNode);
58 | ast.appendNode(expression);
59 | break;
60 | default:
61 | throw new ParserException("Invalid Token");
62 | }
63 | } else {
64 | throw new ParserException("Unexpected Token Type" + currentToken.getType());
65 | }
66 | currentTokenIndex = currentTokenIndex + 1;
67 | }
68 | return ast;
69 | }
70 |
71 | private List findNumericalArguments(int argCount) {
72 | List result = new ArrayList<>();
73 | while (argCount-- > 0) {
74 | result.add(new AstNode(AstNodeClass.NUMBER, tokens.get(++currentTokenIndex).getValue()));
75 | }
76 | return result;
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/compiler-examples/svg-compiler/src/main/java/com/arjunsk/compiler/svg/core/transforming/Transformer.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.svg.core.transforming;
2 |
3 | import com.arjunsk.compiler.svg.domain.lexer.ast.AstNode;
4 | import com.arjunsk.compiler.svg.domain.lexer.ast.support.AstNodeClass;
5 | import com.arjunsk.compiler.svg.domain.transformer.ast.SvgAstNode;
6 | import com.arjunsk.compiler.svg.exceptions.TransformerException;
7 | import java.util.Iterator;
8 |
9 | /** Transform the AST to SVG AST. */
10 | public class Transformer {
11 |
12 | public SvgAstNode transform(AstNode oldAst) {
13 |
14 | SvgAstNode newAst = new SvgAstNode("svg");
15 | newAst.appendAttributes("width", 100);
16 | newAst.appendAttributes("height", 100);
17 | newAst.appendAttributes("viewBox", "0 0 100 100");
18 | newAst.appendAttributes("xmlns", "http://www.w3.org/2000/svg");
19 | newAst.appendAttributes("version", "1.1");
20 |
21 | AstNode currentAstNode;
22 | String penColor = "89";
23 | SvgAstNode expression;
24 |
25 | final Iterator children = oldAst.getChildren();
26 | while (children.hasNext()) {
27 | currentAstNode = children.next();
28 | if (currentAstNode.getNodeClass() == AstNodeClass.CALL_EXPRESSION) {
29 | switch (currentAstNode.getValue()) {
30 | case "Paper":
31 | expression = new SvgAstNode("rect");
32 | expression.appendAttributes("x", 0);
33 | expression.appendAttributes("y", 0);
34 | expression.appendAttributes("width", 100);
35 | expression.appendAttributes("height", 100);
36 | expression.appendAttributes(
37 | "fill", makeColor(currentAstNode.getChildren().next().getValue()));
38 | newAst.appendBody(expression);
39 | break;
40 | case "Pen":
41 | penColor = currentAstNode.getChildren().next().getValue();
42 | break;
43 | case "Line":
44 | expression = new SvgAstNode("line");
45 | final Iterator lineArgs = currentAstNode.getChildren();
46 | expression.appendAttributes("x1", Integer.parseInt(lineArgs.next().getValue()));
47 | expression.appendAttributes("y1", Integer.parseInt(lineArgs.next().getValue()));
48 | expression.appendAttributes("x2", Integer.parseInt(lineArgs.next().getValue()));
49 | expression.appendAttributes("y2", Integer.parseInt(lineArgs.next().getValue()));
50 | expression.appendAttributes("stroke", makeColor(penColor));
51 | expression.appendAttributes("stroke-linecap", "round");
52 | newAst.appendBody(expression);
53 | break;
54 | default:
55 | throw new TransformerException("Invalid Token");
56 | }
57 | }
58 | }
59 |
60 | return newAst;
61 | }
62 |
63 | private String makeColor(String level) {
64 | int output = 100 - Integer.parseInt(level);
65 | return "rgb(" + output + "%, " + output + "%, " + output + "%)";
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/compiler-examples/svg-compiler/src/main/java/com/arjunsk/compiler/svg/domain/lexer/ast/AstNode.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.svg.domain.lexer.ast;
2 |
3 | import com.arjunsk.compiler.svg.domain.lexer.ast.support.AstNodeClass;
4 | import java.util.ArrayList;
5 | import java.util.Iterator;
6 | import java.util.List;
7 |
8 | public class AstNode {
9 |
10 | private final AstNodeClass nodeClass;
11 |
12 | private final String value;
13 |
14 | private final List children = new ArrayList<>();
15 |
16 | public AstNode(AstNodeClass nodeClass, String value) {
17 | this.nodeClass = nodeClass;
18 | this.value = value;
19 | }
20 |
21 | public AstNode(AstNodeClass nodeClass) {
22 | this.nodeClass = nodeClass;
23 | this.value = "";
24 | }
25 |
26 | public AstNodeClass getNodeClass() {
27 | return nodeClass;
28 | }
29 |
30 | public String getValue() {
31 | return value;
32 | }
33 |
34 | public Iterator getChildren() {
35 | return this.children.iterator();
36 | }
37 |
38 | public void appendNode(AstNode astNode) {
39 | this.children.add(astNode);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/compiler-examples/svg-compiler/src/main/java/com/arjunsk/compiler/svg/domain/lexer/ast/support/AstNodeClass.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.svg.domain.lexer.ast.support;
2 |
3 | public enum AstNodeClass {
4 | BLOCK,
5 | CALL_EXPRESSION,
6 | NUMBER
7 | }
8 |
--------------------------------------------------------------------------------
/compiler-examples/svg-compiler/src/main/java/com/arjunsk/compiler/svg/domain/lexer/token/Token.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.svg.domain.lexer.token;
2 |
3 | import com.arjunsk.compiler.svg.domain.lexer.token.support.TokenType;
4 |
5 | public class Token {
6 |
7 | private final TokenType type;
8 |
9 | private final String value;
10 |
11 | public Token(TokenType type, String value) {
12 | this.type = type;
13 | this.value = value;
14 | }
15 |
16 | public TokenType getType() {
17 | return type;
18 | }
19 |
20 | public String getValue() {
21 | return value;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/compiler-examples/svg-compiler/src/main/java/com/arjunsk/compiler/svg/domain/lexer/token/support/TokenType.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.svg.domain.lexer.token.support;
2 |
3 | public enum TokenType {
4 | WORD,
5 | NUMBER
6 | }
7 |
--------------------------------------------------------------------------------
/compiler-examples/svg-compiler/src/main/java/com/arjunsk/compiler/svg/domain/transformer/ast/SvgAstNode.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.svg.domain.transformer.ast;
2 |
3 | import java.util.ArrayList;
4 | import java.util.HashMap;
5 | import java.util.Iterator;
6 | import java.util.List;
7 | import java.util.Map;
8 | import java.util.Map.Entry;
9 |
10 | public class SvgAstNode {
11 |
12 | private final String tag;
13 | private final Map attributes;
14 | private final List body;
15 |
16 | public SvgAstNode(String tag) {
17 | this.tag = tag;
18 | this.attributes = new HashMap<>();
19 | this.body = new ArrayList<>();
20 | }
21 |
22 | public void appendBody(SvgAstNode node) {
23 | this.body.add(node);
24 | }
25 |
26 | public void appendAttributes(String key, Object value) {
27 | attributes.put(key, value);
28 | }
29 |
30 | public String getTag() {
31 | return tag;
32 | }
33 |
34 | public Iterator> getAttributes() {
35 | return attributes.entrySet().iterator();
36 | }
37 |
38 | public Iterator getBody() {
39 | return body.iterator();
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/compiler-examples/svg-compiler/src/main/java/com/arjunsk/compiler/svg/exceptions/LexerException.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.svg.exceptions;
2 |
3 | public class LexerException extends RuntimeException {
4 |
5 | public LexerException() {
6 | super("Exception While Lexical Tokenizing");
7 | }
8 |
9 | public LexerException(String message, Throwable cause) {
10 | super(message, cause);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/compiler-examples/svg-compiler/src/main/java/com/arjunsk/compiler/svg/exceptions/ParserException.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.svg.exceptions;
2 |
3 | public class ParserException extends RuntimeException {
4 |
5 | public ParserException() {
6 | super("Exception While Parsing");
7 | }
8 |
9 | public ParserException(String message) {
10 | super(message);
11 | }
12 |
13 | public ParserException(String message, Throwable cause) {
14 | super(message, cause);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/compiler-examples/svg-compiler/src/main/java/com/arjunsk/compiler/svg/exceptions/TransformerException.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.svg.exceptions;
2 |
3 | public class TransformerException extends RuntimeException {
4 |
5 | public TransformerException() {
6 | super("Exception While Transforming");
7 | }
8 |
9 | public TransformerException(String message) {
10 | super(message);
11 | }
12 |
13 | public TransformerException(String message, Throwable cause) {
14 | super(message, cause);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/compiler-examples/svg-compiler/src/test/java/com/arjunsk/compiler/svg/core/generation/CodeGeneratorTest.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.svg.core.generation;
2 |
3 | import static org.junit.Assert.assertNotNull;
4 |
5 | import com.arjunsk.compiler.svg.core.parsing.Lexer;
6 | import com.arjunsk.compiler.svg.core.parsing.Parser;
7 | import com.arjunsk.compiler.svg.core.transforming.Transformer;
8 | import com.arjunsk.compiler.svg.domain.lexer.ast.AstNode;
9 | import com.arjunsk.compiler.svg.domain.lexer.token.Token;
10 | import com.arjunsk.compiler.svg.domain.transformer.ast.SvgAstNode;
11 | import com.arjunsk.compiler.utils.FileReaderUtil;
12 | import java.io.FileWriter;
13 | import java.util.List;
14 | import java.util.Objects;
15 | import org.junit.Test;
16 |
17 | public class CodeGeneratorTest {
18 |
19 | @Test
20 | public void test_generate() {
21 |
22 | // 1. Arrange
23 | String hllCode =
24 | Objects.requireNonNull(FileReaderUtil.getResourceFileAsString("lexer/code.ck"));
25 | List tokens = Lexer.tokenize(hllCode);
26 | AstNode oldAst = new Parser(tokens).parse();
27 | SvgAstNode newAst = new Transformer().transform(oldAst);
28 |
29 | // 2. Act
30 | String result = new CodeGenerator().generate(newAst);
31 |
32 | // 3. Assert
33 | assertNotNull(result);
34 |
35 | // 4. Log
36 | System.out.println(result);
37 | saveToFile(result, "src/test/resources/output/code.svg");
38 | }
39 |
40 | private void saveToFile(String data, String filename) {
41 | try (FileWriter fw = new FileWriter(filename)) {
42 | fw.write(data);
43 | } catch (Exception e) {
44 | throw new RuntimeException(e);
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/compiler-examples/svg-compiler/src/test/java/com/arjunsk/compiler/svg/core/parsing/LexerTest.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.svg.core.parsing;
2 |
3 | import com.arjunsk.compiler.svg.domain.lexer.token.Token;
4 | import com.arjunsk.compiler.utils.FileReaderUtil;
5 | import java.util.List;
6 | import java.util.Objects;
7 | import org.junit.Assert;
8 | import org.junit.Test;
9 |
10 | public class LexerTest {
11 |
12 | @Test
13 | public void test_tokenize() {
14 | // 1. Arrange
15 | String hllCode =
16 | Objects.requireNonNull(FileReaderUtil.getResourceFileAsString("lexer/code.ck"));
17 |
18 | // 2. Act
19 | List resultList = Lexer.tokenize(hllCode);
20 |
21 | // 3. Assert
22 | Assert.assertEquals(19, resultList.size());
23 |
24 | // (Optional) 4. Log
25 | resultList.forEach(token -> System.out.println(token.getType() + " " + token.getValue()));
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/compiler-examples/svg-compiler/src/test/java/com/arjunsk/compiler/svg/core/parsing/ParserTest.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.svg.core.parsing;
2 |
3 | import com.arjunsk.compiler.svg.domain.lexer.ast.AstNode;
4 | import com.arjunsk.compiler.svg.domain.lexer.token.Token;
5 | import com.arjunsk.compiler.utils.FileReaderUtil;
6 | import java.util.ArrayList;
7 | import java.util.List;
8 | import java.util.Objects;
9 | import org.junit.Assert;
10 | import org.junit.Test;
11 |
12 | public class ParserTest {
13 |
14 | @Test
15 | public void test_parse() {
16 |
17 | // 1. Arrange
18 | String hllCode = Objects.requireNonNull(FileReaderUtil.getResourceFileAsString("lexer/code.ck"));
19 | List tokens = Lexer.tokenize(hllCode);
20 |
21 | // 2. Act
22 | AstNode result = new Parser(tokens).parse();
23 |
24 | // 3. Assert
25 | Assert.assertNotNull(result);
26 |
27 | // 4. Log
28 | System.out.println(printAst(result));
29 | }
30 |
31 | private String printAst(AstNode root) {
32 |
33 | if (root == null) return "";
34 |
35 | StringBuilder sb = new StringBuilder();
36 | sb.append(" Type: ")
37 | .append(root.getNodeClass())
38 | .append(" Value: ")
39 | .append(root.getValue())
40 | .append("\n");
41 |
42 | List children = new ArrayList<>();
43 | root.getChildren()
44 | .forEachRemaining(
45 | item -> {
46 | String child = printAst(item);
47 | if (!child.isEmpty()) children.add(child);
48 | });
49 | if (!children.isEmpty()) {
50 | sb.append("[").append("\n");
51 | children.forEach(sb::append);
52 | sb.append("]").append("\n");
53 | }
54 |
55 | return sb.toString();
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/compiler-examples/svg-compiler/src/test/java/com/arjunsk/compiler/svg/core/transforming/TransformerTest.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.svg.core.transforming;
2 |
3 | import com.arjunsk.compiler.svg.core.parsing.Lexer;
4 | import com.arjunsk.compiler.svg.core.parsing.Parser;
5 | import com.arjunsk.compiler.svg.domain.lexer.ast.AstNode;
6 | import com.arjunsk.compiler.svg.domain.lexer.token.Token;
7 | import com.arjunsk.compiler.svg.domain.transformer.ast.SvgAstNode;
8 | import com.arjunsk.compiler.utils.FileReaderUtil;
9 | import java.util.ArrayList;
10 | import java.util.List;
11 | import java.util.Objects;
12 | import org.junit.Assert;
13 | import org.junit.Test;
14 |
15 | public class TransformerTest {
16 |
17 | @Test
18 | public void test_transform() {
19 | // 1. Arrange
20 | String hllCode =
21 | Objects.requireNonNull(FileReaderUtil.getResourceFileAsString("lexer/code.ck"));
22 | List tokens = Lexer.tokenize(hllCode);
23 | AstNode oldAst = new Parser(tokens).parse();
24 |
25 | // 2. Act
26 | SvgAstNode result = new Transformer().transform(oldAst);
27 |
28 | // 3. Assert
29 | Assert.assertNotNull(result);
30 |
31 | // 4. Log
32 | System.out.println(printAst(result));
33 | }
34 |
35 | private String printAst(SvgAstNode root) {
36 |
37 | if (root == null) return "";
38 |
39 | StringBuilder sb = new StringBuilder();
40 | sb.append(root.getTag()).append("\n");
41 |
42 | root.getAttributes()
43 | .forEachRemaining(
44 | item -> sb.append(item.getKey()).append(" --> ").append(item.getValue()).append("\n"));
45 |
46 | sb.append("\n");
47 |
48 | List children = new ArrayList<>();
49 | root.getBody()
50 | .forEachRemaining(
51 | item -> {
52 | String child = printAst(item);
53 | if (!child.isEmpty()) children.add(child);
54 | });
55 | if (!children.isEmpty()) {
56 | sb.append("[").append("\n");
57 | children.forEach(sb::append);
58 | sb.append("]").append("\n");
59 | }
60 |
61 | return sb.toString();
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/compiler-examples/svg-compiler/src/test/java/com/arjunsk/compiler/utils/FileReaderUtil.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.compiler.utils;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.InputStream;
5 | import java.io.InputStreamReader;
6 | import java.util.stream.Collectors;
7 |
8 | /** File Reader for reading files from test resource. */
9 | public class FileReaderUtil {
10 |
11 | /**
12 | * Reads given resource file as a string.
13 | *
14 | * @param fileName path to the resource file
15 | * @return the file's content in String
16 | */
17 | public static String getResourceFileAsString(String fileName) {
18 | ClassLoader classLoader = ClassLoader.getSystemClassLoader();
19 | try (InputStream is = classLoader.getResourceAsStream(fileName)) {
20 | if (is == null) return null;
21 | try (InputStreamReader isr = new InputStreamReader(is);
22 | BufferedReader reader = new BufferedReader(isr)) {
23 | return reader.lines().collect(Collectors.joining(System.lineSeparator()));
24 | }
25 | } catch (Exception ex) {
26 | throw new RuntimeException("Error reading file", ex);
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/compiler-examples/svg-compiler/src/test/resources/lexer/code.ck:
--------------------------------------------------------------------------------
1 | Paper 100
2 | Pen 0
3 | Line 50 77 22 27
4 | Line 22 27 78 27
5 | Line 78 27 50 77
--------------------------------------------------------------------------------
/compiler-examples/svg-compiler/src/test/resources/output/code.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/parser-examples/antlr-examples/antlr-listener-example/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 |
8 | com.arjunsk
9 | antlr-examples
10 | 1.0-SNAPSHOT
11 |
12 |
13 | antlr-listener-example
14 |
15 |
16 |
17 |
18 |
19 | org.apache.maven.plugins
20 | maven-compiler-plugin
21 | ${maven-compiler-plugin.version}
22 |
23 | ${java.version}
24 | ${java.version}
25 |
26 |
27 |
28 |
29 | org.antlr
30 | antlr4-maven-plugin
31 | ${antlr4.version}
32 |
33 |
34 |
35 | antlr4
36 |
37 |
38 | true
39 | false
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/parser-examples/antlr-examples/antlr-listener-example/src/main/antlr4/com/arjunsk/parser/antlr/SimplerLang.g4:
--------------------------------------------------------------------------------
1 | grammar SimplerLang;
2 |
3 | program : statement+;
4 |
5 | statement : let | show ;
6 |
7 | let : VAR '=' INT ;
8 | show : 'show' (INT | VAR) ;
9 |
10 | VAR : ('a'..'z'|'A'..'Z')+ ;
11 | INT : '0'..'9'+ ;
12 | WS : [ \n\t]+ -> skip;
13 |
--------------------------------------------------------------------------------
/parser-examples/antlr-examples/antlr-listener-example/src/main/java/com/arjunsk/parser/antlr/listener/AntlrListenerDriver.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.parser.antlr.listener;
2 |
3 | import com.arjunsk.parser.antlr.SimplerLangLexer;
4 | import com.arjunsk.parser.antlr.SimplerLangParser;
5 | import com.arjunsk.parser.antlr.listener.support.SimplerLangListenerImpl;
6 | import org.antlr.v4.runtime.CharStreams;
7 | import org.antlr.v4.runtime.CommonTokenStream;
8 |
9 | public class AntlrListenerDriver {
10 |
11 | public static void main(String[] args) {
12 | String code =
13 | "a = 100\n"
14 | + "b = 150\n"
15 | + "show 10\n"
16 | + "show a\n"
17 | + "show b\n"
18 | + "show 121\n"
19 | + "show 200";
20 |
21 | compile(code);
22 | }
23 |
24 | private static void compile(String source) {
25 |
26 | SimplerLangLexer lexer = new SimplerLangLexer(CharStreams.fromString(source));
27 | SimplerLangParser parser = new SimplerLangParser(new CommonTokenStream(lexer));
28 |
29 | parser.addParseListener(new SimplerLangListenerImpl());
30 | parser.program();
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/parser-examples/antlr-examples/antlr-listener-example/src/main/java/com/arjunsk/parser/antlr/listener/support/SimplerLangListenerImpl.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.parser.antlr.listener.support;
2 |
3 | import com.arjunsk.parser.antlr.SimplerLangBaseListener;
4 | import com.arjunsk.parser.antlr.SimplerLangParser.LetContext;
5 | import com.arjunsk.parser.antlr.SimplerLangParser.ShowContext;
6 | import java.util.HashMap;
7 | import java.util.Map;
8 |
9 | /** Logic for handling LET and SHOW. */
10 | public class SimplerLangListenerImpl extends SimplerLangBaseListener {
11 |
12 | private final Map variableMap;
13 |
14 | public SimplerLangListenerImpl() {
15 | super();
16 | this.variableMap = new HashMap<>();
17 | }
18 |
19 | @Override
20 | public void exitLet(LetContext ctx) {
21 | this.variableMap.put(ctx.VAR().getText(), Integer.parseInt(ctx.INT().getText()));
22 | super.exitLet(ctx);
23 | }
24 |
25 | @Override
26 | public void exitShow(ShowContext ctx) {
27 | if (ctx.INT() != null) {
28 | System.out.println(ctx.INT().getText());
29 | } else if (ctx.VAR() != null) {
30 | System.out.println(this.variableMap.get(ctx.VAR().getText()));
31 | }
32 | super.exitShow(ctx);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/parser-examples/antlr-examples/antlr-visitor-example1/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 |
8 | com.arjunsk
9 | antlr-examples
10 | 1.0-SNAPSHOT
11 |
12 |
13 | antlr-visitor-example1
14 |
15 |
16 |
17 |
18 |
19 | org.apache.maven.plugins
20 | maven-compiler-plugin
21 | ${maven-compiler-plugin.version}
22 |
23 | ${java.version}
24 | ${java.version}
25 |
26 |
27 |
28 |
29 | org.antlr
30 | antlr4-maven-plugin
31 | ${antlr4.version}
32 |
33 |
34 |
35 | antlr4
36 |
37 |
38 | false
39 | true
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/parser-examples/antlr-examples/antlr-visitor-example1/src/main/antlr4/com/arjunsk/parser/antlr/Calculator.g4:
--------------------------------------------------------------------------------
1 | grammar Calculator;
2 |
3 | operation : left=NUMBER operator='+' right=NUMBER
4 | | left=NUMBER operator='-' right=NUMBER
5 | | left=NUMBER operator='*' right=NUMBER
6 | | left=NUMBER operator='/' right=NUMBER;
7 |
8 | NUMBER
9 | : ('0' .. '9') + ('.' ('0' .. '9') +)? ;
10 |
11 | WS : (' ' | '\t')+ -> channel(HIDDEN);
--------------------------------------------------------------------------------
/parser-examples/antlr-examples/antlr-visitor-example1/src/main/java/com/arjunsk/parser/antlr/visitor/AntlrVisitorDriver1.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.parser.antlr.visitor;
2 |
3 | import com.arjunsk.parser.antlr.CalculatorLexer;
4 | import com.arjunsk.parser.antlr.CalculatorParser;
5 | import com.arjunsk.parser.antlr.visitor.support.CalculatorVisitorImpl;
6 | import org.antlr.v4.runtime.CharStreams;
7 | import org.antlr.v4.runtime.CommonTokenStream;
8 | import org.antlr.v4.runtime.tree.ParseTree;
9 |
10 | public class AntlrVisitorDriver1 {
11 |
12 | public static void main(String[] args) {
13 |
14 | AntlrVisitorDriver1 driver = new AntlrVisitorDriver1();
15 |
16 | System.out.println(driver.compile("2 + 5")); // 7.0
17 | System.out.println(driver.compile("2 * 5")); // 10.0
18 | System.out.println(driver.compile("5 - 3")); // 2.0
19 | System.out.println(driver.compile("5 / 3")); // 1.6666666666666667
20 | }
21 |
22 | private Double compile(String source) {
23 |
24 | CalculatorLexer lexer = new CalculatorLexer(CharStreams.fromString(source));
25 | CalculatorParser parser = new CalculatorParser(new CommonTokenStream(lexer));
26 |
27 | ParseTree tree = parser.operation();
28 |
29 | CalculatorVisitorImpl visitor = new CalculatorVisitorImpl();
30 | return tree.accept(visitor);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/parser-examples/antlr-examples/antlr-visitor-example1/src/main/java/com/arjunsk/parser/antlr/visitor/support/CalculatorVisitorImpl.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.parser.antlr.visitor.support;
2 |
3 | import com.arjunsk.parser.antlr.CalculatorBaseVisitor;
4 | import com.arjunsk.parser.antlr.CalculatorParser;
5 |
6 | /** Logic for handling NUMERIC Operations. */
7 | public class CalculatorVisitorImpl extends CalculatorBaseVisitor {
8 |
9 | @Override
10 | public Double visitOperation(CalculatorParser.OperationContext ctx) {
11 | if (ctx.operator == null) {
12 | throw new UnsupportedOperationException(
13 | "An operator of +, -, /, * is required to perform the operation");
14 | }
15 | String operator = ctx.operator.getText();
16 | double left = Double.parseDouble(ctx.left.getText());
17 | double right = Double.parseDouble(ctx.right.getText());
18 |
19 | switch (operator) {
20 | case "+":
21 | return left + right;
22 | case "-":
23 | return left - right;
24 | case "/":
25 | return left / right;
26 | case "*":
27 | return left * right;
28 | default:
29 | throw new UnsupportedOperationException("Calculator does not support " + operator);
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/parser-examples/antlr-examples/antlr-visitor.example2/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 |
8 | com.arjunsk
9 | antlr-examples
10 | 1.0-SNAPSHOT
11 |
12 |
13 | antlr-visitor.example2
14 |
15 |
16 |
17 |
18 |
19 | org.apache.maven.plugins
20 | maven-compiler-plugin
21 | ${maven-compiler-plugin.version}
22 |
23 | ${java.version}
24 | ${java.version}
25 |
26 |
27 |
28 |
29 | org.antlr
30 | antlr4-maven-plugin
31 | ${antlr4.version}
32 |
33 |
34 |
35 | antlr4
36 |
37 |
38 | false
39 | true
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/parser-examples/antlr-examples/antlr-visitor.example2/src/main/antlr4/com/arjunsk/parser/antlr/SimplerLang.g4:
--------------------------------------------------------------------------------
1 | grammar SimplerLang;
2 |
3 | program : statement+;
4 |
5 | statement : let | show ;
6 |
7 | let : VAR '=' INT ;
8 | show : 'show' (INT | VAR) ;
9 |
10 | VAR : ('a'..'z'|'A'..'Z')+ ;
11 | INT : '0'..'9'+ ;
12 | WS : [ \n\t]+ -> skip;
13 |
--------------------------------------------------------------------------------
/parser-examples/antlr-examples/antlr-visitor.example2/src/main/java/com/arjunsk/parser/antlr/listener/AntlrVisitorDriver2.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.parser.antlr.listener;
2 |
3 | import com.arjunsk.parser.antlr.SimplerLangLexer;
4 | import com.arjunsk.parser.antlr.SimplerLangParser;
5 | import com.arjunsk.parser.antlr.listener.support.SimplerLangVisitorImpl;
6 | import org.antlr.v4.runtime.CharStreams;
7 | import org.antlr.v4.runtime.CommonTokenStream;
8 | import org.antlr.v4.runtime.tree.ParseTree;
9 |
10 | public class AntlrVisitorDriver2 {
11 |
12 | public static void main(String[] args) {
13 | String code =
14 | "a = 100\n"
15 | + "b = 150\n"
16 | + "show 10\n"
17 | + "show a\n"
18 | + "show b\n"
19 | + "show 121\n"
20 | + "show 200";
21 |
22 | compile(code);
23 | }
24 |
25 | private static void compile(String source) {
26 |
27 | SimplerLangLexer lexer = new SimplerLangLexer(CharStreams.fromString(source));
28 | SimplerLangParser parser = new SimplerLangParser(new CommonTokenStream(lexer));
29 |
30 | ParseTree tree = parser.program();
31 | SimplerLangVisitorImpl visitor = new SimplerLangVisitorImpl();
32 | tree.accept(visitor);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/parser-examples/antlr-examples/antlr-visitor.example2/src/main/java/com/arjunsk/parser/antlr/listener/support/SimplerLangVisitorImpl.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.parser.antlr.listener.support;
2 |
3 | import com.arjunsk.parser.antlr.SimplerLangBaseVisitor;
4 | import com.arjunsk.parser.antlr.SimplerLangParser.LetContext;
5 | import com.arjunsk.parser.antlr.SimplerLangParser.ShowContext;
6 | import java.util.HashMap;
7 | import java.util.Map;
8 |
9 | /** Logic for handling LET and SHOW. */
10 | public class SimplerLangVisitorImpl extends SimplerLangBaseVisitor {
11 |
12 | private final Map variableMap;
13 |
14 | public SimplerLangVisitorImpl() {
15 | super();
16 | variableMap = new HashMap<>();
17 | }
18 |
19 | @Override
20 | public Void visitLet(LetContext ctx) {
21 | this.variableMap.put(ctx.VAR().getText(), Integer.parseInt(ctx.INT().getText()));
22 | return super.visitLet(ctx);
23 | }
24 |
25 | @Override
26 | public Void visitShow(ShowContext ctx) {
27 | if (ctx.INT() != null) {
28 | System.out.println(ctx.INT().getText());
29 | } else if (ctx.VAR() != null) {
30 | System.out.println(this.variableMap.get(ctx.VAR().getText()));
31 | }
32 |
33 | return super.visitShow(ctx);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/parser-examples/antlr-examples/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 |
8 | com.arjunsk
9 | parser-examples
10 | 1.0-SNAPSHOT
11 |
12 |
13 | antlr-examples
14 | pom
15 |
16 |
17 | antlr-listener-example
18 | antlr-visitor-example1
19 | antlr-visitor.example2
20 |
21 |
22 |
23 |
24 |
25 | org.antlr
26 | antlr4-runtime
27 | ${antlr4.version}
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/parser-examples/javaparser-example/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 |
8 | com.arjunsk
9 | parser-examples
10 | 1.0-SNAPSHOT
11 |
12 |
13 | javaparser-example
14 |
15 |
16 |
17 |
18 | com.github.javaparser
19 | javaparser-symbol-solver-core
20 | ${javaparser-symbol-solver-core.version}
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/parser-examples/javaparser-example/src/main/java/com/arjunsk/parser/javaparser/JavaparserDriver.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.parser.javaparser;
2 |
3 | import com.github.javaparser.StaticJavaParser;
4 | import com.github.javaparser.ast.CompilationUnit;
5 | import com.github.javaparser.ast.stmt.Statement;
6 | import java.io.BufferedReader;
7 | import java.io.InputStream;
8 | import java.io.InputStreamReader;
9 | import java.util.stream.Collectors;
10 |
11 | public class JavaparserDriver {
12 |
13 | public static void main(String[] args) {
14 | String code = getResourceFileAsString("input/SimpleProgram.java");
15 | assert code != null;
16 |
17 | parse(code);
18 | }
19 |
20 | /**
21 | * Identify all Statements and see if it is an IfStatement. If yes, print the content of Statement
22 | * Object.
23 | */
24 | private static void parse(String code) {
25 | CompilationUnit cu = StaticJavaParser.parse(code);
26 |
27 | cu.findAll(Statement.class)
28 | .forEach(
29 | statement -> {
30 | if (statement.isIfStmt()) {
31 | System.out.println("If statement content\n" + statement);
32 | }
33 | });
34 | }
35 |
36 | /** Read String from File. */
37 | public static String getResourceFileAsString(String fileName) {
38 | ClassLoader classLoader = ClassLoader.getSystemClassLoader();
39 | try (InputStream is = classLoader.getResourceAsStream(fileName)) {
40 | if (is == null) return null;
41 | try (InputStreamReader isr = new InputStreamReader(is);
42 | BufferedReader reader = new BufferedReader(isr)) {
43 | return reader.lines().collect(Collectors.joining(System.lineSeparator()));
44 | }
45 | } catch (Exception ex) {
46 | throw new RuntimeException("Error reading file", ex);
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/parser-examples/javaparser-example/src/main/resources/input/SimpleProgram.java:
--------------------------------------------------------------------------------
1 | public class SimpleProgram {
2 |
3 | public static void main(String[] args) {
4 | int a = 10;
5 | int b = 20;
6 | int c = a + b;
7 | System.out.println(c + "");
8 |
9 | for (int age = 1; age < 20; age++) {
10 | System.out.println("Your age is " + age);
11 |
12 | if (age > 18) {
13 | System.out.println("You can vote in your current age");
14 | }
15 | }
16 |
17 | for (int vote = 0; vote < 5; vote++) {
18 | System.out.println("You voted " + vote + " times.");
19 | }
20 |
21 | if (true) {
22 | System.out.println("True");
23 | } else {
24 | System.out.println("False");
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/parser-examples/jdt-example/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 |
8 | com.arjunsk
9 | parser-examples
10 | 1.0-SNAPSHOT
11 |
12 |
13 | jdt-example
14 |
15 |
16 |
17 |
18 | org.eclipse.jdt
19 | org.eclipse.jdt.core
20 | ${org.eclipse.jdt.core.version}
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/parser-examples/jdt-example/src/main/java/com/arjunsk/parser/jdt/JdtDriver.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.parser.jdt;
2 |
3 | import com.arjunsk.parser.jdt.ast.JdtAstVisitor;
4 | import java.io.BufferedReader;
5 | import java.io.InputStream;
6 | import java.io.InputStreamReader;
7 | import java.util.stream.Collectors;
8 | import org.eclipse.jdt.core.dom.AST;
9 | import org.eclipse.jdt.core.dom.ASTParser;
10 | import org.eclipse.jdt.core.dom.CompilationUnit;
11 |
12 | public class JdtDriver {
13 |
14 | public static void main(String[] args) {
15 | String javaCode = getResourceFileAsString("input/SimpleProgram.java");
16 | assert javaCode != null;
17 |
18 | ASTParser parser = ASTParser.newParser(AST.JLS15);
19 | parser.setSource(javaCode.toCharArray()); // setting source code.
20 | parser.setKind(ASTParser.K_COMPILATION_UNIT);
21 | final CompilationUnit cu = (CompilationUnit) parser.createAST(null); // Root of tree
22 |
23 | cu.accept(new JdtAstVisitor(cu));
24 | }
25 |
26 | /** Read File as String. */
27 | public static String getResourceFileAsString(String fileName) {
28 | ClassLoader classLoader = ClassLoader.getSystemClassLoader();
29 | try (InputStream is = classLoader.getResourceAsStream(fileName)) {
30 | if (is == null) return null;
31 | try (InputStreamReader isr = new InputStreamReader(is);
32 | BufferedReader reader = new BufferedReader(isr)) {
33 | return reader.lines().collect(Collectors.joining(System.lineSeparator()));
34 | }
35 | } catch (Exception ex) {
36 | throw new RuntimeException("Error reading file", ex);
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/parser-examples/jdt-example/src/main/java/com/arjunsk/parser/jdt/ast/JdtAstVisitor.java:
--------------------------------------------------------------------------------
1 | package com.arjunsk.parser.jdt.ast;
2 |
3 | import java.util.HashSet;
4 | import java.util.Set;
5 | import org.eclipse.jdt.core.dom.ASTVisitor;
6 | import org.eclipse.jdt.core.dom.CompilationUnit;
7 | import org.eclipse.jdt.core.dom.ForStatement;
8 | import org.eclipse.jdt.core.dom.IfStatement;
9 | import org.eclipse.jdt.core.dom.SimpleName;
10 | import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
11 |
12 | /** Visitor for all Java Grammar Semantics. */
13 | public class JdtAstVisitor extends ASTVisitor {
14 |
15 | private final Set names;
16 |
17 | private final CompilationUnit cu;
18 |
19 | public JdtAstVisitor(CompilationUnit cu) {
20 | this.cu = cu;
21 | names = new HashSet<>();
22 | }
23 |
24 | public boolean visit(VariableDeclarationFragment node) {
25 | SimpleName name = node.getName();
26 | this.names.add(name.getIdentifier());
27 | System.out.println(
28 | "Declared '" + name + "' at line " + cu.getLineNumber(name.getStartPosition()));
29 | return false;
30 | }
31 |
32 | public boolean visit(SimpleName node) {
33 | if (this.names.contains(node.getIdentifier())) {
34 | System.out.println(
35 | "Used '" + node + "' at line " + cu.getLineNumber(node.getStartPosition()));
36 | }
37 | return false;
38 | }
39 |
40 | public boolean visit(ForStatement node) {
41 | System.out.println("ForStatement -- content:\n" + node.toString());
42 | return false; // if true, will iterate Visitor to it child node as well.
43 | }
44 |
45 | public boolean visit(IfStatement node) {
46 | System.out.println("IFStatement -- content:\n" + node.toString());
47 | return false;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/parser-examples/jdt-example/src/main/resources/input/SimpleProgram.java:
--------------------------------------------------------------------------------
1 | public class SimpleProgram {
2 |
3 | public static void main(String[] args) {
4 | int a = 10;
5 | int b = 20;
6 | int c = a + b;
7 | System.out.println(c + "");
8 |
9 | for (int age = 1; age < 20; age++) {
10 | System.out.println("Your age is " + age);
11 |
12 | if (age > 18) {
13 | System.out.println("You can vote in your current age");
14 | }
15 | }
16 |
17 | for (int vote = 0; vote < 5; vote++) {
18 | System.out.println("You voted " + vote + " times.");
19 | }
20 |
21 | if (true) {
22 | System.out.println("True");
23 | } else {
24 | System.out.println("False");
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/parser-examples/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 |
8 | com.arjunsk
9 | codekrypt-compiler
10 | 1.0-SNAPSHOT
11 |
12 |
13 | parser-examples
14 | pom
15 |
16 |
17 | javaparser-example
18 | jdt-example
19 | antlr-examples
20 |
21 |
22 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | com.arjunsk
8 | codekrypt-compiler
9 | 1.0-SNAPSHOT
10 | pom
11 |
12 |
13 | compiler-examples
14 | parser-examples
15 |
16 |
17 |
18 | 1.8
19 | ${java.version}
20 | ${java.version}
21 | UTF-8
22 | UTF-8
23 |
24 | 4.13.2
25 |
26 | 3.20.0
27 | 3.24.0
28 | 4.9.2
29 | 6.0
30 |
31 | 3.8.1
32 |
33 |
34 |
35 |
36 |
37 | junit
38 | junit
39 | ${junit.version}
40 | test
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------