Skip to content

Commit

Permalink
update modifiers for generated methods and demos
Browse files Browse the repository at this point in the history
  • Loading branch information
paulzfm committed Aug 8, 2017
1 parent 0ab4476 commit 3eea7c2
Show file tree
Hide file tree
Showing 13 changed files with 68 additions and 56 deletions.
21 changes: 9 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ LL(1) Parser Generator that automatically generate a parser class written in Jav
satisfies the context-free grammar (CFG) written as a specification file. The parse engine is
based on LL(1) parsing technique, from top to bottom.

LL1-Parser-Gen will become a part of the decaf project for the undergraduate course Principles of
Compilation, Tsinghua University.
LL1-Parser-Gen will become a part of the decaf project for the undergraduate course _Principles of
Compilation_, Tsinghua University.

### Build

Expand All @@ -32,19 +32,15 @@ and you will find the target jar at `target/scala-2.12/LL1-Parser-Gen-assembly-1

### Usage

After preparing your
[specification file](https://github.com/paulzfm/LL1-Parser-Gen/wiki/1.-Specification-File),
type

```
java -jar pg.jar [-strict] <spec file> <output file>
```

to generate the target parser `<output file>` from your `<spec file>`. Open the option `-strict` to
run in [strict mode](https://github.com/paulzfm/LL1-Parser-Gen/wiki/2.-Strict-Mode).
Generate the target parser `<output file>` from your `<spec file>`. The definition of specification
file is [here](https://github.com/paulzfm/LL1-Parser-Gen/wiki/1.-Specification-File). Open the
option `-strict` to run in [strict mode](https://github.com/paulzfm/LL1-Parser-Gen/wiki/2.-Strict-Mode).

We strongly recommend you to read our [wiki](https://github.com/paulzfm/LL1-Parser-Gen/wiki) before
using the tool.
We strongly recommend you to read our [wiki](https://github.com/paulzfm/LL1-Parser-Gen/wiki) first.

### Demo Projects

Expand All @@ -53,5 +49,6 @@ demo projects [arith](https://github.com/paulzfm/LL1-Parser-Gen/tree/master/demo
implements a simple calculator, and
[decaf](https://github.com/paulzfm/LL1-Parser-Gen/tree/master/demos/decaf), a Java-like language parser.

To build these projects, under the demo project root directory, type `ant` to build (make sure you have
installed the `ant` tool). The target jar file will be generated at `result/` folder.
To build these projects, first run `sbt assembly` to build LL1-Parser-Gen as a jar. Then under each
demo project root directory, type `ant` to build (make sure you have installed the `ant` tool).
The target jar file will be generated at `result/` folder.
2 changes: 1 addition & 1 deletion demos/arith/build.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<property name="bin.dir" value="${result.dir}/bin"/>
<property name="doc.dir" value="${result.dir}/doc"/>
<property name="jflex.jar" value="../tools/JFlex.jar"/>
<property name="pg.jar" value="../tools/pg.jar"/>
<property name="pg.jar" value="../../target/scala-2.12/LL1-Parser-Gen-assembly-1.0.jar"/>

<target name="prepare" description="Preparing...">
<mkdir dir="${bin.dir}"/>
Expand Down
4 changes: 2 additions & 2 deletions demos/arith/src/arith/Lexer.java

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 9 additions & 6 deletions demos/arith/src/arith/Parser.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
/* This is auto-generated Parser source by LL1-Parser-Gen.
* Generated at: Sat Aug 05 22:19:22 CST 2017
* Specification file: /Users/paul/Workspace/LL1-Parser-Gen/demos/arith/src/arith/Parser.spec
* Options: unstrict mode
* Generated at: Tue Aug 08 14:15:03 CST 2017
* Please do NOT modify it!
*
* Project repository: https://github.com/paulzfm/LL1-Parser-Gen
* Version: 1.0
* Author: Zhu Fengmin (Paul)
*/

Expand All @@ -15,16 +18,16 @@

public class Parser extends BaseParser
{
public static final int eof = -1;
public static final int eos = 0;
public int lookahead = -1;
private static final int eof = -1;
private static final int eos = 0;
private int lookahead = -1;
public SemValue val = new SemValue();

/* tokens */
public static final int NUM = 257; //# line 25

/* search token name */
String[] tokens = {
private String[] tokens = {
"NUM",
};

Expand All @@ -47,7 +50,7 @@ public SemValue parse() throws Exception {
return result;
}

public SemValue matchToken(int expected) throws Exception {
private SemValue matchToken(int expected) throws Exception {
SemValue self = val;
if (lookahead == expected) {
lookahead = lex();
Expand Down
2 changes: 1 addition & 1 deletion demos/decaf/build.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<property name="bin.dir" value="${result.dir}/bin"/>
<property name="doc.dir" value="${result.dir}/doc"/>
<property name="jflex.jar" value="../tools/JFlex.jar"/>
<property name="pg.jar" value="../tools/pg.jar"/>
<property name="pg.jar" value="../../target/scala-2.12/LL1-Parser-Gen-assembly-1.0.jar"/>

<target name="prepare" description="Preparing...">
<mkdir dir="${bin.dir}"/>
Expand Down
6 changes: 0 additions & 6 deletions demos/decaf/src/decaf/BaseLexer.java
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,4 @@ protected int identifier(String name) {
return Parser.IDENTIFIER;
}

public void diagnose() throws IOException {
while (yylex() != 0) {
System.out.println(parser.lookahead);
}
}

}
4 changes: 2 additions & 2 deletions demos/decaf/src/decaf/Lexer.java

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 9 additions & 6 deletions demos/decaf/src/decaf/Parser.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
/* This is auto-generated Parser source by LL1-Parser-Gen.
* Generated at: Sat Aug 05 22:31:08 CST 2017
* Specification file: /Users/paul/Workspace/LL1-Parser-Gen/demos/decaf/src/decaf/Parser.spec
* Options: unstrict mode
* Generated at: Tue Aug 08 14:14:52 CST 2017
* Please do NOT modify it!
*
* Project repository: https://github.com/paulzfm/LL1-Parser-Gen
* Version: 1.0
* Author: Zhu Fengmin (Paul)
*/

Expand All @@ -15,9 +18,9 @@

public class Parser extends BaseParser
{
public static final int eof = -1;
public static final int eos = 0;
public int lookahead = -1;
private static final int eof = -1;
private static final int eos = 0;
private int lookahead = -1;
public SemValue val = new SemValue();

/* tokens */
Expand Down Expand Up @@ -51,7 +54,7 @@ public class Parser extends BaseParser
public static final int NOT_EQUAL = 284; //# line 19

/* search token name */
String[] tokens = {
private String[] tokens = {
"VOID", "BOOL", "INT", "STRING", "CLASS",
"NULL", "EXTENDS", "THIS", "WHILE", "FOR",
"IF", "ELSE", "RETURN", "BREAK", "NEW",
Expand Down Expand Up @@ -79,7 +82,7 @@ public SemValue parse() throws Exception {
return result;
}

public SemValue matchToken(int expected) throws Exception {
private SemValue matchToken(int expected) throws Exception {
SemValue self = val;
if (lookahead == expected) {
lookahead = lex();
Expand Down
Binary file removed demos/tools/pg.jar
Binary file not shown.
6 changes: 4 additions & 2 deletions src/main/scala/Generator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ import scala.util.{Failure, Success, Try}
* Parsers will be constructed according to the Predictive Set.
*
* @param spec specification illustrating the CFG.
* @param file specification file name.
* @param strictMode option to decide whether assuming the CFG is strictlly LL(1) grammar,
* default value closed.
*/
class Generator(spec: Spec, strictMode: Boolean = false) {
class Generator(spec: Spec, file: String = "<string>", strictMode: Boolean = false) {
/**
* Map non-terminals to their corresponding rules.
*/
Expand Down Expand Up @@ -261,7 +262,8 @@ class Generator(spec: Spec, strictMode: Boolean = false) {
}
NonTerminalParser(spec.sem, nt, cases)
}
new JavaCodeFile(spec.pkg, spec.imports, spec.cls, spec.sem, spec.start, spec.tokens, parsers)
new JavaCodeFile(spec.pkg, spec.imports, spec.cls, spec.sem, spec.start, spec.tokens, parsers,
file, if (strictMode) "strict mode" else "unstrict mode")
}

/**
Expand Down
5 changes: 2 additions & 3 deletions src/main/scala/IndentWriter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,9 @@ class IndentWriter(val indent: Int = 4, val endOfLine: String = "\n") {
/**
* Output buffer to file.
*
* @param path output file path.
* @param file output file.
*/
def outputToFile(path: String): Unit = {
val file = new File(path)
def outputToFile(file: File): Unit = {
val bw = new BufferedWriter(new FileWriter(file))
bw.write(buffer)
bw.close()
Expand Down
20 changes: 14 additions & 6 deletions src/main/scala/JavaCodeFile.scala
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,16 @@ import Utils._
* @param start starting symbol of CFG, used as the parser entry.
* @param tokens tokens (or terminals), will be obtained from the lexer.
* @param parsers all non-terminal parsers.
* @param specFile input specification file name.
* @param options custom options.
*/
class JavaCodeFile(val pkg: Package, val imports: Imports, val cls: Class,
val semValue: SemValue, val start: NonTerminal,
val tokens: List[Token],
val parsers: List[NonTerminalParser]) extends Printable {
val parsers: List[NonTerminalParser],
val specFile: String, val options: String) extends Printable {
val version: String = "1.0"

override def printTo(writer: IndentWriter): Unit = {
// Print info.
printInfoTo(writer)
Expand All @@ -52,9 +57,9 @@ class JavaCodeFile(val pkg: Package, val imports: Imports, val cls: Class,
writer.incIndent()

// Print yy variables.
writer.writeLn("public static final int eof = -1;")
writer.writeLn("public static final int eos = 0;")
writer.writeLn("public int lookahead = -1;")
writer.writeLn("private static final int eof = -1;")
writer.writeLn("private static final int eos = 0;")
writer.writeLn("private int lookahead = -1;")
writer.writeLn(s"public $semValue val = new $semValue();")
writer.writeLn()

Expand All @@ -67,7 +72,7 @@ class JavaCodeFile(val pkg: Package, val imports: Imports, val cls: Class,
}
writer.writeLn()
writer.writeLn("/* search token name */")
writer.writeLn("String[] tokens = {")
writer.writeLn("private String[] tokens = {")
writer.incIndent()
identTokens.grouped(5).foreach {
grp =>
Expand Down Expand Up @@ -103,10 +108,13 @@ class JavaCodeFile(val pkg: Package, val imports: Imports, val cls: Class,

private def printInfoTo(writer: IndentWriter): Unit = {
writer.writeLn("/* This is auto-generated Parser source by LL1-Parser-Gen.")
writer.writeLn(s" * Specification file: $specFile")
writer.writeLn(s" * Options: $options")
writer.writeLn(s" * Generated at: ${Calendar.getInstance.getTime}")
writer.writeLn(" * Please do NOT modify it!")
writer.writeLn(" *")
writer.writeLn(" * Project repository: https://github.com/paulzfm/LL1-Parser-Gen")
writer.writeLn(s" * Version: $version")
writer.writeLn(" * Author: Zhu Fengmin (Paul)")
writer.writeLn(" */")
}
Expand Down Expand Up @@ -147,7 +155,7 @@ class JavaCodeFile(val pkg: Package, val imports: Imports, val cls: Class,
}

private def printFuncMatchTokenTo(writer: IndentWriter): Unit = {
writer.writeLn(s"public $semValue matchToken(int expected) throws Exception {")
writer.writeLn(s"private $semValue matchToken(int expected) throws Exception {")
writer.incIndent()
writer.writeLn(s"$semValue self = val;")
writer.writeLn("if (lookahead == expected) {")
Expand Down
24 changes: 15 additions & 9 deletions src/main/scala/Main.scala
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import java.io.File

import scala.util.{Failure, Success, Try}

/**
Expand All @@ -6,25 +8,25 @@ import scala.util.{Failure, Success, Try}
object Main {
def main(args: Array[String]): Unit = {
// Parse command line option and arguments.
var specFile = ""
var outputFile = ""
var specFileName = ""
var parserFileName = ""
var strictMode = false

if (args.length == 0) {
Console.err.println(s"Usage: java -jar pg.jar [-strict] <spec file> <output file>")
System.exit(1)
} else if (args(0) == "-strict") {
if (args.length >= 3) {
specFile = args(1)
outputFile = args(2)
specFileName = args(1)
parserFileName = args(2)
strictMode = true
} else {
Console.err.println(s"Usage: java -jar pg.jar [-strict] <spec file> <output file>")
System.exit(1)
}
} else if (args.length == 2) {
specFile = args(0)
outputFile = args(1)
specFileName = args(0)
parserFileName = args(1)
} else if (args.length == 3) {
Console.err.println(s"Invalid option: ${args(0)}")
System.exit(1)
Expand All @@ -34,13 +36,16 @@ object Main {
}

// Read specification file.
val source = scala.io.Source.fromFile(specFile)
val inputFile = new File(specFileName)
val source = scala.io.Source.fromFile(inputFile)
val lines = try source.mkString finally source.close()

val outputFile = new File(parserFileName)

// Parse and generate.
def parseAndGenerate(source: String): Try[Unit] = for {
spec <- Parsers.parse(source)
gen = new Generator(spec, strictMode)
gen = new Generator(spec, inputFile.getAbsolutePath, strictMode)
code <- gen.generate
} yield {
val writer = new IndentWriter
Expand All @@ -50,7 +55,8 @@ object Main {

parseAndGenerate(lines) match {
case Success(_) =>
println(s"""Parser is successfully generated and written to "$outputFile".""")
println("Parser is successfully generated and written to \"" +
outputFile.getAbsolutePath + "\"")
case Failure(ex) =>
Console.err.println(ex.getMessage)
System.exit(1)
Expand Down

0 comments on commit 3eea7c2

Please sign in to comment.