initial commit
This commit is contained in:
commit
85bcb906ed
77 changed files with 7183 additions and 0 deletions
12
.gitignore
vendored
Normal file
12
.gitignore
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
/data
|
||||||
|
/work
|
||||||
|
/logs
|
||||||
|
/.idea
|
||||||
|
/target
|
||||||
|
.DS_Store
|
||||||
|
/.settings
|
||||||
|
/.classpath
|
||||||
|
/.project
|
||||||
|
/.gradle
|
||||||
|
/build
|
||||||
|
*~
|
33
LICENSE-jacc.txt
Normal file
33
LICENSE-jacc.txt
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
Copyright (c) 1999-2004, Mark P Jones, Oregon Health & Science
|
||||||
|
University (OGI School of Science & Engineering at OHSU)
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or
|
||||||
|
without modification, are permitted provided that the following
|
||||||
|
conditions are met:
|
||||||
|
|
||||||
|
o Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
o Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following
|
||||||
|
disclaimer in the documentation and/or other materials provided
|
||||||
|
with the distribution.
|
||||||
|
|
||||||
|
o Neither the name of the Oregon Health & Science University, the
|
||||||
|
OGI School of Science & Engineering at OHSU nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
45
build.gradle
Normal file
45
build.gradle
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
plugins {
|
||||||
|
id "org.sonarqube" version '2.1-rc1'
|
||||||
|
}
|
||||||
|
|
||||||
|
ext {
|
||||||
|
user = 'jprante'
|
||||||
|
name = 'jacc'
|
||||||
|
description = 'Java implementation of Yet Another Compiler-Compiler'
|
||||||
|
scmUrl = 'https://github.com/' + user + '/' + name
|
||||||
|
scmConnection = 'scm:git:git://github.com/' + user + '/' + name + '.git'
|
||||||
|
scmDeveloperConnection = 'scm:git:git://github.com/' + user + '/' + name + '.git'
|
||||||
|
}
|
||||||
|
|
||||||
|
group = 'org.xbib'
|
||||||
|
version = '2.1.0'
|
||||||
|
|
||||||
|
apply plugin: 'java'
|
||||||
|
apply plugin: 'maven'
|
||||||
|
apply plugin: 'signing'
|
||||||
|
apply plugin: 'findbugs'
|
||||||
|
apply plugin: 'pmd'
|
||||||
|
apply plugin: 'checkstyle'
|
||||||
|
apply plugin: 'jacoco'
|
||||||
|
|
||||||
|
sourceCompatibility = 1.8
|
||||||
|
targetCompatibility = 1.8
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
maven {
|
||||||
|
url "http://xbib.org/repository"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
configurations {
|
||||||
|
wagon
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
testCompile 'junit:junit:4.12'
|
||||||
|
wagon 'org.apache.maven.wagon:wagon-ssh-external:2.10'
|
||||||
|
}
|
||||||
|
|
||||||
|
apply from: 'gradle/publish.gradle'
|
||||||
|
apply from: 'gradle/sonarqube.gradle'
|
323
config/checkstyle/checkstyle.xml
Normal file
323
config/checkstyle/checkstyle.xml
Normal file
|
@ -0,0 +1,323 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE module PUBLIC
|
||||||
|
"-//Puppy Crawl//DTD Check Configuration 1.3//EN"
|
||||||
|
"http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
|
||||||
|
|
||||||
|
<!-- This is a checkstyle configuration file. For descriptions of
|
||||||
|
what the following rules do, please see the checkstyle configuration
|
||||||
|
page at http://checkstyle.sourceforge.net/config.html -->
|
||||||
|
|
||||||
|
<module name="Checker">
|
||||||
|
|
||||||
|
<module name="FileTabCharacter">
|
||||||
|
<!-- Checks that there are no tab characters in the file.
|
||||||
|
-->
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="NewlineAtEndOfFile">
|
||||||
|
<property name="lineSeparator" value="lf"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="RegexpSingleline">
|
||||||
|
<!-- Checks that FIXME is not used in comments. TODO is preferred.
|
||||||
|
-->
|
||||||
|
<property name="format" value="((//.*)|(\*.*))FIXME" />
|
||||||
|
<property name="message" value='TODO is preferred to FIXME. e.g. "TODO(johndoe): Refactor when v2 is released."' />
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="RegexpSingleline">
|
||||||
|
<!-- Checks that TODOs are named. (Actually, just that they are followed
|
||||||
|
by an open paren.)
|
||||||
|
-->
|
||||||
|
<property name="format" value="((//.*)|(\*.*))TODO[^(]" />
|
||||||
|
<property name="message" value='All TODOs should be named. e.g. "TODO(johndoe): Refactor when v2 is released."' />
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="JavadocPackage">
|
||||||
|
<!-- Checks that each Java package has a Javadoc file used for commenting.
|
||||||
|
Only allows a package-info.java, not package.html. -->
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<!-- All Java AST specific tests live under TreeWalker module. -->
|
||||||
|
<module name="TreeWalker">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
|
||||||
|
IMPORT CHECKS
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
<module name="RedundantImport">
|
||||||
|
<!-- Checks for redundant import statements. -->
|
||||||
|
<property name="severity" value="error"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="ImportOrder">
|
||||||
|
<!-- Checks for out of order import statements. -->
|
||||||
|
|
||||||
|
<property name="severity" value="warning"/>
|
||||||
|
<property name="groups" value="com,junit,net,org,java,javax"/>
|
||||||
|
<!-- This ensures that static imports go first. -->
|
||||||
|
<property name="option" value="top"/>
|
||||||
|
<property name="tokens" value="STATIC_IMPORT, IMPORT"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
|
||||||
|
JAVADOC CHECKS
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Checks for Javadoc comments. -->
|
||||||
|
<!-- See http://checkstyle.sf.net/config_javadoc.html -->
|
||||||
|
<module name="JavadocMethod">
|
||||||
|
<property name="scope" value="protected"/>
|
||||||
|
<property name="severity" value="warning"/>
|
||||||
|
<property name="allowMissingJavadoc" value="true"/>
|
||||||
|
<property name="allowMissingParamTags" value="true"/>
|
||||||
|
<property name="allowMissingReturnTag" value="true"/>
|
||||||
|
<property name="allowMissingThrowsTags" value="true"/>
|
||||||
|
<property name="allowThrowsTagsForSubclasses" value="true"/>
|
||||||
|
<property name="allowUndeclaredRTE" value="true"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="JavadocType">
|
||||||
|
<property name="scope" value="protected"/>
|
||||||
|
<property name="severity" value="error"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="JavadocStyle">
|
||||||
|
<property name="severity" value="warning"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
|
||||||
|
NAMING CHECKS
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Item 38 - Adhere to generally accepted naming conventions -->
|
||||||
|
|
||||||
|
<module name="PackageName">
|
||||||
|
<!-- Validates identifiers for package names against the
|
||||||
|
supplied expression. -->
|
||||||
|
<!-- Here the default checkstyle rule restricts package name parts to
|
||||||
|
seven characters, this is not in line with common practice at Google.
|
||||||
|
-->
|
||||||
|
<property name="format" value="^[a-z]+(\.[a-z][a-z0-9]{1,})*$"/>
|
||||||
|
<property name="severity" value="warning"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="TypeNameCheck">
|
||||||
|
<!-- Validates static, final fields against the
|
||||||
|
expression "^[A-Z][a-zA-Z0-9]*$". -->
|
||||||
|
<metadata name="altname" value="TypeName"/>
|
||||||
|
<property name="severity" value="warning"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="ConstantNameCheck">
|
||||||
|
<!-- Validates non-private, static, final fields against the supplied
|
||||||
|
public/package final fields "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$". -->
|
||||||
|
<metadata name="altname" value="ConstantName"/>
|
||||||
|
<property name="applyToPublic" value="true"/>
|
||||||
|
<property name="applyToProtected" value="true"/>
|
||||||
|
<property name="applyToPackage" value="true"/>
|
||||||
|
<property name="applyToPrivate" value="false"/>
|
||||||
|
<property name="format" value="^([A-Z][A-Z0-9]*(_[A-Z0-9]+)*|FLAG_.*)$"/>
|
||||||
|
<message key="name.invalidPattern"
|
||||||
|
value="Variable ''{0}'' should be in ALL_CAPS (if it is a constant) or be private (otherwise)."/>
|
||||||
|
<property name="severity" value="warning"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="StaticVariableNameCheck">
|
||||||
|
<!-- Validates static, non-final fields against the supplied
|
||||||
|
expression "^[a-z][a-zA-Z0-9]*_?$". -->
|
||||||
|
<metadata name="altname" value="StaticVariableName"/>
|
||||||
|
<property name="applyToPublic" value="true"/>
|
||||||
|
<property name="applyToProtected" value="true"/>
|
||||||
|
<property name="applyToPackage" value="true"/>
|
||||||
|
<property name="applyToPrivate" value="true"/>
|
||||||
|
<property name="format" value="^[a-z][a-zA-Z0-9]*_?$"/>
|
||||||
|
<property name="severity" value="warning"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="MemberNameCheck">
|
||||||
|
<!-- Validates non-static members against the supplied expression. -->
|
||||||
|
<metadata name="altname" value="MemberName"/>
|
||||||
|
<property name="applyToPublic" value="true"/>
|
||||||
|
<property name="applyToProtected" value="true"/>
|
||||||
|
<property name="applyToPackage" value="true"/>
|
||||||
|
<property name="applyToPrivate" value="true"/>
|
||||||
|
<property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
|
||||||
|
<property name="severity" value="warning"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="MethodNameCheck">
|
||||||
|
<!-- Validates identifiers for method names. -->
|
||||||
|
<metadata name="altname" value="MethodName"/>
|
||||||
|
<property name="format" value="^[a-z][a-zA-Z0-9]*(_[a-zA-Z0-9]+)*$"/>
|
||||||
|
<property name="severity" value="warning"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="ParameterName">
|
||||||
|
<!-- Validates identifiers for method parameters against the
|
||||||
|
expression "^[a-z][a-zA-Z0-9]*$". -->
|
||||||
|
<property name="severity" value="warning"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="LocalFinalVariableName">
|
||||||
|
<!-- Validates identifiers for local final variables against the
|
||||||
|
expression "^[a-z][a-zA-Z0-9]*$". -->
|
||||||
|
<property name="severity" value="warning"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="LocalVariableName">
|
||||||
|
<!-- Validates identifiers for local variables against the
|
||||||
|
expression "^[a-z][a-zA-Z0-9]*$". -->
|
||||||
|
<property name="severity" value="warning"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
|
||||||
|
LENGTH and CODING CHECKS
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
<module name="LineLength">
|
||||||
|
<!-- Checks if a line is too long. -->
|
||||||
|
<property name="max" value="${com.puppycrawl.tools.checkstyle.checks.sizes.LineLength.max}" default="128"/>
|
||||||
|
<property name="severity" value="error"/>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
The default ignore pattern exempts the following elements:
|
||||||
|
- import statements
|
||||||
|
- long URLs inside comments
|
||||||
|
-->
|
||||||
|
|
||||||
|
<property name="ignorePattern"
|
||||||
|
value="${com.puppycrawl.tools.checkstyle.checks.sizes.LineLength.ignorePattern}"
|
||||||
|
default="^(package .*;\s*)|(import .*;\s*)|( *(\*|//).*https?://.*)$"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="LeftCurly">
|
||||||
|
<!-- Checks for placement of the left curly brace ('{'). -->
|
||||||
|
<property name="severity" value="warning"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="RightCurly">
|
||||||
|
<!-- Checks right curlies on CATCH, ELSE, and TRY blocks are on
|
||||||
|
the same line. e.g., the following example is fine:
|
||||||
|
<pre>
|
||||||
|
if {
|
||||||
|
...
|
||||||
|
} else
|
||||||
|
</pre>
|
||||||
|
-->
|
||||||
|
<!-- This next example is not fine:
|
||||||
|
<pre>
|
||||||
|
if {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
else
|
||||||
|
</pre>
|
||||||
|
-->
|
||||||
|
<property name="option" value="same"/>
|
||||||
|
<property name="severity" value="warning"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<!-- Checks for braces around if and else blocks -->
|
||||||
|
<module name="NeedBraces">
|
||||||
|
<property name="severity" value="warning"/>
|
||||||
|
<property name="tokens" value="LITERAL_IF, LITERAL_ELSE, LITERAL_FOR, LITERAL_WHILE, LITERAL_DO"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="UpperEll">
|
||||||
|
<!-- Checks that long constants are defined with an upper ell.-->
|
||||||
|
<property name="severity" value="error"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="FallThrough">
|
||||||
|
<!-- Warn about falling through to the next case statement. Similar to
|
||||||
|
javac -Xlint:fallthrough, but the check is suppressed if a single-line comment
|
||||||
|
on the last non-blank line preceding the fallen-into case contains 'fall through' (or
|
||||||
|
some other variants which we don't publicized to promote consistency).
|
||||||
|
-->
|
||||||
|
<property name="reliefPattern"
|
||||||
|
value="fall through|Fall through|fallthru|Fallthru|falls through|Falls through|fallthrough|Fallthrough|No break|NO break|no break|continue on"/>
|
||||||
|
<property name="severity" value="error"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
|
||||||
|
MODIFIERS CHECKS
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
<module name="ModifierOrder">
|
||||||
|
<!-- Warn if modifier order is inconsistent with JLS3 8.1.1, 8.3.1, and
|
||||||
|
8.4.3. The prescribed order is:
|
||||||
|
public, protected, private, abstract, static, final, transient, volatile,
|
||||||
|
synchronized, native, strictfp
|
||||||
|
-->
|
||||||
|
</module>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
|
||||||
|
WHITESPACE CHECKS
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
<module name="WhitespaceAround">
|
||||||
|
<!-- Checks that various tokens are surrounded by whitespace.
|
||||||
|
This includes most binary operators and keywords followed
|
||||||
|
by regular or curly braces.
|
||||||
|
-->
|
||||||
|
<property name="tokens" value="ASSIGN, BAND, BAND_ASSIGN, BOR,
|
||||||
|
BOR_ASSIGN, BSR, BSR_ASSIGN, BXOR, BXOR_ASSIGN, COLON, DIV, DIV_ASSIGN,
|
||||||
|
EQUAL, GE, GT, LAND, LE, LITERAL_CATCH, LITERAL_DO, LITERAL_ELSE,
|
||||||
|
LITERAL_FINALLY, LITERAL_FOR, LITERAL_IF, LITERAL_RETURN,
|
||||||
|
LITERAL_SYNCHRONIZED, LITERAL_TRY, LITERAL_WHILE, LOR, LT, MINUS,
|
||||||
|
MINUS_ASSIGN, MOD, MOD_ASSIGN, NOT_EQUAL, PLUS, PLUS_ASSIGN, QUESTION,
|
||||||
|
SL, SL_ASSIGN, SR_ASSIGN, STAR, STAR_ASSIGN"/>
|
||||||
|
<property name="severity" value="error"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="WhitespaceAfter">
|
||||||
|
<!-- Checks that commas, semicolons and typecasts are followed by
|
||||||
|
whitespace.
|
||||||
|
-->
|
||||||
|
<property name="tokens" value="COMMA, SEMI, TYPECAST"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="NoWhitespaceAfter">
|
||||||
|
<!-- Checks that there is no whitespace after various unary operators.
|
||||||
|
Linebreaks are allowed.
|
||||||
|
-->
|
||||||
|
<property name="tokens" value="BNOT, DEC, DOT, INC, LNOT, UNARY_MINUS,
|
||||||
|
UNARY_PLUS"/>
|
||||||
|
<property name="allowLineBreaks" value="true"/>
|
||||||
|
<property name="severity" value="error"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="NoWhitespaceBefore">
|
||||||
|
<!-- Checks that there is no whitespace before various unary operators.
|
||||||
|
Linebreaks are allowed.
|
||||||
|
-->
|
||||||
|
<property name="tokens" value="SEMI, DOT, POST_DEC, POST_INC"/>
|
||||||
|
<property name="allowLineBreaks" value="true"/>
|
||||||
|
<property name="severity" value="error"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="ParenPad">
|
||||||
|
<!-- Checks that there is no whitespace before close parens or after
|
||||||
|
open parens.
|
||||||
|
-->
|
||||||
|
<property name="severity" value="warning"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
</module>
|
||||||
|
</module>
|
||||||
|
|
104
gradle/publish.gradle
Normal file
104
gradle/publish.gradle
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
|
||||||
|
task xbibUpload(type: Upload) {
|
||||||
|
configuration = configurations.archives
|
||||||
|
uploadDescriptor = true
|
||||||
|
repositories {
|
||||||
|
if (project.hasProperty("xbibUsername")) {
|
||||||
|
mavenDeployer {
|
||||||
|
configuration = configurations.wagon
|
||||||
|
repository(url: 'scpexe://xbib.org/repository') {
|
||||||
|
authentication(userName: xbibUsername, privateKey: xbibPrivateKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
task sonaTypeUpload(type: Upload) {
|
||||||
|
configuration = configurations.archives
|
||||||
|
uploadDescriptor = true
|
||||||
|
repositories {
|
||||||
|
if (project.hasProperty('ossrhUsername')) {
|
||||||
|
mavenDeployer {
|
||||||
|
beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
|
||||||
|
repository(url: 'https://oss.sonatype.org/service/local/staging/deploy/maven2') {
|
||||||
|
authentication(userName: ossrhUsername, password: ossrhPassword)
|
||||||
|
}
|
||||||
|
snapshotRepository(url: 'https://oss.sonatype.org/content/repositories/snapshots') {
|
||||||
|
authentication(userName: ossrhUsername, password: ossrhPassword)
|
||||||
|
}
|
||||||
|
pom.project {
|
||||||
|
name name
|
||||||
|
description description
|
||||||
|
packaging 'jar'
|
||||||
|
inceptionYear '2012'
|
||||||
|
url scmUrl
|
||||||
|
organization {
|
||||||
|
name 'xbib'
|
||||||
|
url 'http://xbib.org'
|
||||||
|
}
|
||||||
|
developers {
|
||||||
|
developer {
|
||||||
|
id user
|
||||||
|
name 'Jörg Prante'
|
||||||
|
email 'joergprante@gmail.com'
|
||||||
|
url 'https://github.com/jprante'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
scm {
|
||||||
|
url scmUrl
|
||||||
|
connection scmConnection
|
||||||
|
developerConnection scmDeveloperConnection
|
||||||
|
}
|
||||||
|
licenses {
|
||||||
|
license {
|
||||||
|
name 'The Apache License, Version 2.0'
|
||||||
|
url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
task hbzUpload(type: Upload) {
|
||||||
|
configuration = configurations.archives
|
||||||
|
uploadDescriptor = true
|
||||||
|
repositories {
|
||||||
|
if (project.hasProperty('hbzUserName')) {
|
||||||
|
mavenDeployer {
|
||||||
|
configuration = configurations.wagon
|
||||||
|
beforeDeployment { MavenDeployment deployment ->
|
||||||
|
signing.signPom(deployment)
|
||||||
|
}
|
||||||
|
repository(url: uri(hbzUrl)) {
|
||||||
|
authentication(userName: hbzUserName, privateKey: hbzPrivateKey)
|
||||||
|
}
|
||||||
|
pom.project {
|
||||||
|
developers {
|
||||||
|
developer {
|
||||||
|
id 'jprante'
|
||||||
|
name 'Jörg Prante'
|
||||||
|
email 'joergprante@gmail.com'
|
||||||
|
url 'https://github.com/jprante'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
scm {
|
||||||
|
url 'https://github.com/xbib/groovy-webapp'
|
||||||
|
connection 'scm:git:git://github.com/xbib/groovy-webapp.git'
|
||||||
|
developerConnection 'scm:git:git://github.com/xbib/groovy-webapp.git'
|
||||||
|
}
|
||||||
|
inceptionYear '2016'
|
||||||
|
licenses {
|
||||||
|
license {
|
||||||
|
name 'The Apache License, Version 2.0'
|
||||||
|
url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
42
gradle/sonarqube.gradle
Normal file
42
gradle/sonarqube.gradle
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
tasks.withType(Checkstyle) {
|
||||||
|
ignoreFailures = true
|
||||||
|
reports {
|
||||||
|
xml.enabled = true
|
||||||
|
html.enabled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tasks.withType(Pmd) {
|
||||||
|
ignoreFailures = true
|
||||||
|
reports {
|
||||||
|
xml.enabled = true
|
||||||
|
html.enabled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tasks.withType(FindBugs) {
|
||||||
|
ignoreFailures = true
|
||||||
|
reports {
|
||||||
|
xml.enabled = true
|
||||||
|
html.enabled = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
jacocoTestReport {
|
||||||
|
reports {
|
||||||
|
xml.enabled true
|
||||||
|
csv.enabled false
|
||||||
|
xml.destination "${buildDir}/reports/jacoco-xml"
|
||||||
|
html.destination "${buildDir}/reports/jacoco-html"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sonarqube {
|
||||||
|
properties {
|
||||||
|
property "sonar.projectName", "jacc"
|
||||||
|
property "sonar.sourceEncoding", "UTF-8"
|
||||||
|
property "sonar.language", "java"
|
||||||
|
property "sonar.sources", "src/main/java"
|
||||||
|
property "sonar.tests", "src/test/java"
|
||||||
|
property "sonar.scm.provider", "git"
|
||||||
|
property "sonar.java.coveragePlugin", "jacoco"
|
||||||
|
property "sonar.junit.reportsPath", "build/test-results/test/"
|
||||||
|
}
|
||||||
|
}
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
6
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
6
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#Sat Oct 22 21:01:39 CEST 2016
|
||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-3.1-bin.zip
|
169
gradlew
vendored
Executable file
169
gradlew
vendored
Executable file
|
@ -0,0 +1,169 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
##
|
||||||
|
## Gradle start up script for UN*X
|
||||||
|
##
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
# Attempt to set APP_HOME
|
||||||
|
# Resolve links: $0 may be a link
|
||||||
|
PRG="$0"
|
||||||
|
# Need this for relative symlinks.
|
||||||
|
while [ -h "$PRG" ] ; do
|
||||||
|
ls=`ls -ld "$PRG"`
|
||||||
|
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||||
|
if expr "$link" : '/.*' > /dev/null; then
|
||||||
|
PRG="$link"
|
||||||
|
else
|
||||||
|
PRG=`dirname "$PRG"`"/$link"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
SAVED="`pwd`"
|
||||||
|
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||||
|
APP_HOME="`pwd -P`"
|
||||||
|
cd "$SAVED" >/dev/null
|
||||||
|
|
||||||
|
APP_NAME="Gradle"
|
||||||
|
APP_BASE_NAME=`basename "$0"`
|
||||||
|
|
||||||
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
DEFAULT_JVM_OPTS=""
|
||||||
|
|
||||||
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
|
MAX_FD="maximum"
|
||||||
|
|
||||||
|
warn ( ) {
|
||||||
|
echo "$*"
|
||||||
|
}
|
||||||
|
|
||||||
|
die ( ) {
|
||||||
|
echo
|
||||||
|
echo "$*"
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# OS specific support (must be 'true' or 'false').
|
||||||
|
cygwin=false
|
||||||
|
msys=false
|
||||||
|
darwin=false
|
||||||
|
nonstop=false
|
||||||
|
case "`uname`" in
|
||||||
|
CYGWIN* )
|
||||||
|
cygwin=true
|
||||||
|
;;
|
||||||
|
Darwin* )
|
||||||
|
darwin=true
|
||||||
|
;;
|
||||||
|
MINGW* )
|
||||||
|
msys=true
|
||||||
|
;;
|
||||||
|
NONSTOP* )
|
||||||
|
nonstop=true
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
# Determine the Java command to use to start the JVM.
|
||||||
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
|
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||||
|
else
|
||||||
|
JAVACMD="$JAVA_HOME/bin/java"
|
||||||
|
fi
|
||||||
|
if [ ! -x "$JAVACMD" ] ; then
|
||||||
|
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
JAVACMD="java"
|
||||||
|
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Increase the maximum file descriptors if we can.
|
||||||
|
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||||
|
MAX_FD_LIMIT=`ulimit -H -n`
|
||||||
|
if [ $? -eq 0 ] ; then
|
||||||
|
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||||
|
MAX_FD="$MAX_FD_LIMIT"
|
||||||
|
fi
|
||||||
|
ulimit -n $MAX_FD
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Darwin, add options to specify how the application appears in the dock
|
||||||
|
if $darwin; then
|
||||||
|
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Cygwin, switch paths to Windows format before running java
|
||||||
|
if $cygwin ; then
|
||||||
|
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||||
|
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||||
|
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||||
|
|
||||||
|
# We build the pattern for arguments to be converted via cygpath
|
||||||
|
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||||
|
SEP=""
|
||||||
|
for dir in $ROOTDIRSRAW ; do
|
||||||
|
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||||
|
SEP="|"
|
||||||
|
done
|
||||||
|
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||||
|
# Add a user-defined pattern to the cygpath arguments
|
||||||
|
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||||
|
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||||
|
fi
|
||||||
|
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||||
|
i=0
|
||||||
|
for arg in "$@" ; do
|
||||||
|
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||||
|
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||||
|
|
||||||
|
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||||
|
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||||
|
else
|
||||||
|
eval `echo args$i`="\"$arg\""
|
||||||
|
fi
|
||||||
|
i=$((i+1))
|
||||||
|
done
|
||||||
|
case $i in
|
||||||
|
(0) set -- ;;
|
||||||
|
(1) set -- "$args0" ;;
|
||||||
|
(2) set -- "$args0" "$args1" ;;
|
||||||
|
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||||
|
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||||
|
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||||
|
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||||
|
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||||
|
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||||
|
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
|
||||||
|
function splitJvmOpts() {
|
||||||
|
JVM_OPTS=("$@")
|
||||||
|
}
|
||||||
|
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
|
||||||
|
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
|
||||||
|
|
||||||
|
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||||
|
if [[ "$(uname)" == "Darwin" ]] && [[ "$HOME" == "$PWD" ]]; then
|
||||||
|
cd "$(dirname "$0")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
|
84
gradlew.bat
vendored
Normal file
84
gradlew.bat
vendored
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
@if "%DEBUG%" == "" @echo off
|
||||||
|
@rem ##########################################################################
|
||||||
|
@rem
|
||||||
|
@rem Gradle startup script for Windows
|
||||||
|
@rem
|
||||||
|
@rem ##########################################################################
|
||||||
|
|
||||||
|
@rem Set local scope for the variables with windows NT shell
|
||||||
|
if "%OS%"=="Windows_NT" setlocal
|
||||||
|
|
||||||
|
set DIRNAME=%~dp0
|
||||||
|
if "%DIRNAME%" == "" set DIRNAME=.
|
||||||
|
set APP_BASE_NAME=%~n0
|
||||||
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
|
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
set DEFAULT_JVM_OPTS=
|
||||||
|
|
||||||
|
@rem Find java.exe
|
||||||
|
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||||
|
|
||||||
|
set JAVA_EXE=java.exe
|
||||||
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
|
if "%ERRORLEVEL%" == "0" goto init
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
echo.
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
echo location of your Java installation.
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:findJavaFromJavaHome
|
||||||
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
|
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
|
if exist "%JAVA_EXE%" goto init
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||||
|
echo.
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
echo location of your Java installation.
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:init
|
||||||
|
@rem Get command-line arguments, handling Windows variants
|
||||||
|
|
||||||
|
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||||
|
|
||||||
|
:win9xME_args
|
||||||
|
@rem Slurp the command line arguments.
|
||||||
|
set CMD_LINE_ARGS=
|
||||||
|
set _SKIP=2
|
||||||
|
|
||||||
|
:win9xME_args_slurp
|
||||||
|
if "x%~1" == "x" goto execute
|
||||||
|
|
||||||
|
set CMD_LINE_ARGS=%*
|
||||||
|
|
||||||
|
:execute
|
||||||
|
@rem Setup the command line
|
||||||
|
|
||||||
|
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||||
|
|
||||||
|
@rem Execute Gradle
|
||||||
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||||
|
|
||||||
|
:end
|
||||||
|
@rem End local scope for the variables with windows NT shell
|
||||||
|
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||||
|
|
||||||
|
:fail
|
||||||
|
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||||
|
rem the _cmd.exe /c_ return code!
|
||||||
|
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||||
|
exit /b 1
|
||||||
|
|
||||||
|
:mainEnd
|
||||||
|
if "%OS%"=="Windows_NT" endlocal
|
||||||
|
|
||||||
|
:omega
|
1
settings.gradle
Normal file
1
settings.gradle
Normal file
|
@ -0,0 +1 @@
|
||||||
|
rootProject.name = 'jacc'
|
77
src/main/java/org/xbib/jacc/Conflicts.java
Normal file
77
src/main/java/org/xbib/jacc/Conflicts.java
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
package org.xbib.jacc;
|
||||||
|
|
||||||
|
import org.xbib.jacc.grammar.Grammar;
|
||||||
|
import org.xbib.jacc.grammar.Machine;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class Conflicts {
|
||||||
|
|
||||||
|
private int type;
|
||||||
|
private int arg1;
|
||||||
|
private int arg2;
|
||||||
|
private Grammar.Symbol sym;
|
||||||
|
private Conflicts next;
|
||||||
|
|
||||||
|
private Conflicts(int i, int j, int k, Grammar.Symbol symbol, Conflicts conflicts) {
|
||||||
|
type = i;
|
||||||
|
arg1 = j;
|
||||||
|
arg2 = k;
|
||||||
|
sym = symbol;
|
||||||
|
next = conflicts;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Conflicts sr(int i, int j, Grammar.Symbol symbol, Conflicts conflicts) {
|
||||||
|
return append(conflicts, new Conflicts(0, i, j, symbol, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
static Conflicts rr(int i, int j, Grammar.Symbol symbol, Conflicts conflicts) {
|
||||||
|
return append(conflicts, new Conflicts(1, i, j, symbol, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Conflicts append(Conflicts conflicts, Conflicts conflicts1) {
|
||||||
|
if (conflicts == null) {
|
||||||
|
return conflicts1;
|
||||||
|
}
|
||||||
|
Conflicts conflicts2;
|
||||||
|
conflicts2 = conflicts;
|
||||||
|
while (conflicts2.next != null) {
|
||||||
|
conflicts2 = conflicts2.next;
|
||||||
|
}
|
||||||
|
conflicts2.next = conflicts1;
|
||||||
|
return conflicts;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String describe(Machine machine, int i, Conflicts conflicts) {
|
||||||
|
if (conflicts == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
String s = System.getProperty("line.separator", "\n");
|
||||||
|
for (; conflicts != null; conflicts = conflicts.next) {
|
||||||
|
sb.append(i);
|
||||||
|
sb.append(": ");
|
||||||
|
if (conflicts.type == 0) {
|
||||||
|
sb.append("shift/reduce conflict (");
|
||||||
|
if (conflicts.arg1 < 0) {
|
||||||
|
sb.append("$end");
|
||||||
|
} else {
|
||||||
|
sb.append("shift ");
|
||||||
|
sb.append(conflicts.arg1);
|
||||||
|
}
|
||||||
|
sb.append(" and red'n ");
|
||||||
|
sb.append(machine.reduceItem(i, conflicts.arg2).getSeqNo());
|
||||||
|
} else {
|
||||||
|
sb.append("reduce/reduce conflict (red'ns ");
|
||||||
|
sb.append(machine.reduceItem(i, conflicts.arg1).getSeqNo());
|
||||||
|
sb.append(" and ");
|
||||||
|
sb.append(machine.reduceItem(i, conflicts.arg2).getSeqNo());
|
||||||
|
}
|
||||||
|
sb.append(") on ");
|
||||||
|
sb.append(conflicts.sym.getName());
|
||||||
|
sb.append(s);
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
58
src/main/java/org/xbib/jacc/Fixity.java
Normal file
58
src/main/java/org/xbib/jacc/Fixity.java
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
package org.xbib.jacc;
|
||||||
|
|
||||||
|
class Fixity {
|
||||||
|
|
||||||
|
private static final int LEFT = 1;
|
||||||
|
private static final int NONASS = 2;
|
||||||
|
private static final int RIGHT = 3;
|
||||||
|
private int assoc;
|
||||||
|
private int prec;
|
||||||
|
|
||||||
|
private Fixity(int i, int j) {
|
||||||
|
assoc = i;
|
||||||
|
prec = j;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Fixity left(int i) {
|
||||||
|
return new Fixity(LEFT, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Fixity nonass(int i) {
|
||||||
|
return new Fixity(NONASS, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Fixity right(int i) {
|
||||||
|
return new Fixity(RIGHT, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int which(Fixity fixity, Fixity fixity1) {
|
||||||
|
if (fixity != null && fixity1 != null) {
|
||||||
|
if (fixity.prec > fixity1.prec) {
|
||||||
|
return LEFT;
|
||||||
|
}
|
||||||
|
if (fixity.prec < fixity1.prec) {
|
||||||
|
return RIGHT;
|
||||||
|
}
|
||||||
|
if (fixity.assoc == LEFT && fixity1.assoc == LEFT) {
|
||||||
|
return LEFT;
|
||||||
|
}
|
||||||
|
if (fixity.assoc == RIGHT && fixity1.assoc == RIGHT) {
|
||||||
|
return RIGHT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NONASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean equalsFixity(Fixity fixity) {
|
||||||
|
return assoc == fixity.assoc && prec == fixity.prec;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
return obj instanceof Fixity && equalsFixity((Fixity) obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
return assoc ^ prec;
|
||||||
|
}
|
||||||
|
}
|
201
src/main/java/org/xbib/jacc/Jacc.java
Normal file
201
src/main/java/org/xbib/jacc/Jacc.java
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
package org.xbib.jacc;
|
||||||
|
|
||||||
|
import org.xbib.jacc.compiler.ConsoleHandler;
|
||||||
|
|
||||||
|
import java.io.BufferedWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.io.Writer;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class Jacc {
|
||||||
|
|
||||||
|
public Jacc() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
NameList namelist = null;
|
||||||
|
String s = ".jacc";
|
||||||
|
Settings settings = new Settings();
|
||||||
|
boolean flag = true;
|
||||||
|
boolean flag1 = true;
|
||||||
|
boolean flag2 = false;
|
||||||
|
boolean flag4 = false;
|
||||||
|
NameList namelist1 = null;
|
||||||
|
NameList namelist2 = null;
|
||||||
|
boolean flag5 = false;
|
||||||
|
String dir = null;
|
||||||
|
Writer writer = new BufferedWriter(new OutputStreamWriter(System.out, StandardCharsets.UTF_8));
|
||||||
|
label0:
|
||||||
|
for (int i = 0; i < args.length; i++) {
|
||||||
|
String s1 = args[i];
|
||||||
|
if (s1.startsWith("-")) {
|
||||||
|
if (s1.length() == 1) {
|
||||||
|
usage("Missing command line options");
|
||||||
|
}
|
||||||
|
int j = 1;
|
||||||
|
do {
|
||||||
|
if (j >= s1.length()) {
|
||||||
|
continue label0;
|
||||||
|
}
|
||||||
|
switch (s1.charAt(j)) {
|
||||||
|
case 102: // 'f'
|
||||||
|
flag4 = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 112: // 'p'
|
||||||
|
flag = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 116: // 't'
|
||||||
|
flag1 = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 118: // 'v'
|
||||||
|
flag2 = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 48: // '0'
|
||||||
|
settings.setMachineType(0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 115: // 's'
|
||||||
|
settings.setMachineType(1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 97: // 'a'
|
||||||
|
settings.setMachineType(2);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 101: // 'e'
|
||||||
|
if (i + 1 >= args.length) {
|
||||||
|
usage("Missing filename for -e option");
|
||||||
|
}
|
||||||
|
namelist1 = new NameList(args[++i], namelist1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 114: // 'r'
|
||||||
|
if (i + 1 >= args.length) {
|
||||||
|
usage("Missing filename for -r option");
|
||||||
|
}
|
||||||
|
namelist2 = new NameList(args[++i], namelist2);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 110: // 'n'
|
||||||
|
flag5 = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'd':
|
||||||
|
if (i + 1 >= args.length) {
|
||||||
|
usage("Missing directory for -d option");
|
||||||
|
}
|
||||||
|
dir = args[++i];
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
usage("Unrecognized command line option " + s1.charAt(j));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
j++;
|
||||||
|
} while (true);
|
||||||
|
}
|
||||||
|
if (!s1.endsWith(s)) {
|
||||||
|
usage("Input file must have \"" + s + "\" suffix");
|
||||||
|
} else {
|
||||||
|
namelist = new NameList(s1, namelist);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (namelist == null) {
|
||||||
|
usage("No input file(s) specified");
|
||||||
|
}
|
||||||
|
ConsoleHandler simplehandler = new ConsoleHandler();
|
||||||
|
String s2 = namelist.getFirst();
|
||||||
|
int k = 1 + Math.max(s2.lastIndexOf('\\'), s2.lastIndexOf('/'));
|
||||||
|
dir = dir == null ? s2.substring(0, k) : dir;
|
||||||
|
String s4 = s2.substring(k, s2.length() - s.length());
|
||||||
|
final JaccJob job = new JaccJob(simplehandler, writer, settings);
|
||||||
|
NameList.visit(namelist, new NameList.Visitor() {
|
||||||
|
public void visit(String s5) throws IOException {
|
||||||
|
job.parseGrammarFile(s5);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
job.buildTables();
|
||||||
|
settings.fillBlanks(s4);
|
||||||
|
NameList.visit(namelist1, new NameList.Visitor() {
|
||||||
|
public void visit(String s5) throws IOException {
|
||||||
|
job.readErrorExamples(s5);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (simplehandler.getNumFailures() > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (flag) {
|
||||||
|
(new ParserOutput(simplehandler, job)).write(dir + settings.getClassName() + ".java");
|
||||||
|
}
|
||||||
|
if (flag1) {
|
||||||
|
(new TokensOutput(simplehandler, job)).write(dir + settings.getInterfaceName() + ".java");
|
||||||
|
}
|
||||||
|
if (flag2) {
|
||||||
|
(new TextOutput(simplehandler, job, flag4)).write(dir + s4 + ".output");
|
||||||
|
}
|
||||||
|
final boolean showState = flag5;
|
||||||
|
NameList.visit(namelist2, new NameList.Visitor() {
|
||||||
|
public void visit(String s5) throws IOException {
|
||||||
|
job.readRunExample(s5, showState);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void usage(String s) {
|
||||||
|
System.err.println(s);
|
||||||
|
System.err.println("usage: jacc [options] file.jacc ...");
|
||||||
|
System.err.println("options (individually, or in combination):");
|
||||||
|
System.err.println(" -p do not generate parser");
|
||||||
|
System.err.println(" -t do not generate token specification");
|
||||||
|
System.err.println(" -v output text description of machine");
|
||||||
|
System.err.println(" -f show first/follow sets (with -h or -v)");
|
||||||
|
System.err.println(" -a treat as LALR(1) grammar (default)");
|
||||||
|
System.err.println(" -s treat as SLR(1) grammar");
|
||||||
|
System.err.println(" -0 treat as LR(0) grammar");
|
||||||
|
System.err.println(" -r file run parser on input in file");
|
||||||
|
System.err.println(" -n show state numbers in parser output");
|
||||||
|
System.err.println(" -e file read error cases from file");
|
||||||
|
System.err.println(" -d dir output files to directory");
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class NameList {
|
||||||
|
|
||||||
|
String name;
|
||||||
|
NameList names;
|
||||||
|
|
||||||
|
NameList(String s, NameList namelist) {
|
||||||
|
name = s;
|
||||||
|
names = namelist;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void visit(NameList namelist, Visitor visitor) throws IOException {
|
||||||
|
if (namelist != null) {
|
||||||
|
visit(namelist.names, visitor);
|
||||||
|
visitor.visit(namelist.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String getFirst() {
|
||||||
|
NameList namelist;
|
||||||
|
namelist = this;
|
||||||
|
while (namelist.names != null) {
|
||||||
|
namelist = namelist.names;
|
||||||
|
}
|
||||||
|
return namelist.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Visitor {
|
||||||
|
void visit(String s) throws IOException;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
182
src/main/java/org/xbib/jacc/JaccJob.java
Normal file
182
src/main/java/org/xbib/jacc/JaccJob.java
Normal file
|
@ -0,0 +1,182 @@
|
||||||
|
package org.xbib.jacc;
|
||||||
|
|
||||||
|
import org.xbib.jacc.compiler.Failure;
|
||||||
|
import org.xbib.jacc.compiler.Handler;
|
||||||
|
import org.xbib.jacc.compiler.JavaSource;
|
||||||
|
import org.xbib.jacc.compiler.Phase;
|
||||||
|
import org.xbib.jacc.compiler.Position;
|
||||||
|
import org.xbib.jacc.compiler.Warning;
|
||||||
|
import org.xbib.jacc.grammar.Finitary;
|
||||||
|
import org.xbib.jacc.grammar.Grammar;
|
||||||
|
import org.xbib.jacc.grammar.LookaheadMachine;
|
||||||
|
import org.xbib.jacc.grammar.Parser;
|
||||||
|
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.Reader;
|
||||||
|
import java.io.Writer;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
class JaccJob extends Phase {
|
||||||
|
|
||||||
|
private Settings settings;
|
||||||
|
|
||||||
|
private JaccParser parser;
|
||||||
|
|
||||||
|
private JaccTables tables;
|
||||||
|
|
||||||
|
private JaccResolver resolver;
|
||||||
|
|
||||||
|
private Writer out;
|
||||||
|
|
||||||
|
JaccJob(Handler handler, Writer out, Settings settings) {
|
||||||
|
super(handler);
|
||||||
|
this.out = out;
|
||||||
|
this.settings = settings;
|
||||||
|
this.parser = new JaccParser(handler, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
Settings getSettings() {
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
JaccTables getTables() {
|
||||||
|
return tables;
|
||||||
|
}
|
||||||
|
|
||||||
|
JaccResolver getResolver() {
|
||||||
|
return resolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
private JaccLexer lexerFromFile(String s) {
|
||||||
|
JaccLexer jacclexer;
|
||||||
|
try {
|
||||||
|
Reader filereader = new InputStreamReader(new FileInputStream(s), StandardCharsets.UTF_8);
|
||||||
|
jacclexer = new JaccLexer(getHandler(), new JavaSource(getHandler(), s, filereader));
|
||||||
|
jacclexer.nextToken();
|
||||||
|
return jacclexer;
|
||||||
|
} catch (IOException e) {
|
||||||
|
report(new Failure("Could not open file \"" + s + "\""));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void parseGrammarFile(String s) throws IOException {
|
||||||
|
JaccLexer jacclexer = lexerFromFile(s);
|
||||||
|
if (jacclexer != null) {
|
||||||
|
parser.parse(jacclexer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void buildTables() {
|
||||||
|
Grammar grammar = parser.getGrammar();
|
||||||
|
if (grammar == null || !allDeriveFinite(grammar)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LookaheadMachine lookaheadmachine = settings.makeMachine(grammar);
|
||||||
|
resolver = new JaccResolver(lookaheadmachine);
|
||||||
|
tables = new JaccTables(lookaheadmachine, resolver);
|
||||||
|
if (tables.getProdUnused() > 0) {
|
||||||
|
report(new Warning(tables.getProdUnused() + " rules never reduced"));
|
||||||
|
}
|
||||||
|
if (resolver.getNumSRConflicts() > 0 || resolver.getNumRRConflicts() > 0) {
|
||||||
|
report(new Warning("conflicts: " +
|
||||||
|
resolver.getNumSRConflicts() +
|
||||||
|
" shift/reduce, " +
|
||||||
|
resolver.getNumRRConflicts() +
|
||||||
|
" reduce/reduce"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean allDeriveFinite(Grammar grammar) {
|
||||||
|
Finitary finitary = grammar.getFinitary();
|
||||||
|
boolean flag = true;
|
||||||
|
for (int i = 0; i < grammar.getNumNTs(); i++) {
|
||||||
|
if (!finitary.at(i)) {
|
||||||
|
flag = false;
|
||||||
|
report(new Failure("No finite strings can be derived for " +
|
||||||
|
grammar.getNonterminal(i)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
void readRunExample(String s, boolean flag) throws IOException {
|
||||||
|
out.write("Running example from \"" + s + "\"]\n");
|
||||||
|
JaccLexer jacclexer = lexerFromFile(s);
|
||||||
|
if (jacclexer != null) {
|
||||||
|
runExample(parser.parseSymbols(jacclexer), flag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void runExample(int ai[], boolean flag) throws IOException {
|
||||||
|
Grammar grammar = parser.getGrammar();
|
||||||
|
Parser parser1 = new Parser(tables, ai);
|
||||||
|
out.write("start ");
|
||||||
|
do {
|
||||||
|
out.write(" : ");
|
||||||
|
parser1.display(out, flag);
|
||||||
|
switch (parser1.step()) {
|
||||||
|
case 0:
|
||||||
|
out.write("Accept!\n");
|
||||||
|
return;
|
||||||
|
case 1:
|
||||||
|
out.write("error in state ");
|
||||||
|
out.write(parser1.getState());
|
||||||
|
out.write(", next symbol ");
|
||||||
|
out.write(grammar.getSymbol(parser1.getNextSymbol()).toString());
|
||||||
|
return;
|
||||||
|
case 3:
|
||||||
|
out.write("goto ");
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
out.write("shift ");
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
out.write("reduce");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void readErrorExamples(String s) throws IOException {
|
||||||
|
out.write("Reading error examples from \"" + s + "\"");
|
||||||
|
JaccLexer jacclexer = lexerFromFile(s);
|
||||||
|
if (jacclexer != null) {
|
||||||
|
parser.parseErrorExamples(jacclexer, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void errorExample(Position position, String s, int ai[]) {
|
||||||
|
Parser parser1 = new Parser(tables, ai);
|
||||||
|
int i;
|
||||||
|
do {
|
||||||
|
i = parser1.step();
|
||||||
|
} while (i != 0 && i != 1);
|
||||||
|
if (i == 0) {
|
||||||
|
report(new Warning(position, "Example for \"" + s + "\" does not produce an error"));
|
||||||
|
} else {
|
||||||
|
Grammar grammar = tables.getMachine().getGrammar();
|
||||||
|
int j = parser1.getNextSymbol();
|
||||||
|
if (grammar.isNonterminal(j)) {
|
||||||
|
report(new Warning(position,
|
||||||
|
"Example for \"" + s + "\" reaches an error at the nonterminal " + grammar.getSymbol(j)));
|
||||||
|
} else {
|
||||||
|
int k = parser1.getState();
|
||||||
|
if (!tables.errorAt(k, j)) {
|
||||||
|
report(new Failure(position, "Error example results in internal error"));
|
||||||
|
} else {
|
||||||
|
String s1 = tables.errorSet(k, j, s);
|
||||||
|
if (s1 != null) {
|
||||||
|
report(new Warning(position,
|
||||||
|
"Multiple errors are possible in state " + k + " on terminal " +
|
||||||
|
grammar.getSymbol(j) + ":\n - " + s1 + "\n - " + s));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
419
src/main/java/org/xbib/jacc/JaccLexer.java
Normal file
419
src/main/java/org/xbib/jacc/JaccLexer.java
Normal file
|
@ -0,0 +1,419 @@
|
||||||
|
package org.xbib.jacc;
|
||||||
|
|
||||||
|
import org.xbib.jacc.compiler.Failure;
|
||||||
|
import org.xbib.jacc.compiler.Handler;
|
||||||
|
import org.xbib.jacc.compiler.Source;
|
||||||
|
import org.xbib.jacc.compiler.SourceLexer;
|
||||||
|
import org.xbib.jacc.compiler.Warning;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class JaccLexer extends SourceLexer implements JaccTokens {
|
||||||
|
|
||||||
|
private int lastLiteral;
|
||||||
|
|
||||||
|
JaccLexer(Handler handler, Source source) throws IOException {
|
||||||
|
super(handler, source);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int nextToken() throws IOException {
|
||||||
|
do {
|
||||||
|
skipWhitespace();
|
||||||
|
markPosition();
|
||||||
|
lexemeText = null;
|
||||||
|
switch (c) {
|
||||||
|
case -1:
|
||||||
|
return token = ENDINPUT;
|
||||||
|
|
||||||
|
case 58: // ':'
|
||||||
|
nextChar();
|
||||||
|
return token = COLON;
|
||||||
|
|
||||||
|
case 59: // ';'
|
||||||
|
nextChar();
|
||||||
|
return token = SEMI;
|
||||||
|
|
||||||
|
case 124: // '|'
|
||||||
|
nextChar();
|
||||||
|
return token = BAR;
|
||||||
|
|
||||||
|
case 60: // '<'
|
||||||
|
nextChar();
|
||||||
|
return token = TOPEN;
|
||||||
|
|
||||||
|
case 62: // '>'
|
||||||
|
nextChar();
|
||||||
|
return token = TCLOSE;
|
||||||
|
|
||||||
|
case 91: // '['
|
||||||
|
nextChar();
|
||||||
|
return token = BOPEN;
|
||||||
|
|
||||||
|
case 93: // ']'
|
||||||
|
nextChar();
|
||||||
|
return token = BCLOSE;
|
||||||
|
|
||||||
|
case 46: // '.'
|
||||||
|
nextChar();
|
||||||
|
return token = DOT;
|
||||||
|
|
||||||
|
case 37: // '%'
|
||||||
|
if (directive() != -1) {
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 34: // '"'
|
||||||
|
if (string() != -1) {
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 39: // '\''
|
||||||
|
if (literal() != -1) {
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 123: // '{'
|
||||||
|
if (action() != -1) {
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 47: // '/'
|
||||||
|
skipComment();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (Character.isJavaIdentifierStart((char) c)) {
|
||||||
|
return identifier();
|
||||||
|
}
|
||||||
|
if (Character.isDigit((char) c)) {
|
||||||
|
return number();
|
||||||
|
}
|
||||||
|
illegalCharacter();
|
||||||
|
nextChar();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
String readWholeLine() throws IOException {
|
||||||
|
if (line == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String s = line;
|
||||||
|
if (col > 0) {
|
||||||
|
s = s.substring(col);
|
||||||
|
}
|
||||||
|
nextLine();
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
String readCodeLine() throws IOException {
|
||||||
|
while (isWhitespace(c)) {
|
||||||
|
nextChar();
|
||||||
|
}
|
||||||
|
return readWholeLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isWhitespace(int i) {
|
||||||
|
return i == 32 || i == 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void skipWhitespace() throws IOException {
|
||||||
|
while (isWhitespace(c)) {
|
||||||
|
nextChar();
|
||||||
|
}
|
||||||
|
while (c == 10) {
|
||||||
|
nextLine();
|
||||||
|
while (isWhitespace(c)) {
|
||||||
|
nextChar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void skipComment() throws IOException {
|
||||||
|
nextChar();
|
||||||
|
if (c == 47) {
|
||||||
|
nextLine();
|
||||||
|
} else {
|
||||||
|
if (c == 42) {
|
||||||
|
nextChar();
|
||||||
|
do {
|
||||||
|
if (c == 42) {
|
||||||
|
do {
|
||||||
|
nextChar();
|
||||||
|
} while (c == 42);
|
||||||
|
if (c == 47) {
|
||||||
|
nextChar();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (c == -1) {
|
||||||
|
report(new Failure(getPos(), "Unterminated comment"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (c == 10) {
|
||||||
|
nextLine();
|
||||||
|
} else {
|
||||||
|
nextChar();
|
||||||
|
}
|
||||||
|
} while (true);
|
||||||
|
}
|
||||||
|
report(new Failure(getPos(), "Illegal comment format"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int identifier() {
|
||||||
|
int i = col;
|
||||||
|
do {
|
||||||
|
nextChar();
|
||||||
|
} while (c != -1 && Character.isJavaIdentifierPart((char) c));
|
||||||
|
lexemeText = line.substring(i, col);
|
||||||
|
return token = IDENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int directive() throws IOException {
|
||||||
|
nextChar();
|
||||||
|
if (c == 37) {
|
||||||
|
nextChar();
|
||||||
|
return token = MARK;
|
||||||
|
}
|
||||||
|
if (Character.isJavaIdentifierStart((char) c)) {
|
||||||
|
identifier();
|
||||||
|
if (lexemeText.equals("token")) {
|
||||||
|
return token = TOKEN;
|
||||||
|
}
|
||||||
|
if (lexemeText.equals("type")) {
|
||||||
|
return token = TYPE;
|
||||||
|
}
|
||||||
|
if (lexemeText.equals("prec")) {
|
||||||
|
return token = PREC;
|
||||||
|
}
|
||||||
|
if (lexemeText.equals("left")) {
|
||||||
|
return token = LEFT;
|
||||||
|
}
|
||||||
|
if (lexemeText.equals("right")) {
|
||||||
|
return token = RIGHT;
|
||||||
|
}
|
||||||
|
if (lexemeText.equals("nonassoc")) {
|
||||||
|
return token = NONASSOC;
|
||||||
|
}
|
||||||
|
if (lexemeText.equals("start")) {
|
||||||
|
return token = START;
|
||||||
|
}
|
||||||
|
if (lexemeText.equals("package")) {
|
||||||
|
return token = PACKAGE;
|
||||||
|
}
|
||||||
|
if (lexemeText.equals("extends")) {
|
||||||
|
return token = EXTENDS;
|
||||||
|
}
|
||||||
|
if (lexemeText.equals("implements")) {
|
||||||
|
return token = IMPLEMENTS;
|
||||||
|
}
|
||||||
|
if (lexemeText.equals("semantic")) {
|
||||||
|
return token = SEMANTIC;
|
||||||
|
}
|
||||||
|
if (lexemeText.equals("get")) {
|
||||||
|
return token = GETTOKEN;
|
||||||
|
}
|
||||||
|
if (lexemeText.equals("next")) {
|
||||||
|
return token = NEXTTOKEN;
|
||||||
|
}
|
||||||
|
if (lexemeText.equals("class")) {
|
||||||
|
return token = CLASS;
|
||||||
|
}
|
||||||
|
if (lexemeText.equals("interface")) {
|
||||||
|
return token = INTERFACE;
|
||||||
|
} else {
|
||||||
|
report(new Failure(getPos(), "Unrecognized directive"));
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (c == 123) {
|
||||||
|
nextChar();
|
||||||
|
return code();
|
||||||
|
} else {
|
||||||
|
report(new Failure(getPos(), "Illegal directive syntax"));
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int code() throws IOException {
|
||||||
|
int i = col;
|
||||||
|
StringBuilder sb = null;
|
||||||
|
do {
|
||||||
|
if (c == 37) {
|
||||||
|
do {
|
||||||
|
nextChar();
|
||||||
|
} while (c == 37);
|
||||||
|
if (c == 125) {
|
||||||
|
lexemeText = endBuffer(sb, i, col - 1);
|
||||||
|
nextChar();
|
||||||
|
return token = CODE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (c == -1) {
|
||||||
|
report(new Failure(getPos(), "Code fragment terminator %} not found"));
|
||||||
|
lexemeText = endBuffer(sb, i, col);
|
||||||
|
return token = CODE;
|
||||||
|
}
|
||||||
|
if (c == 10) {
|
||||||
|
if (sb == null) {
|
||||||
|
sb = new StringBuilder(line.substring(i, col));
|
||||||
|
} else {
|
||||||
|
sb.append('\n');
|
||||||
|
sb.append(line);
|
||||||
|
}
|
||||||
|
nextLine();
|
||||||
|
} else {
|
||||||
|
nextChar();
|
||||||
|
}
|
||||||
|
} while (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String endBuffer(StringBuilder sb, int i, int j) {
|
||||||
|
if (sb == null) {
|
||||||
|
return line.substring(i, j);
|
||||||
|
}
|
||||||
|
sb.append('\n');
|
||||||
|
if (line != null) {
|
||||||
|
sb.append(line.substring(0, j));
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
int getLastLiteral() {
|
||||||
|
return lastLiteral;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int number() {
|
||||||
|
int i = col;
|
||||||
|
int j = 0;
|
||||||
|
int k = Character.digit((char) c, 10);
|
||||||
|
do {
|
||||||
|
j = 10 * j + k;
|
||||||
|
nextChar();
|
||||||
|
k = Character.digit((char) c, 10);
|
||||||
|
} while (k >= 0);
|
||||||
|
lexemeText = line.substring(i, col);
|
||||||
|
lastLiteral = j;
|
||||||
|
return token = INTLIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int string() {
|
||||||
|
nextChar();
|
||||||
|
int i = col;
|
||||||
|
while (c != 34 && c != 10 && c != -1) {
|
||||||
|
if (c == 92) {
|
||||||
|
escapeChar();
|
||||||
|
} else {
|
||||||
|
nextChar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lexemeText = line.substring(i, col);
|
||||||
|
if (c == 34) {
|
||||||
|
nextChar();
|
||||||
|
} else {
|
||||||
|
report(new Warning(getPos(), "Missing \" on string literal"));
|
||||||
|
}
|
||||||
|
return token = STRLIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int literal() {
|
||||||
|
int i = col;
|
||||||
|
nextChar();
|
||||||
|
if (c == 92) {
|
||||||
|
escapeChar();
|
||||||
|
} else {
|
||||||
|
if (c != 39 && c != 10 && c != -1) {
|
||||||
|
lastLiteral = c;
|
||||||
|
nextChar();
|
||||||
|
} else {
|
||||||
|
report(new Failure(getPos(), "Illegal character literal syntax"));
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (c == 39) {
|
||||||
|
nextChar();
|
||||||
|
} else {
|
||||||
|
report(new Warning(getPos(), "Missing ' on character literal"));
|
||||||
|
}
|
||||||
|
lexemeText = line.substring(i, col);
|
||||||
|
return token = CHARLIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void escapeChar() {
|
||||||
|
nextChar();
|
||||||
|
switch (c) {
|
||||||
|
case 34: // '"'
|
||||||
|
case 39: // '\''
|
||||||
|
case 92: // '\\'
|
||||||
|
case 98: // 'b'
|
||||||
|
case 102: // 'f'
|
||||||
|
case 110: // 'n'
|
||||||
|
case 114: // 'r'
|
||||||
|
case 116: // 't'
|
||||||
|
lastLiteral = c;
|
||||||
|
nextChar();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int i = Character.digit((char) c, 8);
|
||||||
|
if (i >= 0) {
|
||||||
|
lastLiteral = 0;
|
||||||
|
int j = i >= 4 ? 2 : 3;
|
||||||
|
do {
|
||||||
|
lastLiteral = (lastLiteral << 3) + i;
|
||||||
|
nextChar();
|
||||||
|
i = Character.digit((char) c, 8);
|
||||||
|
} while (i >= 0 && --j > 0);
|
||||||
|
} else {
|
||||||
|
report(new Failure(getPos(), "Syntax error in escape sequence"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int action() throws IOException {
|
||||||
|
int i = col;
|
||||||
|
int j = 0;
|
||||||
|
StringBuilder sb = null;
|
||||||
|
do {
|
||||||
|
if (c == 125) {
|
||||||
|
if (--j == 0) {
|
||||||
|
nextChar();
|
||||||
|
lexemeText = endBuffer(sb, i, col);
|
||||||
|
return token = ACTION;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (c == 123) {
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (c == -1) {
|
||||||
|
report(new Failure(getPos(), "Unterminated action"));
|
||||||
|
lexemeText = endBuffer(sb, i, col);
|
||||||
|
return token = ACTION;
|
||||||
|
}
|
||||||
|
if (c == 10) {
|
||||||
|
if (sb == null) {
|
||||||
|
sb = new StringBuilder(line.substring(i, col));
|
||||||
|
} else {
|
||||||
|
sb.append('\n');
|
||||||
|
sb.append(line);
|
||||||
|
}
|
||||||
|
nextLine();
|
||||||
|
} else {
|
||||||
|
nextChar();
|
||||||
|
}
|
||||||
|
} while (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void illegalCharacter() {
|
||||||
|
report(new Warning(getPos(), "Ignoring illegal character"));
|
||||||
|
}
|
||||||
|
}
|
629
src/main/java/org/xbib/jacc/JaccParser.java
Normal file
629
src/main/java/org/xbib/jacc/JaccParser.java
Normal file
|
@ -0,0 +1,629 @@
|
||||||
|
package org.xbib.jacc;
|
||||||
|
|
||||||
|
import org.xbib.jacc.compiler.Failure;
|
||||||
|
import org.xbib.jacc.compiler.Handler;
|
||||||
|
import org.xbib.jacc.compiler.Phase;
|
||||||
|
import org.xbib.jacc.compiler.Position;
|
||||||
|
import org.xbib.jacc.compiler.Warning;
|
||||||
|
import org.xbib.jacc.grammar.Grammar;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class JaccParser extends Phase implements JaccTokens {
|
||||||
|
|
||||||
|
private Settings settings;
|
||||||
|
private int seqNo;
|
||||||
|
private JaccLexer lexer;
|
||||||
|
private int precedence;
|
||||||
|
private NamedJaccSymbols terminals;
|
||||||
|
private NamedJaccSymbols nonterms;
|
||||||
|
private NumJaccSymbols literals;
|
||||||
|
private JaccSymbol start;
|
||||||
|
JaccParser(Handler handler, Settings settings1) {
|
||||||
|
super(handler);
|
||||||
|
seqNo = 1;
|
||||||
|
precedence = 0;
|
||||||
|
settings = settings1;
|
||||||
|
terminals = new NamedJaccSymbols();
|
||||||
|
nonterms = new NamedJaccSymbols();
|
||||||
|
literals = new NumJaccSymbols();
|
||||||
|
start = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Grammar getGrammar() {
|
||||||
|
try {
|
||||||
|
JaccSymbol ajaccsymbol[];
|
||||||
|
JaccProd ajaccprod[][];
|
||||||
|
int i = nonterms.getSize();
|
||||||
|
int j = terminals.getSize() + literals.getSize() + 1;
|
||||||
|
if (i == 0 || start == null) {
|
||||||
|
report(new Failure("No nonterminals defined"));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ajaccsymbol = new JaccSymbol[i + j];
|
||||||
|
literals.fill(ajaccsymbol, terminals.fill(ajaccsymbol, nonterms.fill(ajaccsymbol, 0)));
|
||||||
|
ajaccsymbol[(i + j) - 1] = new JaccSymbol("$end");
|
||||||
|
ajaccsymbol[(i + j) - 1].setNum(0);
|
||||||
|
int k = 1;
|
||||||
|
for (int l = 0; l < j - 1; l++) {
|
||||||
|
if (ajaccsymbol[i + l].getNum() >= 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
while (literals.find(k) != null) {
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
ajaccsymbol[i + l].setNum(k++);
|
||||||
|
}
|
||||||
|
int i1 = 0;
|
||||||
|
do {
|
||||||
|
if (i1 >= i) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ajaccsymbol[i1] == start) {
|
||||||
|
if (i1 > 0) {
|
||||||
|
JaccSymbol jaccsymbol = ajaccsymbol[0];
|
||||||
|
ajaccsymbol[0] = ajaccsymbol[i1];
|
||||||
|
ajaccsymbol[i1] = jaccsymbol;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i1++;
|
||||||
|
} while (true);
|
||||||
|
for (int j1 = 0; j1 < ajaccsymbol.length; j1++) {
|
||||||
|
ajaccsymbol[j1].setTokenNo(j1);
|
||||||
|
}
|
||||||
|
ajaccprod = new JaccProd[nonterms.getSize()][];
|
||||||
|
for (int k1 = 0; k1 < ajaccprod.length; k1++) {
|
||||||
|
ajaccprod[k1] = ajaccsymbol[k1].getProds();
|
||||||
|
if (ajaccprod[k1] == null || ajaccprod[k1].length == 0) {
|
||||||
|
report(new Failure("No productions for " + ajaccsymbol[k1].getName()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new Grammar(ajaccsymbol, ajaccprod);
|
||||||
|
} catch (Exception e) {
|
||||||
|
report(new Failure("Internal problem " + e.getMessage()));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void parse(JaccLexer jacclexer) throws IOException {
|
||||||
|
lexer = jacclexer;
|
||||||
|
terminals.findOrAdd("error");
|
||||||
|
parseDefinitions();
|
||||||
|
if (jacclexer.getToken() != 1) {
|
||||||
|
report(new Failure(jacclexer.getPos(), "Missing grammar"));
|
||||||
|
} else {
|
||||||
|
jacclexer.nextToken();
|
||||||
|
parseGrammar();
|
||||||
|
String s;
|
||||||
|
if (jacclexer.getToken() == 1) {
|
||||||
|
while ((s = jacclexer.readWholeLine()) != null) {
|
||||||
|
settings.addPostText(s);
|
||||||
|
settings.addPostText("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
jacclexer.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
int[] parseSymbols(JaccLexer jacclexer) throws IOException {
|
||||||
|
lexer = jacclexer;
|
||||||
|
SymList symlist = null;
|
||||||
|
do {
|
||||||
|
JaccSymbol jaccsymbol = parseDefinedSymbol();
|
||||||
|
if (jaccsymbol == null) {
|
||||||
|
if (jacclexer.getToken() != 0) {
|
||||||
|
report(new Warning(jacclexer.getPos(), "Ignoring extra tokens at end of input"));
|
||||||
|
}
|
||||||
|
jacclexer.close();
|
||||||
|
return SymList.toIntArray(symlist);
|
||||||
|
}
|
||||||
|
symlist = new SymList(jaccsymbol, symlist);
|
||||||
|
jacclexer.nextToken();
|
||||||
|
} while (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void parseErrorExamples(JaccLexer jacclexer, JaccJob jaccjob) throws IOException {
|
||||||
|
lexer = jacclexer;
|
||||||
|
do {
|
||||||
|
if (jacclexer.getToken() != 5) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
String s = jacclexer.getLexeme();
|
||||||
|
if (jacclexer.nextToken() == 58) {
|
||||||
|
jacclexer.nextToken();
|
||||||
|
} else {
|
||||||
|
report(new Warning(jacclexer.getPos(), "A colon was expected here"));
|
||||||
|
}
|
||||||
|
int i;
|
||||||
|
do {
|
||||||
|
Position position = jacclexer.getPos();
|
||||||
|
SymList symlist = null;
|
||||||
|
JaccSymbol jaccsymbol;
|
||||||
|
while ((jaccsymbol = parseDefinedSymbol()) != null) {
|
||||||
|
symlist = new SymList(jaccsymbol, symlist);
|
||||||
|
jacclexer.nextToken();
|
||||||
|
}
|
||||||
|
int ai[] = SymList.toIntArray(symlist);
|
||||||
|
jaccjob.errorExample(position, s, ai);
|
||||||
|
i = jacclexer.getToken();
|
||||||
|
if (i != 124) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
jacclexer.nextToken();
|
||||||
|
} while (true);
|
||||||
|
if (i != 0) {
|
||||||
|
if (i != 59) {
|
||||||
|
report(new Failure(jacclexer.getPos(), "Unexpected token; a semicolon was expected here"));
|
||||||
|
do {
|
||||||
|
i = jacclexer.nextToken();
|
||||||
|
} while (i != 59 && i != 0);
|
||||||
|
}
|
||||||
|
if (i == 59) {
|
||||||
|
jacclexer.nextToken();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (true);
|
||||||
|
if (jacclexer.getToken() != 0) {
|
||||||
|
report(new Failure(jacclexer.getPos(), "Unexpected token; ignoring the rest of this file"));
|
||||||
|
}
|
||||||
|
jacclexer.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseDefinitions() throws IOException {
|
||||||
|
boolean flag = false;
|
||||||
|
do {
|
||||||
|
switch (lexer.getToken()) {
|
||||||
|
case 0: // '\0'
|
||||||
|
case 1: // '\001'
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (parseDefinition()) {
|
||||||
|
flag = false;
|
||||||
|
} else {
|
||||||
|
if (!flag) {
|
||||||
|
flag = true;
|
||||||
|
report(new Failure(lexer.getPos(), "Syntax error in definition"));
|
||||||
|
}
|
||||||
|
lexer.nextToken();
|
||||||
|
}
|
||||||
|
} while (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean parseDefinition() throws IOException {
|
||||||
|
switch (lexer.getToken()) {
|
||||||
|
case 2: // '\002'
|
||||||
|
settings.addPreText(lexer.getLexeme());
|
||||||
|
lexer.nextToken();
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 8: // '\b'
|
||||||
|
parseTokenDefn();
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 9: // '\t'
|
||||||
|
parseTypeDefn();
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 11: // '\013'
|
||||||
|
parseFixityDefn(Fixity.left(precedence++));
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 13: // '\r'
|
||||||
|
parseFixityDefn(Fixity.nonass(precedence++));
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 12: // '\f'
|
||||||
|
parseFixityDefn(Fixity.right(precedence++));
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 14: // '\016'
|
||||||
|
parseStart();
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 16: // '\020'
|
||||||
|
settings.setClassName(parseIdent(lexer.getLexeme(), settings.getClassName()));
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 17: // '\021'
|
||||||
|
settings.setInterfaceName(parseIdent(lexer.getLexeme(), settings.getInterfaceName()));
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 15: // '\017'
|
||||||
|
settings.setPackageName(parseDefnQualName(lexer.getLexeme(), settings.getPackageName()));
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 18: // '\022'
|
||||||
|
settings.setExtendsName(parseDefnQualName(lexer.getLexeme(), settings.getExtendsName()));
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 19: // '\023'
|
||||||
|
lexer.nextToken();
|
||||||
|
String s = parseQualName();
|
||||||
|
if (s != null) {
|
||||||
|
settings.addImplementsNames(s);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 20: // '\024'
|
||||||
|
settings.setTypeName(parseDefnQualName(lexer.getLexeme(), settings.getTypeName()));
|
||||||
|
if (lexer.getToken() == 58) {
|
||||||
|
settings.setGetSemantic(lexer.readCodeLine());
|
||||||
|
lexer.nextToken();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 21: // '\025'
|
||||||
|
settings.setGetToken(lexer.readCodeLine());
|
||||||
|
lexer.nextToken();
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 22: // '\026'
|
||||||
|
settings.setNextToken(lexer.readCodeLine());
|
||||||
|
lexer.nextToken();
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 3: // '\003'
|
||||||
|
case 4: // '\004'
|
||||||
|
case 5: // '\005'
|
||||||
|
case 6: // '\006'
|
||||||
|
case 7: // '\007'
|
||||||
|
case 10: // '\n'
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseStart() throws IOException {
|
||||||
|
Position position = lexer.getPos();
|
||||||
|
lexer.nextToken();
|
||||||
|
JaccSymbol jaccsymbol = parseNonterminal();
|
||||||
|
if (jaccsymbol == null) {
|
||||||
|
report(new Failure(position, "Missing start symbol"));
|
||||||
|
} else {
|
||||||
|
if (start == null) {
|
||||||
|
start = jaccsymbol;
|
||||||
|
} else {
|
||||||
|
report(new Failure(position, "Multiple %start definitions are not permitted"));
|
||||||
|
}
|
||||||
|
lexer.nextToken();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String parseIdent(String s, String s1) throws IOException {
|
||||||
|
Position position = lexer.getPos();
|
||||||
|
if (lexer.nextToken() != 3) {
|
||||||
|
report(new Failure(lexer.getPos(), "Syntax error in %" + s + " directive; identifier expected"));
|
||||||
|
return s1;
|
||||||
|
}
|
||||||
|
String s2 = lexer.getLexeme();
|
||||||
|
lexer.nextToken();
|
||||||
|
if (s2 != null && s1 != null) {
|
||||||
|
report(new Failure(position, "Multiple %" + s + " definitions are not permitted"));
|
||||||
|
s2 = s1;
|
||||||
|
}
|
||||||
|
return s2;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String parseDefnQualName(String s, String s1) throws IOException {
|
||||||
|
Position position = lexer.getPos();
|
||||||
|
lexer.nextToken();
|
||||||
|
String s2 = parseQualName();
|
||||||
|
if (s2 != null && s1 != null) {
|
||||||
|
report(new Failure(position, "Multiple %" + s + " definitions are not permitted"));
|
||||||
|
s2 = s1;
|
||||||
|
}
|
||||||
|
return s2;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseTokenDefn() throws IOException {
|
||||||
|
Position position = lexer.getPos();
|
||||||
|
String s = optionalType();
|
||||||
|
int i = 0;
|
||||||
|
do {
|
||||||
|
JaccSymbol jaccsymbol = parseTerminal();
|
||||||
|
if (jaccsymbol == null) {
|
||||||
|
if (i == 0) {
|
||||||
|
report(new Failure(position, "Missing symbols in %token definition"));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
addType(jaccsymbol, s);
|
||||||
|
lexer.nextToken();
|
||||||
|
i++;
|
||||||
|
} while (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseTypeDefn() throws IOException {
|
||||||
|
Position position = lexer.getPos();
|
||||||
|
String s = optionalType();
|
||||||
|
int i = 0;
|
||||||
|
do {
|
||||||
|
JaccSymbol jaccsymbol = parseSymbol();
|
||||||
|
if (jaccsymbol == null) {
|
||||||
|
if (i == 0) {
|
||||||
|
report(new Failure(position, "Missing symbols in %type definition"));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
addType(jaccsymbol, s);
|
||||||
|
lexer.nextToken();
|
||||||
|
i++;
|
||||||
|
} while (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseFixityDefn(Fixity fixity) throws IOException {
|
||||||
|
Position position = lexer.getPos();
|
||||||
|
String s = optionalType();
|
||||||
|
int i = 0;
|
||||||
|
do {
|
||||||
|
JaccSymbol jaccsymbol = parseTerminal();
|
||||||
|
if (jaccsymbol == null) {
|
||||||
|
if (i == 0) {
|
||||||
|
report(new Failure(position, "Missing symbols in fixity definition"));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
addFixity(jaccsymbol, fixity);
|
||||||
|
addType(jaccsymbol, s);
|
||||||
|
lexer.nextToken();
|
||||||
|
i++;
|
||||||
|
} while (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String optionalType() throws IOException {
|
||||||
|
label0:
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
label1:
|
||||||
|
{
|
||||||
|
if (lexer.nextToken() != 60) {
|
||||||
|
break label0;
|
||||||
|
}
|
||||||
|
lexer.nextToken();
|
||||||
|
sb.append(parseQualName());
|
||||||
|
do {
|
||||||
|
if (lexer.getToken() != 91) {
|
||||||
|
break label1;
|
||||||
|
}
|
||||||
|
if (lexer.nextToken() != 93) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
lexer.nextToken();
|
||||||
|
sb.append("[]");
|
||||||
|
} while (true);
|
||||||
|
report(new Failure(lexer.getPos(), "Missing ']' in array type"));
|
||||||
|
}
|
||||||
|
if (lexer.getToken() == 62) {
|
||||||
|
lexer.nextToken();
|
||||||
|
} else if (sb.length() > 0) {
|
||||||
|
report(new Failure(lexer.getPos(), "Missing `>' in type specification"));
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addFixity(JaccSymbol jaccsymbol, Fixity fixity) {
|
||||||
|
if (!jaccsymbol.setFixity(fixity)) {
|
||||||
|
report(new Warning(lexer.getPos(), "Cannot change fixity for " + jaccsymbol.getName()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addType(JaccSymbol jaccsymbol, String s) {
|
||||||
|
if (s != null && !jaccsymbol.setType(s)) {
|
||||||
|
report(new Warning(lexer.getPos(), "Cannot change type for " + jaccsymbol.getName()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseGrammar() throws IOException {
|
||||||
|
JaccSymbol jaccsymbol;
|
||||||
|
while ((jaccsymbol = parseLhs()) != null) {
|
||||||
|
if (start == null) {
|
||||||
|
start = jaccsymbol;
|
||||||
|
}
|
||||||
|
jaccsymbol.addProduction(parseRhs());
|
||||||
|
for (; lexer.getToken() == 124; jaccsymbol.addProduction(parseRhs())) {
|
||||||
|
lexer.nextToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lexer.getToken() == 59) {
|
||||||
|
lexer.nextToken();
|
||||||
|
} else {
|
||||||
|
report(new Warning(lexer.getPos(), "Missing ';' at end of rule"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private JaccSymbol parseLhs() throws IOException {
|
||||||
|
boolean flag = false;
|
||||||
|
for (int i = lexer.getToken(); i != 1 && i != 0; ) {
|
||||||
|
JaccSymbol jaccsymbol = parseNonterminal();
|
||||||
|
if (jaccsymbol == null) {
|
||||||
|
if (!flag) {
|
||||||
|
if (parseTerminal() != null) {
|
||||||
|
report(new Failure(lexer.getPos(), "Terminal symbol used on left hand side of rule"));
|
||||||
|
} else {
|
||||||
|
report(new Failure(lexer.getPos(), "Missing left hand side in rule"));
|
||||||
|
}
|
||||||
|
flag = true;
|
||||||
|
}
|
||||||
|
i = lexer.nextToken();
|
||||||
|
} else {
|
||||||
|
i = lexer.nextToken();
|
||||||
|
if (i != 58) {
|
||||||
|
if (!flag) {
|
||||||
|
report(new Failure(lexer.getPos(), "Missing colon after left hand side of rule"));
|
||||||
|
}
|
||||||
|
flag = true;
|
||||||
|
} else {
|
||||||
|
lexer.nextToken();
|
||||||
|
return jaccsymbol;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private JaccProd parseRhs() throws IOException {
|
||||||
|
Fixity fixity = null;
|
||||||
|
SymList symlist = null;
|
||||||
|
do {
|
||||||
|
while (lexer.getToken() == 10) {
|
||||||
|
lexer.nextToken();
|
||||||
|
JaccSymbol jaccsymbol = parseSymbol();
|
||||||
|
if (jaccsymbol == null) {
|
||||||
|
report(new Failure(lexer.getPos(), "Missing token for %prec directive"));
|
||||||
|
} else if (jaccsymbol.getFixity() == null) {
|
||||||
|
report(new Failure(lexer.getPos(),
|
||||||
|
"Ignoring %prec annotation because no fixity has been specified for " +
|
||||||
|
jaccsymbol.getName()));
|
||||||
|
lexer.nextToken();
|
||||||
|
} else {
|
||||||
|
if (fixity != null) {
|
||||||
|
report(new Warning(lexer.getPos(), "Multiple %prec annotations in production"));
|
||||||
|
}
|
||||||
|
fixity = jaccsymbol.getFixity();
|
||||||
|
lexer.nextToken();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
JaccSymbol jaccsymbol1 = parseSymbol();
|
||||||
|
if (jaccsymbol1 == null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
symlist = new SymList(jaccsymbol1, symlist);
|
||||||
|
lexer.nextToken();
|
||||||
|
} while (true);
|
||||||
|
String s = null;
|
||||||
|
Position position = null;
|
||||||
|
if (lexer.getToken() == 7) {
|
||||||
|
s = lexer.getLexeme();
|
||||||
|
position = lexer.getPos();
|
||||||
|
lexer.nextToken();
|
||||||
|
}
|
||||||
|
JaccSymbol ajaccsymbol[] = SymList.toArray(symlist);
|
||||||
|
return new JaccProd(fixity, ajaccsymbol, position, s, seqNo++);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String parseQualName() throws IOException {
|
||||||
|
if (lexer.getToken() != 3) {
|
||||||
|
report(new Failure(lexer.getPos(), "Syntax error in qualified name; identifier expected"));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
StringBuilder stringbuffer = new StringBuilder();
|
||||||
|
do {
|
||||||
|
stringbuffer.append(lexer.getLexeme());
|
||||||
|
if (lexer.nextToken() != 46) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (lexer.nextToken() != 3) {
|
||||||
|
report(new Failure(lexer.getPos(), "Syntax error in qualified name"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
stringbuffer.append('.');
|
||||||
|
} while (true);
|
||||||
|
return stringbuffer.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private JaccSymbol parseTerminal() {
|
||||||
|
String s = lexer.getLexeme();
|
||||||
|
switch (lexer.getToken()) {
|
||||||
|
case 3: // '\003'
|
||||||
|
if (nonterms.find(s) != null) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return terminals.findOrAdd(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
case 4: // '\004'
|
||||||
|
return literals.findOrAdd(s, lexer.getLastLiteral());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private JaccSymbol parseNonterminal() {
|
||||||
|
String s = lexer.getLexeme();
|
||||||
|
switch (lexer.getToken()) {
|
||||||
|
case 3: // '\003'
|
||||||
|
if (terminals.find(s) != null) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return nonterms.findOrAdd(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private JaccSymbol parseSymbol() {
|
||||||
|
String s = lexer.getLexeme();
|
||||||
|
switch (lexer.getToken()) {
|
||||||
|
case 3: // '\003'
|
||||||
|
JaccSymbol jaccsymbol;
|
||||||
|
jaccsymbol = terminals.find(s);
|
||||||
|
if (jaccsymbol == null) {
|
||||||
|
jaccsymbol = nonterms.findOrAdd(s);
|
||||||
|
}
|
||||||
|
return jaccsymbol;
|
||||||
|
|
||||||
|
case 4: // '\004'
|
||||||
|
return literals.findOrAdd(s, lexer.getLastLiteral());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private JaccSymbol parseDefinedSymbol() {
|
||||||
|
String s = lexer.getLexeme();
|
||||||
|
switch (lexer.getToken()) {
|
||||||
|
case 3: // '\003'
|
||||||
|
JaccSymbol jaccsymbol = nonterms.find(s);
|
||||||
|
return jaccsymbol == null ? terminals.find(s) : jaccsymbol;
|
||||||
|
|
||||||
|
case 4: // '\004'
|
||||||
|
return literals.find(lexer.getLastLiteral());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class SymList {
|
||||||
|
|
||||||
|
JaccSymbol head;
|
||||||
|
SymList tail;
|
||||||
|
|
||||||
|
SymList(JaccSymbol jaccsymbol, SymList symlist) {
|
||||||
|
head = jaccsymbol;
|
||||||
|
tail = symlist;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int length(SymList symlist) {
|
||||||
|
int i = 0;
|
||||||
|
for (; symlist != null; symlist = symlist.tail) {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static JaccSymbol[] toArray(SymList symlist) {
|
||||||
|
int i = length(symlist);
|
||||||
|
JaccSymbol ajaccsymbol[] = new JaccSymbol[i];
|
||||||
|
while (i > 0) {
|
||||||
|
ajaccsymbol[--i] = symlist.head;
|
||||||
|
symlist = symlist.tail;
|
||||||
|
}
|
||||||
|
return ajaccsymbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int[] toIntArray(SymList symlist) {
|
||||||
|
int i = length(symlist);
|
||||||
|
int ai[] = new int[i];
|
||||||
|
while (i > 0) {
|
||||||
|
ai[--i] = symlist.head.getTokenNo();
|
||||||
|
symlist = symlist.tail;
|
||||||
|
}
|
||||||
|
return ai;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
54
src/main/java/org/xbib/jacc/JaccProd.java
Normal file
54
src/main/java/org/xbib/jacc/JaccProd.java
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
package org.xbib.jacc;
|
||||||
|
|
||||||
|
import org.xbib.jacc.compiler.Position;
|
||||||
|
import org.xbib.jacc.grammar.Grammar;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class JaccProd extends Grammar.Prod {
|
||||||
|
|
||||||
|
private Fixity fixity;
|
||||||
|
private JaccSymbol[] prodSyms;
|
||||||
|
private Position actPos;
|
||||||
|
private String action;
|
||||||
|
|
||||||
|
JaccProd(Fixity fixity, JaccSymbol[] jaccsymbol, Position position, String s, int i) {
|
||||||
|
super(new int[jaccsymbol.length], i);
|
||||||
|
this.fixity = fixity;
|
||||||
|
prodSyms = jaccsymbol;
|
||||||
|
actPos = position;
|
||||||
|
action = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLabel() {
|
||||||
|
return Integer.toString(getSeqNo());
|
||||||
|
}
|
||||||
|
|
||||||
|
void fixup() {
|
||||||
|
int[] ai = getRhs();
|
||||||
|
for (int i = 0; i < prodSyms.length; i++) {
|
||||||
|
ai[i] = prodSyms[i].getTokenNo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Fixity getFixity() {
|
||||||
|
if (fixity == null) {
|
||||||
|
for (int i = prodSyms.length - 1; i >= 0; i--) {
|
||||||
|
Fixity fixity1 = prodSyms[i].getFixity();
|
||||||
|
if (fixity1 != null) {
|
||||||
|
return fixity1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fixity;
|
||||||
|
}
|
||||||
|
|
||||||
|
Position getActionPos() {
|
||||||
|
return actPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getAction() {
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
}
|
73
src/main/java/org/xbib/jacc/JaccResolver.java
Normal file
73
src/main/java/org/xbib/jacc/JaccResolver.java
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
package org.xbib.jacc;
|
||||||
|
|
||||||
|
import org.xbib.jacc.grammar.Grammar;
|
||||||
|
import org.xbib.jacc.grammar.LR0Items;
|
||||||
|
import org.xbib.jacc.grammar.LookaheadMachine;
|
||||||
|
import org.xbib.jacc.grammar.Resolver;
|
||||||
|
import org.xbib.jacc.grammar.Tables;
|
||||||
|
import org.xbib.jacc.util.IntSet;
|
||||||
|
|
||||||
|
class JaccResolver implements Resolver {
|
||||||
|
|
||||||
|
private LookaheadMachine machine;
|
||||||
|
private int numSRConflicts;
|
||||||
|
private int numRRConflicts;
|
||||||
|
private Conflicts conflicts[];
|
||||||
|
|
||||||
|
JaccResolver(LookaheadMachine lookaheadmachine) {
|
||||||
|
numSRConflicts = 0;
|
||||||
|
numRRConflicts = 0;
|
||||||
|
machine = lookaheadmachine;
|
||||||
|
conflicts = new Conflicts[lookaheadmachine.getNumStates()];
|
||||||
|
}
|
||||||
|
|
||||||
|
int getNumSRConflicts() {
|
||||||
|
return numSRConflicts;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getNumRRConflicts() {
|
||||||
|
return numRRConflicts;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getConflictsAt(int i) {
|
||||||
|
return Conflicts.describe(machine, i, conflicts[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void srResolve(Tables tables, int i, int j, int k) {
|
||||||
|
Grammar grammar = machine.getGrammar();
|
||||||
|
Grammar.Symbol symbol = grammar.getTerminal(j);
|
||||||
|
IntSet intset = machine.getItemsAt(i);
|
||||||
|
LR0Items lr0items = machine.getItems();
|
||||||
|
Grammar.Prod prod = lr0items.getItem(intset.at(k)).getProd();
|
||||||
|
if ((symbol instanceof JaccSymbol) && (prod instanceof JaccProd)) {
|
||||||
|
JaccSymbol jaccsymbol = (JaccSymbol) symbol;
|
||||||
|
JaccProd jaccprod = (JaccProd) prod;
|
||||||
|
switch (Fixity.which(jaccprod.getFixity(), jaccsymbol.getFixity())) {
|
||||||
|
case 1:
|
||||||
|
tables.setReduce(i, j, k);
|
||||||
|
return;
|
||||||
|
case 3:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
conflicts[i] = Conflicts.sr(tables.getArgAt(i)[j], k, symbol, conflicts[i]);
|
||||||
|
numSRConflicts++;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void rrResolve(Tables tables, int i, int j, int k) {
|
||||||
|
Grammar grammar = machine.getGrammar();
|
||||||
|
int l = tables.getArgAt(i)[j];
|
||||||
|
IntSet intset = machine.getItemsAt(i);
|
||||||
|
LR0Items lr0items = machine.getItems();
|
||||||
|
Grammar.Prod prod = lr0items.getItem(intset.at(l)).getProd();
|
||||||
|
Grammar.Prod prod1 = lr0items.getItem(intset.at(k)).getProd();
|
||||||
|
Grammar.Symbol symbol = grammar.getTerminal(j);
|
||||||
|
if (prod1.getSeqNo() < prod.getSeqNo()) {
|
||||||
|
tables.setReduce(i, j, k);
|
||||||
|
}
|
||||||
|
conflicts[i] = Conflicts.rr(l, k, symbol, conflicts[i]);
|
||||||
|
numRRConflicts++;
|
||||||
|
}
|
||||||
|
}
|
97
src/main/java/org/xbib/jacc/JaccSymbol.java
Normal file
97
src/main/java/org/xbib/jacc/JaccSymbol.java
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
package org.xbib.jacc;
|
||||||
|
|
||||||
|
import org.xbib.jacc.grammar.Grammar;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class JaccSymbol extends Grammar.Symbol {
|
||||||
|
|
||||||
|
private int num;
|
||||||
|
private int tokenNo;
|
||||||
|
private JaccProd[] jaccProds;
|
||||||
|
private int pused;
|
||||||
|
private Fixity fixity;
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
JaccSymbol(String s, int i) {
|
||||||
|
super(s);
|
||||||
|
tokenNo = -1;
|
||||||
|
jaccProds = null;
|
||||||
|
pused = 0;
|
||||||
|
num = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
JaccSymbol(String s) {
|
||||||
|
this(s, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int getNum() {
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setNum(int i) {
|
||||||
|
if (num < 0) {
|
||||||
|
num = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int getTokenNo() {
|
||||||
|
return tokenNo;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setTokenNo(int i) {
|
||||||
|
if (tokenNo < 0) {
|
||||||
|
tokenNo = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void addProduction(JaccProd jaccprod) {
|
||||||
|
if (jaccProds == null) {
|
||||||
|
jaccProds = new JaccProd[1];
|
||||||
|
} else {
|
||||||
|
if (pused >= jaccProds.length) {
|
||||||
|
JaccProd ajaccprod[] = new JaccProd[2 * jaccProds.length];
|
||||||
|
System.arraycopy(jaccProds, 0, ajaccprod, 0, jaccProds.length);
|
||||||
|
|
||||||
|
jaccProds = ajaccprod;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
jaccProds[pused++] = jaccprod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JaccProd[] getProds() {
|
||||||
|
JaccProd ajaccprod[] = new JaccProd[pused];
|
||||||
|
for (int i = 0; i < pused; i++) {
|
||||||
|
ajaccprod[i] = jaccProds[i];
|
||||||
|
ajaccprod[i].fixup();
|
||||||
|
}
|
||||||
|
return ajaccprod;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean setFixity(Fixity fixity1) {
|
||||||
|
if (fixity == null) {
|
||||||
|
fixity = fixity1;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return fixity1.equalsFixity(fixity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Fixity getFixity() {
|
||||||
|
return fixity;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean setType(String s) {
|
||||||
|
if (type == null) {
|
||||||
|
type = s;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return s.compareTo(type) == 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
38
src/main/java/org/xbib/jacc/JaccSymbols.java
Normal file
38
src/main/java/org/xbib/jacc/JaccSymbols.java
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
package org.xbib.jacc;
|
||||||
|
|
||||||
|
abstract class JaccSymbols {
|
||||||
|
Node root;
|
||||||
|
int size;
|
||||||
|
JaccSymbols() {
|
||||||
|
root = null;
|
||||||
|
size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int fill(JaccSymbol ajaccsymbol[], int i, Node node) {
|
||||||
|
if (node != null) {
|
||||||
|
i = fill(ajaccsymbol, i, node.left);
|
||||||
|
ajaccsymbol[i++] = node.data;
|
||||||
|
i = fill(ajaccsymbol, i, node.right);
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getSize() {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fill(JaccSymbol ajaccsymbol[], int i) {
|
||||||
|
return fill(ajaccsymbol, i, root);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static class Node {
|
||||||
|
|
||||||
|
Node left;
|
||||||
|
JaccSymbol data;
|
||||||
|
Node right;
|
||||||
|
|
||||||
|
Node(JaccSymbol data) {
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
191
src/main/java/org/xbib/jacc/JaccTables.java
Normal file
191
src/main/java/org/xbib/jacc/JaccTables.java
Normal file
|
@ -0,0 +1,191 @@
|
||||||
|
package org.xbib.jacc;
|
||||||
|
|
||||||
|
import org.xbib.jacc.grammar.LookaheadMachine;
|
||||||
|
import org.xbib.jacc.grammar.Resolver;
|
||||||
|
import org.xbib.jacc.grammar.Tables;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Writer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class JaccTables extends Tables {
|
||||||
|
|
||||||
|
private String[] errors;
|
||||||
|
private int numErrors;
|
||||||
|
private int[][] index;
|
||||||
|
private int[] defaultRow;
|
||||||
|
|
||||||
|
JaccTables(LookaheadMachine lookaheadmachine, Resolver resolver) {
|
||||||
|
super(lookaheadmachine, resolver);
|
||||||
|
errors = null;
|
||||||
|
numErrors = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getNumErrors() {
|
||||||
|
return numErrors;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getError(int i) {
|
||||||
|
return errors[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean errorAt(int i, int j) {
|
||||||
|
return action[i][j - numNTs] == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
String errorSet(int i, int j, String s) {
|
||||||
|
if (arg[i][j - numNTs] != 0) {
|
||||||
|
return errors[arg[i][j - numNTs] - 1];
|
||||||
|
} else {
|
||||||
|
arg[i][j - numNTs] = errorNo(s) + 1;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int errorNo(String s) {
|
||||||
|
for (int i = 0; i < numErrors; i++) {
|
||||||
|
if (errors[i].equals(s)) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String as[] = new String[numErrors != 0 ? 2 * numErrors : 1];
|
||||||
|
System.arraycopy(errors, 0, as, 0, numErrors);
|
||||||
|
errors = as;
|
||||||
|
errors[numErrors] = s;
|
||||||
|
return numErrors++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void analyzeRows() {
|
||||||
|
if (index == null) {
|
||||||
|
RowAnalysis rowanalysis = new RowAnalysis();
|
||||||
|
int i = machine.getNumStates();
|
||||||
|
index = new int[i][];
|
||||||
|
defaultRow = new int[i];
|
||||||
|
for (int j = 0; j < i; j++) {
|
||||||
|
rowanalysis.analyze(j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int[] indexAt(int i) {
|
||||||
|
return index[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
int getDefaultRowAt(int i) {
|
||||||
|
return defaultRow[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void display(Writer writer) throws IOException {
|
||||||
|
int i = machine.getNumStates();
|
||||||
|
for (int j = 0; j < i; j++) {
|
||||||
|
writer.write("state " + j + ":\n");
|
||||||
|
for (int k = 0; k < numTs; k++) {
|
||||||
|
switch (action[j][k]) {
|
||||||
|
case 0:
|
||||||
|
writer.write(" E");
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
writer.write(" S");
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
writer.write(" R");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
writer.write(arg[j][k]);
|
||||||
|
}
|
||||||
|
writer.write("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private class RowAnalysis {
|
||||||
|
private byte[] a;
|
||||||
|
private int[] b;
|
||||||
|
private int size;
|
||||||
|
private int[] idx;
|
||||||
|
|
||||||
|
void analyze(int i) {
|
||||||
|
a = action[i];
|
||||||
|
b = arg[i];
|
||||||
|
size = numTs;
|
||||||
|
idx = new int[size];
|
||||||
|
for (int j = 0; j < numTs; j++) {
|
||||||
|
idx[j] = j;
|
||||||
|
}
|
||||||
|
for (int k = size / 2; k >= 0; k--) {
|
||||||
|
heapify(k);
|
||||||
|
}
|
||||||
|
for (int l = size - 1; l > 0; l--) {
|
||||||
|
int i1 = idx[l];
|
||||||
|
idx[l] = idx[0];
|
||||||
|
idx[0] = i1;
|
||||||
|
size--;
|
||||||
|
heapify(0);
|
||||||
|
}
|
||||||
|
index[i] = idx;
|
||||||
|
defaultRow[i] = findDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void heapify(int i) {
|
||||||
|
int j = i;
|
||||||
|
int k = idx[j];
|
||||||
|
do {
|
||||||
|
int l = 2 * i + 1;
|
||||||
|
int i1 = l + 1;
|
||||||
|
if (l < size) {
|
||||||
|
int j1 = idx[l];
|
||||||
|
if (a[j1] > a[k] || a[j1] == a[k] && b[j1] > b[k]) {
|
||||||
|
j = l;
|
||||||
|
k = j1;
|
||||||
|
}
|
||||||
|
if (i1 < size) {
|
||||||
|
int k1 = idx[i1];
|
||||||
|
if (a[k1] > a[k] || a[k1] == a[k] && b[k1] > b[k]) {
|
||||||
|
j = i1;
|
||||||
|
k = k1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (j == i) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
idx[j] = idx[i];
|
||||||
|
idx[i] = k;
|
||||||
|
i = j;
|
||||||
|
k = idx[j];
|
||||||
|
} while (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
int findDefault() {
|
||||||
|
int i = 1;
|
||||||
|
int j = -1;
|
||||||
|
int k = 0;
|
||||||
|
do {
|
||||||
|
if (k >= a.length) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
int l = idx[k];
|
||||||
|
byte byte0 = a[l];
|
||||||
|
if (byte0 == 1) {
|
||||||
|
k++;
|
||||||
|
} else {
|
||||||
|
int j1 = 1;
|
||||||
|
for (int k1 = b[l]; ++k < a.length && a[idx[k]] == byte0 && b[idx[k]] == k1; ) {
|
||||||
|
j1++;
|
||||||
|
}
|
||||||
|
if (j1 > i) {
|
||||||
|
j = l;
|
||||||
|
i = j1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (true);
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
36
src/main/java/org/xbib/jacc/JaccTokens.java
Normal file
36
src/main/java/org/xbib/jacc/JaccTokens.java
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
package org.xbib.jacc;
|
||||||
|
|
||||||
|
interface JaccTokens {
|
||||||
|
int ERROR = -1;
|
||||||
|
int ENDINPUT = 0;
|
||||||
|
int MARK = 1;
|
||||||
|
int CODE = 2;
|
||||||
|
int IDENT = 3;
|
||||||
|
int CHARLIT = 4;
|
||||||
|
int STRLIT = 5;
|
||||||
|
int INTLIT = 6;
|
||||||
|
int ACTION = 7;
|
||||||
|
int TOKEN = 8;
|
||||||
|
int TYPE = 9;
|
||||||
|
int PREC = 10;
|
||||||
|
int LEFT = 11;
|
||||||
|
int RIGHT = 12;
|
||||||
|
int NONASSOC = 13;
|
||||||
|
int START = 14;
|
||||||
|
int PACKAGE = 15;
|
||||||
|
int CLASS = 16;
|
||||||
|
int INTERFACE = 17;
|
||||||
|
int EXTENDS = 18;
|
||||||
|
int IMPLEMENTS = 19;
|
||||||
|
int SEMANTIC = 20;
|
||||||
|
int GETTOKEN = 21;
|
||||||
|
int NEXTTOKEN = 22;
|
||||||
|
int COLON = 58;
|
||||||
|
int SEMI = 59;
|
||||||
|
int BAR = 124;
|
||||||
|
int TOPEN = 60;
|
||||||
|
int TCLOSE = 62;
|
||||||
|
int BOPEN = 91;
|
||||||
|
int BCLOSE = 93;
|
||||||
|
int DOT = 46;
|
||||||
|
}
|
53
src/main/java/org/xbib/jacc/NamedJaccSymbols.java
Normal file
53
src/main/java/org/xbib/jacc/NamedJaccSymbols.java
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
package org.xbib.jacc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class NamedJaccSymbols extends JaccSymbols {
|
||||||
|
|
||||||
|
JaccSymbol find(String s) {
|
||||||
|
for (JaccSymbols.Node node = root; node != null; ) {
|
||||||
|
int i = s.compareTo(node.data.getName());
|
||||||
|
if (i < 0) {
|
||||||
|
node = node.left;
|
||||||
|
} else if (i > 0) {
|
||||||
|
node = node.right;
|
||||||
|
} else {
|
||||||
|
return node.data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
JaccSymbol findOrAdd(String s) {
|
||||||
|
if (root == null) {
|
||||||
|
JaccSymbol jaccsymbol = new JaccSymbol(s);
|
||||||
|
root = new JaccSymbols.Node(jaccsymbol);
|
||||||
|
size++;
|
||||||
|
return jaccsymbol;
|
||||||
|
}
|
||||||
|
JaccSymbols.Node node = root;
|
||||||
|
do {
|
||||||
|
int i = s.compareTo(node.data.getName());
|
||||||
|
if (i < 0) {
|
||||||
|
if (node.left == null) {
|
||||||
|
JaccSymbol jaccsymbol1 = new JaccSymbol(s);
|
||||||
|
node.left = new JaccSymbols.Node(jaccsymbol1);
|
||||||
|
size++;
|
||||||
|
return jaccsymbol1;
|
||||||
|
}
|
||||||
|
node = node.left;
|
||||||
|
} else if (i > 0) {
|
||||||
|
if (node.right == null) {
|
||||||
|
JaccSymbol jaccsymbol2 = new JaccSymbol(s);
|
||||||
|
node.right = new JaccSymbols.Node(jaccsymbol2);
|
||||||
|
size++;
|
||||||
|
return jaccsymbol2;
|
||||||
|
}
|
||||||
|
node = node.right;
|
||||||
|
} else {
|
||||||
|
return node.data;
|
||||||
|
}
|
||||||
|
} while (true);
|
||||||
|
}
|
||||||
|
}
|
53
src/main/java/org/xbib/jacc/NumJaccSymbols.java
Normal file
53
src/main/java/org/xbib/jacc/NumJaccSymbols.java
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
package org.xbib.jacc;
|
||||||
|
|
||||||
|
class NumJaccSymbols extends JaccSymbols {
|
||||||
|
|
||||||
|
JaccSymbol find(int i) {
|
||||||
|
Node node = root;
|
||||||
|
while (node != null) {
|
||||||
|
int j = node.data.getNum();
|
||||||
|
if (i < j) {
|
||||||
|
node = node.left;
|
||||||
|
} else {
|
||||||
|
if (i > j) {
|
||||||
|
node = node.right;
|
||||||
|
} else {
|
||||||
|
return node.data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
JaccSymbol findOrAdd(String s, int i) {
|
||||||
|
if (root == null) {
|
||||||
|
JaccSymbol jaccsymbol = new JaccSymbol(s, i);
|
||||||
|
root = new JaccSymbols.Node(jaccsymbol);
|
||||||
|
size++;
|
||||||
|
return jaccsymbol;
|
||||||
|
}
|
||||||
|
JaccSymbols.Node node = root;
|
||||||
|
do {
|
||||||
|
int j = node.data.getNum();
|
||||||
|
if (i < j) {
|
||||||
|
if (node.left == null) {
|
||||||
|
JaccSymbol jaccsymbol1 = new JaccSymbol(s, i);
|
||||||
|
node.left = new JaccSymbols.Node(jaccsymbol1);
|
||||||
|
size++;
|
||||||
|
return jaccsymbol1;
|
||||||
|
}
|
||||||
|
node = node.left;
|
||||||
|
} else if (i > j) {
|
||||||
|
if (node.right == null) {
|
||||||
|
JaccSymbol jaccsymbol2 = new JaccSymbol(s, i);
|
||||||
|
node.right = new JaccSymbols.Node(jaccsymbol2);
|
||||||
|
size++;
|
||||||
|
return jaccsymbol2;
|
||||||
|
}
|
||||||
|
node = node.right;
|
||||||
|
} else {
|
||||||
|
return node.data;
|
||||||
|
}
|
||||||
|
} while (true);
|
||||||
|
}
|
||||||
|
}
|
85
src/main/java/org/xbib/jacc/Output.java
Normal file
85
src/main/java/org/xbib/jacc/Output.java
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
package org.xbib.jacc;
|
||||||
|
|
||||||
|
import org.xbib.jacc.compiler.Failure;
|
||||||
|
import org.xbib.jacc.compiler.Handler;
|
||||||
|
import org.xbib.jacc.compiler.Phase;
|
||||||
|
import org.xbib.jacc.grammar.Grammar;
|
||||||
|
import org.xbib.jacc.grammar.Machine;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.io.Writer;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
abstract class Output extends Phase {
|
||||||
|
|
||||||
|
protected Grammar grammar;
|
||||||
|
protected int numTs;
|
||||||
|
protected int numNTs;
|
||||||
|
protected Machine machine;
|
||||||
|
int numSyms;
|
||||||
|
int numStates;
|
||||||
|
JaccTables tables;
|
||||||
|
JaccResolver resolver;
|
||||||
|
Settings settings;
|
||||||
|
|
||||||
|
Output(Handler handler, JaccJob jaccjob) {
|
||||||
|
super(handler);
|
||||||
|
tables = jaccjob.getTables();
|
||||||
|
machine = tables.getMachine();
|
||||||
|
grammar = machine.getGrammar();
|
||||||
|
numTs = grammar.getNumTs();
|
||||||
|
numNTs = grammar.getNumNTs();
|
||||||
|
numSyms = grammar.getNumSyms();
|
||||||
|
numStates = machine.getNumStates();
|
||||||
|
resolver = jaccjob.getResolver();
|
||||||
|
settings = jaccjob.getSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void indent(Writer writer, int i, String[] as) throws IOException {
|
||||||
|
for (String a : as) {
|
||||||
|
indent(writer, i, a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void indent(Writer writer, int i) throws IOException {
|
||||||
|
for (int j = 0; j < i; j++) {
|
||||||
|
writer.write(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void indent(Writer writer, int i, String s) throws IOException {
|
||||||
|
indent(writer, i);
|
||||||
|
writer.write(s + "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void datestamp(Writer writer) throws IOException {
|
||||||
|
writer.write("// Output created by jacc 2.1.0 on " + LocalDateTime.now() + "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void write(String s) throws IOException {
|
||||||
|
Writer writer = null;
|
||||||
|
try {
|
||||||
|
File file = new File(s);
|
||||||
|
File parent = file.getParentFile();
|
||||||
|
if (!parent.exists()) {
|
||||||
|
boolean mkdirs = parent.mkdirs();
|
||||||
|
}
|
||||||
|
writer = new OutputStreamWriter(new FileOutputStream(s), StandardCharsets.UTF_8);
|
||||||
|
write(writer);
|
||||||
|
} catch (IOException ioexception) {
|
||||||
|
report(new Failure("Cannot write to file \"" + s + "\""));
|
||||||
|
}
|
||||||
|
if (writer != null) {
|
||||||
|
writer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void write(Writer writer) throws IOException;
|
||||||
|
}
|
498
src/main/java/org/xbib/jacc/ParserOutput.java
Normal file
498
src/main/java/org/xbib/jacc/ParserOutput.java
Normal file
|
@ -0,0 +1,498 @@
|
||||||
|
package org.xbib.jacc;
|
||||||
|
|
||||||
|
import org.xbib.jacc.compiler.Failure;
|
||||||
|
import org.xbib.jacc.compiler.Handler;
|
||||||
|
import org.xbib.jacc.grammar.Grammar;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Writer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class ParserOutput extends Output {
|
||||||
|
|
||||||
|
private int yyaccept;
|
||||||
|
private int yyabort;
|
||||||
|
private int stackOverflow;
|
||||||
|
private int errorHandler;
|
||||||
|
private int userErrorHandler;
|
||||||
|
private int[] stNumSwitches;
|
||||||
|
private int[][] ntGoto;
|
||||||
|
private int[][] ntGotoSrc;
|
||||||
|
private int[] ntDefault;
|
||||||
|
private int[] ntDistinct;
|
||||||
|
private int errTok;
|
||||||
|
private boolean errMsgs;
|
||||||
|
private boolean errUsed;
|
||||||
|
|
||||||
|
ParserOutput(Handler handler, JaccJob jaccjob) {
|
||||||
|
super(handler, jaccjob);
|
||||||
|
errMsgs = false;
|
||||||
|
errUsed = false;
|
||||||
|
tables.analyzeRows();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void write(Writer writer) throws IOException {
|
||||||
|
datestamp(writer);
|
||||||
|
String s = settings.getPackageName();
|
||||||
|
if (s != null) {
|
||||||
|
writer.write("package " + s + ";\n");
|
||||||
|
}
|
||||||
|
if (settings.getPreText() != null) {
|
||||||
|
writer.write(settings.getPreText() + "\n");
|
||||||
|
}
|
||||||
|
yyaccept = 2 * numStates;
|
||||||
|
stackOverflow = 2 * numStates + 1;
|
||||||
|
yyabort = 2 * numStates + 2;
|
||||||
|
errorHandler = 2 * numStates + 3;
|
||||||
|
userErrorHandler = 2 * numStates + 4;
|
||||||
|
int ai[] = new int[numNTs];
|
||||||
|
stNumSwitches = new int[numStates];
|
||||||
|
for (int i = 0; i < numStates; i++) {
|
||||||
|
int ai1[] = machine.getGotosAt(i);
|
||||||
|
for (int anAi1 : ai1) {
|
||||||
|
ai[machine.getEntry(anAi1)]++;
|
||||||
|
}
|
||||||
|
byte abyte0[] = tables.getActionAt(i);
|
||||||
|
int ai4[] = tables.getArgAt(i);
|
||||||
|
int l3 = tables.getDefaultRowAt(i);
|
||||||
|
stNumSwitches[i] = 0;
|
||||||
|
for (int j4 = 0; j4 < abyte0.length; j4++) {
|
||||||
|
if (l3 < 0 || abyte0[j4] != abyte0[l3] || ai4[j4] != ai4[l3]) {
|
||||||
|
stNumSwitches[i]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ntGoto = new int[numNTs][];
|
||||||
|
ntGotoSrc = new int[numNTs][];
|
||||||
|
ntDefault = new int[numNTs];
|
||||||
|
ntDistinct = new int[numNTs];
|
||||||
|
for (int j = 0; j < numNTs; j++) {
|
||||||
|
ntGoto[j] = new int[ai[j]];
|
||||||
|
ntGotoSrc[j] = new int[ai[j]];
|
||||||
|
}
|
||||||
|
for (int k = 0; k < numStates; k++) {
|
||||||
|
int ai2[] = machine.getGotosAt(k);
|
||||||
|
for (int anAi2 : ai2) {
|
||||||
|
int j3 = machine.getEntry(anAi2);
|
||||||
|
ntGoto[j3][--ai[j3]] = anAi2;
|
||||||
|
ntGotoSrc[j3][ai[j3]] = k;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int l = 0; l < numNTs; l++) {
|
||||||
|
int l1 = -1;
|
||||||
|
int k2 = 0;
|
||||||
|
int k3 = ntGoto[l].length;
|
||||||
|
for (int i4 = 0; i4 + k2 < k3; i4++) {
|
||||||
|
int k4 = 1;
|
||||||
|
for (int l4 = i4 + 1; l4 < k3; l4++) {
|
||||||
|
if (ntGoto[l][l4] == ntGoto[l][i4]) {
|
||||||
|
k4++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (k4 > k2) {
|
||||||
|
k2 = k4;
|
||||||
|
l1 = i4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ntDefault[l] = l1;
|
||||||
|
ntDistinct[l] = ntGoto[l].length - (k2 - 1);
|
||||||
|
}
|
||||||
|
errMsgs = tables.getNumErrors() > 0;
|
||||||
|
errTok = numNTs;
|
||||||
|
while (errTok < numSyms && !grammar.getSymbol(errTok).getName().equals("error")) {
|
||||||
|
errTok++;
|
||||||
|
}
|
||||||
|
if (errTok < numSyms) {
|
||||||
|
for (int i1 = 0; i1 < numStates && !errUsed; i1++) {
|
||||||
|
int ai3[] = machine.getShiftsAt(i1);
|
||||||
|
for (int l2 = 0; l2 < ai3.length && !errUsed; l2++) {
|
||||||
|
if (machine.getEntry(ai3[l2]) == errTok) {
|
||||||
|
errUsed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writer.write("public class " + settings.getClassName());
|
||||||
|
if (settings.getExtendsName() != null) {
|
||||||
|
writer.write(" extends " + settings.getExtendsName());
|
||||||
|
}
|
||||||
|
if (settings.getImplementsNames() != null) {
|
||||||
|
writer.write(" implements " + settings.getImplementsNames());
|
||||||
|
}
|
||||||
|
writer.write(" {\n");
|
||||||
|
indent(writer, 1, new String[]{
|
||||||
|
"private int yyss = 100;",
|
||||||
|
"private int yytok;",
|
||||||
|
"private int yysp = 0;",
|
||||||
|
"private int[] yyst;",
|
||||||
|
"protected int yyerrno = (-1);"
|
||||||
|
});
|
||||||
|
if (errUsed) {
|
||||||
|
indent(writer, 1, "private int yyerrstatus = 3;");
|
||||||
|
}
|
||||||
|
indent(writer, 1, "private " + settings.getTypeName() + "[] yysv;");
|
||||||
|
indent(writer, 1, "private " + settings.getTypeName() + " yyrv;");
|
||||||
|
writer.write("\n");
|
||||||
|
defineParse(writer, 1);
|
||||||
|
defineExpand(writer, 1);
|
||||||
|
defineErrRec(writer, 1);
|
||||||
|
for (int j1 = 0; j1 < numStates; j1++) {
|
||||||
|
defineState(writer, 1, j1);
|
||||||
|
}
|
||||||
|
for (int k1 = 0; k1 < numNTs; k1++) {
|
||||||
|
Grammar.Prod aprod[] = grammar.getProds(k1);
|
||||||
|
for (Grammar.Prod anAprod : aprod) {
|
||||||
|
defineReduce(writer, 1, anAprod, k1);
|
||||||
|
}
|
||||||
|
defineNonterminal(writer, 1, k1);
|
||||||
|
}
|
||||||
|
defineErrMsgs(writer);
|
||||||
|
if (settings.getPostText() != null) {
|
||||||
|
writer.write(settings.getPostText() + "\n");
|
||||||
|
}
|
||||||
|
writer.write("}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void defineErrMsgs(Writer writer) throws IOException {
|
||||||
|
if (errMsgs) {
|
||||||
|
indent(writer, 1, new String[]{
|
||||||
|
"private int yyerr(int e, int n) {", " yyerrno = e;", " return n;", "}"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
indent(writer, 1, "protected String[] yyerrmsgs = {");
|
||||||
|
int i = tables.getNumErrors();
|
||||||
|
if (i > 0) {
|
||||||
|
for (int j = 0; j < i - 1; j++) {
|
||||||
|
indent(writer, 2, "\"" + tables.getError(j) + "\",");
|
||||||
|
}
|
||||||
|
indent(writer, 2, "\"" + tables.getError(i - 1) + "\"");
|
||||||
|
}
|
||||||
|
indent(writer, 1, "};");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void defineExpand(Writer writer, int i) throws IOException {
|
||||||
|
indent(writer, i, new String[]{
|
||||||
|
"protected void yyexpand() {", " int[] newyyst = new int[2*yyst.length];"
|
||||||
|
});
|
||||||
|
indent(writer, i + 1, settings.getTypeName() + "[] newyysv = new " + settings.getTypeName() + "[2*yyst.length];");
|
||||||
|
indent(writer, i, new String[]{
|
||||||
|
" for (int i=0; i<yyst.length; i++) {",
|
||||||
|
" newyyst[i] = yyst[i];",
|
||||||
|
" newyysv[i] = yysv[i];", " }",
|
||||||
|
" yyst = newyyst;",
|
||||||
|
" yysv = newyysv;",
|
||||||
|
"}"
|
||||||
|
});
|
||||||
|
writer.write("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void defineErrRec(Writer writer, int i) throws IOException {
|
||||||
|
if (errUsed) {
|
||||||
|
indent(writer, i, "public void yyerrok() {");
|
||||||
|
indent(writer, i + 1, "yyerrstatus = 3;");
|
||||||
|
if (errMsgs) {
|
||||||
|
indent(writer, i + 1, "yyerrno = (-1);");
|
||||||
|
}
|
||||||
|
indent(writer, i, "}");
|
||||||
|
writer.write("\n");
|
||||||
|
indent(writer, i, "public void yyclearin() {");
|
||||||
|
indent(writer, i + 1, "yytok = (" + settings.getNextToken());
|
||||||
|
indent(writer, i + 1, " );");
|
||||||
|
indent(writer, i, "}");
|
||||||
|
writer.write("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void defineParse(Writer writer, int i) throws IOException {
|
||||||
|
indent(writer, i, "public boolean parse() {");
|
||||||
|
indent(writer, i + 1, new String[]{
|
||||||
|
"int yyn = 0;", "yysp = 0;", "yyst = new int[yyss];"
|
||||||
|
});
|
||||||
|
if (errUsed) {
|
||||||
|
indent(writer, i + 1, "yyerrstatus = 3;");
|
||||||
|
}
|
||||||
|
if (errMsgs) {
|
||||||
|
indent(writer, i + 1, "yyerrno = (-1);");
|
||||||
|
}
|
||||||
|
indent(writer, i + 1, "yysv = new " + settings.getTypeName() + "[yyss];");
|
||||||
|
indent(writer, i + 1, "yytok = (" + settings.getGetToken());
|
||||||
|
indent(writer, i + 1, " );");
|
||||||
|
indent(writer, i, new String[]{
|
||||||
|
"loop:", " for (;;) {", " switch (yyn) {"
|
||||||
|
});
|
||||||
|
for (int j = 0; j < numStates; j++) {
|
||||||
|
stateCases(writer, i + 3, j);
|
||||||
|
}
|
||||||
|
|
||||||
|
indent(writer, i + 3, "case " + yyaccept + ":");
|
||||||
|
indent(writer, i + 4, "return true;");
|
||||||
|
indent(writer, i + 3, "case " + stackOverflow + ":");
|
||||||
|
indent(writer, i + 4, "yyerror(\"stack overflow\");");
|
||||||
|
indent(writer, i + 3, "case " + yyabort + ":");
|
||||||
|
indent(writer, i + 4, "return false;");
|
||||||
|
errorCases(writer, i + 3);
|
||||||
|
indent(writer, i, new String[]{
|
||||||
|
" }", " }", "}"
|
||||||
|
});
|
||||||
|
writer.write("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stateCases(Writer writer, int i, int j) throws IOException {
|
||||||
|
indent(writer, i, "case " + j + ":");
|
||||||
|
indent(writer, i + 1, "yyst[yysp] = " + j + ";");
|
||||||
|
if (grammar.isTerminal(machine.getEntry(j))) {
|
||||||
|
indent(writer, i + 1, "yysv[yysp] = (" + settings.getGetSemantic());
|
||||||
|
indent(writer, i + 1, " );");
|
||||||
|
indent(writer, i + 1, "yytok = (" + settings.getNextToken());
|
||||||
|
indent(writer, i + 1, " );");
|
||||||
|
if (errUsed) {
|
||||||
|
indent(writer, i + 1, "yyerrstatus++;");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
indent(writer, i + 1, new String[]{
|
||||||
|
"if (++yysp>=yyst.length) {", " yyexpand();", "}"
|
||||||
|
});
|
||||||
|
indent(writer, i, "case " + (j + numStates) + ":");
|
||||||
|
if (stNumSwitches[j] > 5) {
|
||||||
|
continueTo(writer, i + 1, "yys" + j + "()", true);
|
||||||
|
} else {
|
||||||
|
switchState(writer, i + 1, j, true);
|
||||||
|
}
|
||||||
|
writer.write("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void continueTo(Writer writer, int i, String s, boolean flag) throws IOException {
|
||||||
|
if (flag) {
|
||||||
|
indent(writer, i, "yyn = " + s + ";");
|
||||||
|
indent(writer, i, "continue;");
|
||||||
|
} else {
|
||||||
|
indent(writer, i, "return " + s + ";");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void defineState(Writer writer, int i, int j) throws IOException {
|
||||||
|
if (stNumSwitches[j] > 5) {
|
||||||
|
indent(writer, i, "private int yys" + j + "() {");
|
||||||
|
switchState(writer, i + 1, j, false);
|
||||||
|
indent(writer, i, "}");
|
||||||
|
writer.write("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void switchState(Writer writer, int i, int j, boolean flag) throws IOException {
|
||||||
|
byte[] abyte0 = tables.getActionAt(j);
|
||||||
|
int[] ai = tables.getArgAt(j);
|
||||||
|
int k = tables.getDefaultRowAt(j);
|
||||||
|
if (stNumSwitches[j] > 0) {
|
||||||
|
indent(writer, i, "switch (yytok) {");
|
||||||
|
int ai1[] = tables.indexAt(j);
|
||||||
|
int k1;
|
||||||
|
for (int l = 0; l < ai1.length; l = k1) {
|
||||||
|
int i1 = ai1[l];
|
||||||
|
byte byte0 = abyte0[i1];
|
||||||
|
int j1 = ai[i1];
|
||||||
|
k1 = l;
|
||||||
|
++k1;
|
||||||
|
while (k1 < ai1.length && abyte0[ai1[k1]] == byte0 && ai[ai1[k1]] == j1) {
|
||||||
|
k1++;
|
||||||
|
}
|
||||||
|
if (k >= 0 && byte0 == abyte0[k] && j1 == ai[k]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (int l1 = l; l1 < k1; l1++) {
|
||||||
|
indent(writer, i + 1);
|
||||||
|
writer.write("case ");
|
||||||
|
if (ai1[l1] == numTs - 1) {
|
||||||
|
writer.write("ENDINPUT");
|
||||||
|
} else {
|
||||||
|
writer.write(grammar.getTerminal(ai1[l1]).getName());
|
||||||
|
}
|
||||||
|
writer.write(":\n");
|
||||||
|
}
|
||||||
|
continueTo(writer, i + 2, codeAction(j, byte0, j1), flag);
|
||||||
|
}
|
||||||
|
indent(writer, i, "}");
|
||||||
|
}
|
||||||
|
if (k < 0) {
|
||||||
|
continueTo(writer, i, Integer.toString(errorHandler), flag);
|
||||||
|
} else {
|
||||||
|
continueTo(writer, i, codeAction(j, abyte0[k], ai[k]), flag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String codeAction(int i, int j, int k) {
|
||||||
|
if (j == 0) {
|
||||||
|
String s = Integer.toString(errorHandler);
|
||||||
|
return k != 0 ? "yyerr(" + (k - 1) + ", " + s + ")" : s;
|
||||||
|
}
|
||||||
|
if (j == 2) {
|
||||||
|
return "yyr" + machine.reduceItem(i, k).getSeqNo() + "()";
|
||||||
|
} else {
|
||||||
|
return Integer.toString(k >= 0 ? k : yyaccept);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void defineReduce(Writer writer, int i, Grammar.Prod prod, int j) throws IOException {
|
||||||
|
if ((prod instanceof JaccProd) && ntDefault[j] >= 0) {
|
||||||
|
JaccProd jaccprod = (JaccProd) prod;
|
||||||
|
indent(writer, i);
|
||||||
|
writer.write("private int yyr" + jaccprod.getSeqNo() + "() { // ");
|
||||||
|
writer.write(grammar.getSymbol(j).getName() + " : ");
|
||||||
|
writer.write(grammar.displaySymbols(jaccprod.getRhs(), "/* empty */", " ") + "\n");
|
||||||
|
String s = jaccprod.getAction();
|
||||||
|
int k = jaccprod.getRhs().length;
|
||||||
|
if (s != null) {
|
||||||
|
indent(writer, i + 1);
|
||||||
|
translateAction(writer, jaccprod, s);
|
||||||
|
indent(writer, i + 1, "yysv[yysp-=" + k + "] = yyrv;");
|
||||||
|
} else if (k > 0) {
|
||||||
|
indent(writer, i + 1, "yysp -= " + k + ";");
|
||||||
|
}
|
||||||
|
gotoNonterminal(writer, i + 1, j);
|
||||||
|
indent(writer, i, "}");
|
||||||
|
writer.write("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void translateAction(Writer writer, JaccProd jaccprod, String s) throws IOException {
|
||||||
|
int ai[] = jaccprod.getRhs();
|
||||||
|
int i = s.length();
|
||||||
|
for (int j = 0; j < i; j++) {
|
||||||
|
char c = s.charAt(j);
|
||||||
|
if (c == '$') {
|
||||||
|
c = s.charAt(j + 1);
|
||||||
|
if (c == '$') {
|
||||||
|
j++;
|
||||||
|
writer.write("yyrv");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (Character.isDigit(c)) {
|
||||||
|
int k = 0;
|
||||||
|
do {
|
||||||
|
k = k * 10 + Character.digit(c, 10);
|
||||||
|
j++;
|
||||||
|
c = s.charAt(j + 1);
|
||||||
|
} while (Character.isDigit(c));
|
||||||
|
if (k < 1 || k > ai.length) {
|
||||||
|
report(new Failure(jaccprod.getActionPos(), "$" + k + " cannot be used in this action."));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int l = (1 + ai.length) - k;
|
||||||
|
String s1 = null;
|
||||||
|
if (grammar.getSymbol(ai[k - 1]) instanceof JaccSymbol) {
|
||||||
|
JaccSymbol jaccsymbol = (JaccSymbol) grammar.getSymbol(ai[k - 1]);
|
||||||
|
s1 = jaccsymbol.getType();
|
||||||
|
}
|
||||||
|
if (s1 != null) {
|
||||||
|
writer.write("((" + s1 + ")");
|
||||||
|
}
|
||||||
|
writer.write("yysv[yysp-" + l + "]");
|
||||||
|
if (s1 != null) {
|
||||||
|
writer.write(")");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
writer.write('$');
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (c == '\n') {
|
||||||
|
writer.write("\n");
|
||||||
|
} else {
|
||||||
|
writer.write(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writer.write("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void gotoNonterminal(Writer writer, int i, int j) throws IOException {
|
||||||
|
if (ntDefault[j] < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ntDistinct[j] == 1) {
|
||||||
|
indent(writer, i, "return " + ntGoto[j][0] + ";");
|
||||||
|
} else {
|
||||||
|
if (grammar.getProds(j).length == 1) {
|
||||||
|
nonterminalSwitch(writer, i, j);
|
||||||
|
} else {
|
||||||
|
indent(writer, i, "return " + ntName(j) + "();");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void defineNonterminal(Writer writer, int i, int j) throws IOException {
|
||||||
|
if (ntDefault[j] >= 0 && ntDistinct[j] != 1 && grammar.getProds(j).length != 1) {
|
||||||
|
indent(writer, i, "private int " + ntName(j) + "() {");
|
||||||
|
nonterminalSwitch(writer, i + 1, j);
|
||||||
|
indent(writer, i, "}");
|
||||||
|
writer.write("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void nonterminalSwitch(Writer writer, int i, int j) throws IOException {
|
||||||
|
int k = ntGoto[j][ntDefault[j]];
|
||||||
|
indent(writer, i);
|
||||||
|
writer.write("switch (yyst[yysp-1]) {\n");
|
||||||
|
for (int l = 0; l < ntGoto[j].length; l++) {
|
||||||
|
int i1 = ntGoto[j][l];
|
||||||
|
if (i1 != k) {
|
||||||
|
indent(writer, i + 1);
|
||||||
|
writer.write("case " + ntGotoSrc[j][l]);
|
||||||
|
writer.write(": return " + i1 + ";\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
indent(writer, i + 1);
|
||||||
|
writer.write("default: return " + k + ";\n");
|
||||||
|
indent(writer, i);
|
||||||
|
writer.write("}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
private String ntName(int i) {
|
||||||
|
return "yyp" + grammar.getSymbol(i).getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void errorCases(Writer writer, int i) throws IOException {
|
||||||
|
indent(writer, i, "case " + errorHandler + ":");
|
||||||
|
if (!errUsed) {
|
||||||
|
indent(writer, i + 1, new String[]{
|
||||||
|
"yyerror(\"syntax error\");", "return false;"
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
indent(writer, i + 1, new String[]{
|
||||||
|
"if (yyerrstatus>2) {", " yyerror(\"syntax error\");", "}"
|
||||||
|
});
|
||||||
|
indent(writer, i, "case " + userErrorHandler + " :");
|
||||||
|
indent(writer, i + 1, new String[]{
|
||||||
|
"if (yyerrstatus==0) {",
|
||||||
|
" if ((" + settings.getGetToken(),
|
||||||
|
" )==ENDINPUT) {",
|
||||||
|
" return false;",
|
||||||
|
" }",
|
||||||
|
" " + settings.getNextToken(),
|
||||||
|
" ;"
|
||||||
|
});
|
||||||
|
indent(writer, i + 2, "yyn = " + numStates + " + yyst[yysp-1];");
|
||||||
|
indent(writer, i + 1, new String[]{
|
||||||
|
" continue;",
|
||||||
|
"} else {",
|
||||||
|
" yyerrstatus = 0;",
|
||||||
|
" while (yysp>0) {",
|
||||||
|
" switch(yyst[yysp-1]) {"
|
||||||
|
});
|
||||||
|
for (int j = 0; j < numStates; j++) {
|
||||||
|
int[] ai = machine.getShiftsAt(j);
|
||||||
|
for (int anAi : ai) {
|
||||||
|
if (machine.getEntry(anAi) == errTok) {
|
||||||
|
indent(writer, i + 4, "case " + j + ":");
|
||||||
|
indent(writer, i + 5, "yyn = " + anAi + ";");
|
||||||
|
indent(writer, i + 5, "continue loop;");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
indent(writer, i + 1, new String[]{
|
||||||
|
" }", " yysp--;", " }", " return false;", "}"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
174
src/main/java/org/xbib/jacc/Settings.java
Normal file
174
src/main/java/org/xbib/jacc/Settings.java
Normal file
|
@ -0,0 +1,174 @@
|
||||||
|
package org.xbib.jacc;
|
||||||
|
|
||||||
|
import org.xbib.jacc.grammar.Grammar;
|
||||||
|
import org.xbib.jacc.grammar.LALRMachine;
|
||||||
|
import org.xbib.jacc.grammar.LR0Machine;
|
||||||
|
import org.xbib.jacc.grammar.LookaheadMachine;
|
||||||
|
import org.xbib.jacc.grammar.SLRMachine;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class Settings {
|
||||||
|
|
||||||
|
private static final int LR0 = 0;
|
||||||
|
private static final int SLR1 = 1;
|
||||||
|
private static final int LALR1 = 2;
|
||||||
|
private int machineType;
|
||||||
|
private String packageName;
|
||||||
|
private String className;
|
||||||
|
private String interfaceName;
|
||||||
|
private String extendsName;
|
||||||
|
private String implementsNames;
|
||||||
|
private String typeName;
|
||||||
|
private String getToken;
|
||||||
|
private String nextToken;
|
||||||
|
private String getSemantic;
|
||||||
|
private StringBuilder preTextBuffer;
|
||||||
|
private StringBuilder postTextBuffer;
|
||||||
|
|
||||||
|
Settings() {
|
||||||
|
machineType = LALR1;
|
||||||
|
preTextBuffer = new StringBuilder();
|
||||||
|
postTextBuffer = new StringBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMachineType() {
|
||||||
|
return machineType;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setMachineType(int i) {
|
||||||
|
machineType = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
LookaheadMachine makeMachine(Grammar grammar) {
|
||||||
|
if (machineType == LR0) {
|
||||||
|
return new LR0Machine(grammar);
|
||||||
|
}
|
||||||
|
if (machineType == SLR1) {
|
||||||
|
return new SLRMachine(grammar);
|
||||||
|
} else {
|
||||||
|
return new LALRMachine(grammar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String getPackageName() {
|
||||||
|
return packageName;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPackageName(String s) {
|
||||||
|
packageName = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getClassName() {
|
||||||
|
return className;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setClassName(String s) {
|
||||||
|
className = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getInterfaceName() {
|
||||||
|
return interfaceName;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setInterfaceName(String s) {
|
||||||
|
interfaceName = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getExtendsName() {
|
||||||
|
return extendsName;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setExtendsName(String s) {
|
||||||
|
extendsName = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addImplementsNames(String s) {
|
||||||
|
if (implementsNames != null) {
|
||||||
|
implementsNames += ", " + s;
|
||||||
|
} else {
|
||||||
|
implementsNames = s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String getImplementsNames() {
|
||||||
|
return implementsNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setImplementsNames(String s) {
|
||||||
|
implementsNames = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getTypeName() {
|
||||||
|
return typeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setTypeName(String s) {
|
||||||
|
typeName = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getGetToken() {
|
||||||
|
return getToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setGetToken(String s) {
|
||||||
|
getToken = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getNextToken() {
|
||||||
|
return nextToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setNextToken(String s) {
|
||||||
|
nextToken = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getGetSemantic() {
|
||||||
|
return getSemantic;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setGetSemantic(String s) {
|
||||||
|
getSemantic = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addPreText(String s) {
|
||||||
|
preTextBuffer.append(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
String getPreText() {
|
||||||
|
return preTextBuffer.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void addPostText(String s) {
|
||||||
|
postTextBuffer.append(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
String getPostText() {
|
||||||
|
return postTextBuffer.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void fillBlanks(String s) {
|
||||||
|
if (getClassName() == null) {
|
||||||
|
setClassName(s + "Parser");
|
||||||
|
}
|
||||||
|
if (getInterfaceName() == null) {
|
||||||
|
setInterfaceName(s + "Tokens");
|
||||||
|
}
|
||||||
|
if (getTypeName() == null) {
|
||||||
|
setTypeName("Object");
|
||||||
|
}
|
||||||
|
if (getInterfaceName() != null) {
|
||||||
|
addImplementsNames(getInterfaceName());
|
||||||
|
}
|
||||||
|
if (getGetSemantic() == null) {
|
||||||
|
setGetSemantic("lexer.getSemantic()");
|
||||||
|
}
|
||||||
|
if (getGetToken() == null) {
|
||||||
|
setGetToken("lexer.getToken()");
|
||||||
|
}
|
||||||
|
if (getNextToken() == null) {
|
||||||
|
setNextToken("lexer.nextToken()");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
128
src/main/java/org/xbib/jacc/TextOutput.java
Normal file
128
src/main/java/org/xbib/jacc/TextOutput.java
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
package org.xbib.jacc;
|
||||||
|
|
||||||
|
import org.xbib.jacc.compiler.Handler;
|
||||||
|
import org.xbib.jacc.util.IntSet;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Writer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class TextOutput extends Output {
|
||||||
|
|
||||||
|
private boolean wantFirst;
|
||||||
|
|
||||||
|
TextOutput(Handler handler, JaccJob jaccjob, boolean flag) {
|
||||||
|
super(handler, jaccjob);
|
||||||
|
wantFirst = false;
|
||||||
|
wantFirst = flag;
|
||||||
|
tables.analyzeRows();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void write(Writer writer) throws IOException {
|
||||||
|
datestamp(writer);
|
||||||
|
for (int i = 0; i < numStates; i++) {
|
||||||
|
writer.write(resolver.getConflictsAt(i));
|
||||||
|
writer.write(describeEntry(i) + "\n");
|
||||||
|
IntSet intset = machine.getItemsAt(i);
|
||||||
|
int k = intset.size();
|
||||||
|
for (int i1 = 0; i1 < k; i1++) {
|
||||||
|
indent(writer, 1);
|
||||||
|
machine.getItems().getItem(intset.at(i1)).display(writer);
|
||||||
|
writer.write("\n");
|
||||||
|
}
|
||||||
|
writer.write("\n");
|
||||||
|
byte abyte0[] = tables.getActionAt(i);
|
||||||
|
int ai1[] = tables.getArgAt(i);
|
||||||
|
int j1 = tables.getDefaultRowAt(i);
|
||||||
|
int ai2[] = tables.indexAt(i);
|
||||||
|
for (int k1 = 0; k1 < abyte0.length; k1++) {
|
||||||
|
int l1 = ai2[k1];
|
||||||
|
if (j1 < 0 || abyte0[l1] != abyte0[j1] || ai1[l1] != ai1[j1]) {
|
||||||
|
indent(writer, 1);
|
||||||
|
writer.write(grammar.getTerminal(l1).getName());
|
||||||
|
writer.write(' ');
|
||||||
|
writer.write(describeAction(i, abyte0[l1], ai1[l1]) + "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
indent(writer, 1);
|
||||||
|
if (j1 < 0) {
|
||||||
|
writer.write(". error" + "\n");
|
||||||
|
} else {
|
||||||
|
writer.write(". ");
|
||||||
|
writer.write(describeAction(i, abyte0[j1], ai1[j1]) + "\n");
|
||||||
|
}
|
||||||
|
writer.write("\n");
|
||||||
|
int ai3[] = machine.getGotosAt(i);
|
||||||
|
if (ai3.length <= 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (int anAi3 : ai3) {
|
||||||
|
int j2 = machine.getEntry(anAi3);
|
||||||
|
indent(writer, 1);
|
||||||
|
writer.write(grammar.getSymbol(j2).getName());
|
||||||
|
writer.write(" " + describeGoto(anAi3) + "\n");
|
||||||
|
}
|
||||||
|
writer.write("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wantFirst) {
|
||||||
|
grammar.getFirst().display(writer);
|
||||||
|
writer.write("\n");
|
||||||
|
grammar.getFollow().display(writer);
|
||||||
|
writer.write("\n");
|
||||||
|
grammar.getNullable().display(writer);
|
||||||
|
writer.write("\n");
|
||||||
|
}
|
||||||
|
if (tables.getProdUnused() > 0) {
|
||||||
|
for (int j = 0; j < numNTs; j++) {
|
||||||
|
boolean aflag[] = tables.getProdsUsedAt(j);
|
||||||
|
for (int l = 0; l < aflag.length; l++) {
|
||||||
|
if (!aflag[l]) {
|
||||||
|
int ai[] = grammar.getProds(j)[l].getRhs();
|
||||||
|
writer.write("Rule not reduced: ");
|
||||||
|
writer.write(grammar.getNonterminal(j).getName());
|
||||||
|
writer.write(" : ");
|
||||||
|
writer.write(grammar.displaySymbols(ai, "", " ") + "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writer.write("\n");
|
||||||
|
}
|
||||||
|
writer.write(numTs + " terminals, " + numNTs + " nonterminals;");
|
||||||
|
writer.write(grammar.getNumProds() + " grammar rules, " + numStates + " states;");
|
||||||
|
writer.write(resolver.getNumSRConflicts() + " shift/reduce and " +
|
||||||
|
resolver.getNumRRConflicts() + " reduce/reduce conflicts reported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private String describeEntry(int i) {
|
||||||
|
return "state " + i + " (entry on " + grammar.getSymbol(machine.getEntry(i)) + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
private String describeAction(int i, int j, int k) {
|
||||||
|
if (j == 0) {
|
||||||
|
if (k == 0) {
|
||||||
|
return "error";
|
||||||
|
} else {
|
||||||
|
return "error \"" + tables.getError(k - 1) + "\"";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (j == 2) {
|
||||||
|
return "reduce " + machine.reduceItem(i, k).getSeqNo();
|
||||||
|
}
|
||||||
|
if (k < 0) {
|
||||||
|
return "accept";
|
||||||
|
} else {
|
||||||
|
return describeShift(k);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String describeShift(int i) {
|
||||||
|
return "shift " + i;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String describeGoto(int i) {
|
||||||
|
return "goto " + i;
|
||||||
|
}
|
||||||
|
}
|
44
src/main/java/org/xbib/jacc/TokensOutput.java
Normal file
44
src/main/java/org/xbib/jacc/TokensOutput.java
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
package org.xbib.jacc;
|
||||||
|
|
||||||
|
import org.xbib.jacc.compiler.Handler;
|
||||||
|
import org.xbib.jacc.grammar.Grammar;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Writer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class TokensOutput extends Output {
|
||||||
|
|
||||||
|
TokensOutput(Handler handler, JaccJob jaccjob) {
|
||||||
|
super(handler, jaccjob);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(Writer writer) throws IOException {
|
||||||
|
datestamp(writer);
|
||||||
|
String s = settings.getPackageName();
|
||||||
|
if (s != null) {
|
||||||
|
writer.write("package " + s + ";\n\n");
|
||||||
|
}
|
||||||
|
writer.write("interface " + settings.getInterfaceName() + " {\n");
|
||||||
|
indent(writer, 1);
|
||||||
|
writer.write("int ENDINPUT = 0;\n");
|
||||||
|
for (int i = 0; i < numTs - 1; i++) {
|
||||||
|
Grammar.Symbol symbol = grammar.getTerminal(i);
|
||||||
|
if (!(symbol instanceof JaccSymbol)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
JaccSymbol jaccsymbol = (JaccSymbol) symbol;
|
||||||
|
String s1 = jaccsymbol.getName();
|
||||||
|
indent(writer, 1);
|
||||||
|
if (s1.startsWith("'")) {
|
||||||
|
writer.write("// " + s1 + " (code=" + jaccsymbol.getNum() + ")\n");
|
||||||
|
} else {
|
||||||
|
writer.write("int " + s1 + " = " + jaccsymbol.getNum() + ";\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writer.write("}\n");
|
||||||
|
}
|
||||||
|
}
|
23
src/main/java/org/xbib/jacc/compiler/ConsoleHandler.java
Normal file
23
src/main/java/org/xbib/jacc/compiler/ConsoleHandler.java
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
package org.xbib.jacc.compiler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ConsoleHandler extends Handler {
|
||||||
|
protected void respondTo(Diagnostic diagnostic) {
|
||||||
|
Position position = diagnostic.getPos();
|
||||||
|
if (diagnostic instanceof Warning) {
|
||||||
|
System.err.print("WARNING: ");
|
||||||
|
} else {
|
||||||
|
System.err.print("ERROR: ");
|
||||||
|
}
|
||||||
|
if (position != null) {
|
||||||
|
System.err.println(position.describe());
|
||||||
|
}
|
||||||
|
String s = diagnostic.getText();
|
||||||
|
if (s != null) {
|
||||||
|
System.err.println(s);
|
||||||
|
}
|
||||||
|
System.err.println();
|
||||||
|
}
|
||||||
|
}
|
27
src/main/java/org/xbib/jacc/compiler/Diagnostic.java
Normal file
27
src/main/java/org/xbib/jacc/compiler/Diagnostic.java
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
package org.xbib.jacc.compiler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
abstract class Diagnostic extends Exception {
|
||||||
|
|
||||||
|
private String text;
|
||||||
|
private Position position;
|
||||||
|
|
||||||
|
Diagnostic(String s) {
|
||||||
|
text = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
Diagnostic(Position position, String s) {
|
||||||
|
this.position = position;
|
||||||
|
text = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getText() {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
Position getPos() {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
}
|
15
src/main/java/org/xbib/jacc/compiler/Failure.java
Normal file
15
src/main/java/org/xbib/jacc/compiler/Failure.java
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
package org.xbib.jacc.compiler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class Failure extends Diagnostic {
|
||||||
|
|
||||||
|
public Failure(String s) {
|
||||||
|
super(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Failure(Position position, String s) {
|
||||||
|
super(position, s);
|
||||||
|
}
|
||||||
|
}
|
27
src/main/java/org/xbib/jacc/compiler/Handler.java
Normal file
27
src/main/java/org/xbib/jacc/compiler/Handler.java
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
package org.xbib.jacc.compiler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public abstract class Handler {
|
||||||
|
|
||||||
|
private int numFailures;
|
||||||
|
|
||||||
|
public Handler() {
|
||||||
|
numFailures = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumFailures() {
|
||||||
|
return numFailures;
|
||||||
|
}
|
||||||
|
|
||||||
|
void report(Diagnostic diagnostic) {
|
||||||
|
if (diagnostic instanceof Failure) {
|
||||||
|
numFailures++;
|
||||||
|
}
|
||||||
|
respondTo(diagnostic);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void respondTo(Diagnostic diagnostic);
|
||||||
|
|
||||||
|
}
|
121
src/main/java/org/xbib/jacc/compiler/JavaSource.java
Normal file
121
src/main/java/org/xbib/jacc/compiler/JavaSource.java
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
package org.xbib.jacc.compiler;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Reader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class JavaSource extends Source {
|
||||||
|
|
||||||
|
private final StringBuilder buf;
|
||||||
|
private Reader input;
|
||||||
|
private int tabwidth;
|
||||||
|
private String description;
|
||||||
|
private int c0;
|
||||||
|
private int c1;
|
||||||
|
private int lineNumber;
|
||||||
|
|
||||||
|
public JavaSource(Handler handler, String s, Reader reader) {
|
||||||
|
this(handler, s, reader, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
private JavaSource(Handler handler, String s, Reader reader, int i) {
|
||||||
|
super(handler);
|
||||||
|
c1 = 0;
|
||||||
|
lineNumber = 0;
|
||||||
|
description = s;
|
||||||
|
input = reader;
|
||||||
|
tabwidth = i;
|
||||||
|
buf = new StringBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String describe() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void skip() throws IOException {
|
||||||
|
c0 = c1;
|
||||||
|
if (c0 != -1) {
|
||||||
|
c1 = input.read();
|
||||||
|
if (c0 == 26 && c1 == -1) {
|
||||||
|
c0 = c1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String readLine() throws IOException {
|
||||||
|
if (input == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
buf.setLength(0);
|
||||||
|
if (lineNumber++ == 0) {
|
||||||
|
skip();
|
||||||
|
skip();
|
||||||
|
}
|
||||||
|
if (c0 == -1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
if (c0 == -1 || c0 == 10 || c0 == 13) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (c0 == 92) {
|
||||||
|
skip();
|
||||||
|
if (c0 == 117) {
|
||||||
|
do {
|
||||||
|
skip();
|
||||||
|
} while (c0 == 117);
|
||||||
|
int i = 0;
|
||||||
|
int k = 0;
|
||||||
|
for (int l; k < 4 && c0 != -1 && (l = Character.digit((char) c0, 16)) >= 0; ) {
|
||||||
|
i = (i << 4) + l;
|
||||||
|
k++;
|
||||||
|
skip();
|
||||||
|
}
|
||||||
|
if (k != 4) {
|
||||||
|
report(new Warning("Error in Unicode escape sequence"));
|
||||||
|
} else {
|
||||||
|
buf.append((char) i);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
buf.append('\\');
|
||||||
|
if (c0 == -1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
buf.append((char) c0);
|
||||||
|
skip();
|
||||||
|
} else if (c0 == 9 && tabwidth > 0) {
|
||||||
|
for (int j = tabwidth - buf.length() % tabwidth; j > 0; j--) {
|
||||||
|
buf.append(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
skip();
|
||||||
|
} else {
|
||||||
|
buf.append((char) c0);
|
||||||
|
skip();
|
||||||
|
}
|
||||||
|
} while (true);
|
||||||
|
if (c0 == 13) {
|
||||||
|
skip();
|
||||||
|
}
|
||||||
|
if (c0 == 10) {
|
||||||
|
skip();
|
||||||
|
}
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getLineNo() {
|
||||||
|
return lineNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() throws IOException {
|
||||||
|
if (input != null) {
|
||||||
|
input.close();
|
||||||
|
input = null;
|
||||||
|
buf.setLength(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
40
src/main/java/org/xbib/jacc/compiler/Lexer.java
Normal file
40
src/main/java/org/xbib/jacc/compiler/Lexer.java
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
package org.xbib.jacc.compiler;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public abstract class Lexer extends Phase {
|
||||||
|
|
||||||
|
protected int token;
|
||||||
|
|
||||||
|
protected String lexemeText;
|
||||||
|
|
||||||
|
Lexer(Handler handler) {
|
||||||
|
super(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract int nextToken() throws IOException;
|
||||||
|
|
||||||
|
public int getToken() {
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLexeme() {
|
||||||
|
return lexemeText;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract Position getPos();
|
||||||
|
|
||||||
|
public boolean match(int i) throws IOException {
|
||||||
|
if (i == token) {
|
||||||
|
nextToken();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void close() throws IOException;
|
||||||
|
}
|
23
src/main/java/org/xbib/jacc/compiler/Phase.java
Normal file
23
src/main/java/org/xbib/jacc/compiler/Phase.java
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
package org.xbib.jacc.compiler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public abstract class Phase {
|
||||||
|
|
||||||
|
private final Handler handler;
|
||||||
|
|
||||||
|
protected Phase(Handler handler) {
|
||||||
|
this.handler = handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Handler getHandler() {
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void report(Diagnostic diagnostic) {
|
||||||
|
if (handler != null) {
|
||||||
|
handler.report(diagnostic);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
src/main/java/org/xbib/jacc/compiler/Position.java
Normal file
11
src/main/java/org/xbib/jacc/compiler/Position.java
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
package org.xbib.jacc.compiler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public abstract class Position {
|
||||||
|
|
||||||
|
public abstract String describe();
|
||||||
|
|
||||||
|
public abstract Position copy();
|
||||||
|
}
|
26
src/main/java/org/xbib/jacc/compiler/Source.java
Normal file
26
src/main/java/org/xbib/jacc/compiler/Source.java
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
package org.xbib.jacc.compiler;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public abstract class Source extends Phase {
|
||||||
|
|
||||||
|
Source(Handler handler) {
|
||||||
|
super(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract String describe();
|
||||||
|
|
||||||
|
public abstract String readLine() throws IOException;
|
||||||
|
|
||||||
|
public abstract int getLineNo();
|
||||||
|
|
||||||
|
String getLine(int i) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() throws IOException {
|
||||||
|
}
|
||||||
|
}
|
59
src/main/java/org/xbib/jacc/compiler/SourceLexer.java
Normal file
59
src/main/java/org/xbib/jacc/compiler/SourceLexer.java
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
package org.xbib.jacc.compiler;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public abstract class SourceLexer extends Lexer {
|
||||||
|
|
||||||
|
protected String line;
|
||||||
|
protected int col;
|
||||||
|
protected int c;
|
||||||
|
private Source source;
|
||||||
|
private SourcePosition pos;
|
||||||
|
|
||||||
|
public SourceLexer(Handler handler, Source source) throws IOException {
|
||||||
|
super(handler);
|
||||||
|
col = -1;
|
||||||
|
this.source = source;
|
||||||
|
pos = new SourcePosition(source);
|
||||||
|
line = source.readLine();
|
||||||
|
nextChar();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Position getPos() {
|
||||||
|
return pos.copy();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void markPosition() {
|
||||||
|
pos.updateCoords(source.getLineNo(), col);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void nextLine() throws IOException {
|
||||||
|
line = source.readLine();
|
||||||
|
col = -1;
|
||||||
|
nextChar();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int nextChar() {
|
||||||
|
if (line == null) {
|
||||||
|
c = -1;
|
||||||
|
col = 0;
|
||||||
|
} else {
|
||||||
|
if (++col >= line.length()) {
|
||||||
|
c = 10;
|
||||||
|
} else {
|
||||||
|
c = line.charAt(col);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() throws IOException {
|
||||||
|
if (source != null) {
|
||||||
|
source.close();
|
||||||
|
source = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
61
src/main/java/org/xbib/jacc/compiler/SourcePosition.java
Normal file
61
src/main/java/org/xbib/jacc/compiler/SourcePosition.java
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
package org.xbib.jacc.compiler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class SourcePosition extends Position {
|
||||||
|
|
||||||
|
private final Source source;
|
||||||
|
|
||||||
|
private int row;
|
||||||
|
|
||||||
|
private int column;
|
||||||
|
|
||||||
|
SourcePosition(Source source) {
|
||||||
|
this(source, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private SourcePosition(Source source, int i, int j) {
|
||||||
|
this.source = source;
|
||||||
|
row = i;
|
||||||
|
column = j;
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateCoords(int i, int j) {
|
||||||
|
row = i;
|
||||||
|
column = j;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String describe() {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
if (source != null) {
|
||||||
|
sb.append('"');
|
||||||
|
sb.append(source.describe());
|
||||||
|
sb.append('"');
|
||||||
|
if (row > 0) {
|
||||||
|
sb.append(", ");
|
||||||
|
}
|
||||||
|
if (row > 0) {
|
||||||
|
sb.append("line ");
|
||||||
|
sb.append(row);
|
||||||
|
}
|
||||||
|
String s = source.getLine(row);
|
||||||
|
if (s != null) {
|
||||||
|
sb.append('\n');
|
||||||
|
sb.append(s);
|
||||||
|
sb.append('\n');
|
||||||
|
for (int i = 0; i < column; i++) {
|
||||||
|
sb.append(' ');
|
||||||
|
}
|
||||||
|
sb.append('^');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb.length() > 0 ? sb.toString() : "input";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Position copy() {
|
||||||
|
return new SourcePosition(source, row, column);
|
||||||
|
}
|
||||||
|
}
|
15
src/main/java/org/xbib/jacc/compiler/Warning.java
Normal file
15
src/main/java/org/xbib/jacc/compiler/Warning.java
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
package org.xbib.jacc.compiler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class Warning extends Diagnostic {
|
||||||
|
|
||||||
|
public Warning(String s) {
|
||||||
|
super(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Warning(Position position, String s) {
|
||||||
|
super(position, s);
|
||||||
|
}
|
||||||
|
}
|
4
src/main/java/org/xbib/jacc/compiler/package-info.java
Normal file
4
src/main/java/org/xbib/jacc/compiler/package-info.java
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
/**
|
||||||
|
* CLasses for compiler construction.
|
||||||
|
*/
|
||||||
|
package org.xbib.jacc.compiler;
|
38
src/main/java/org/xbib/jacc/grammar/Analysis.java
Normal file
38
src/main/java/org/xbib/jacc/grammar/Analysis.java
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
package org.xbib.jacc.grammar;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
abstract class Analysis {
|
||||||
|
|
||||||
|
private int[][] comps;
|
||||||
|
|
||||||
|
Analysis(int[][] ai) {
|
||||||
|
comps = ai;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bottomUp() {
|
||||||
|
for (int[] comp : comps) {
|
||||||
|
analyzeComponent(comp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void topDown() {
|
||||||
|
for (int i = comps.length; i-- > 0; ) {
|
||||||
|
analyzeComponent(comps[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void analyzeComponent(int ai[]) {
|
||||||
|
for (boolean flag = true; flag; ) {
|
||||||
|
flag = false;
|
||||||
|
int i = 0;
|
||||||
|
while (i < ai.length) {
|
||||||
|
flag |= analyze(ai[i]);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract boolean analyze(int i);
|
||||||
|
}
|
77
src/main/java/org/xbib/jacc/grammar/Finitary.java
Normal file
77
src/main/java/org/xbib/jacc/grammar/Finitary.java
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
package org.xbib.jacc.grammar;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Writer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public final class Finitary extends Analysis {
|
||||||
|
|
||||||
|
private boolean[] finitary;
|
||||||
|
private boolean[] consider;
|
||||||
|
private Grammar grammar;
|
||||||
|
private int numNTs;
|
||||||
|
|
||||||
|
Finitary(Grammar grammar) {
|
||||||
|
super(grammar.getComponents());
|
||||||
|
this.grammar = grammar;
|
||||||
|
numNTs = grammar.getNumNTs();
|
||||||
|
finitary = new boolean[numNTs];
|
||||||
|
consider = new boolean[numNTs];
|
||||||
|
for (int i = 0; i < numNTs; i++) {
|
||||||
|
finitary[i] = false;
|
||||||
|
consider[i] = true;
|
||||||
|
}
|
||||||
|
bottomUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean analyze(int i) {
|
||||||
|
boolean flag = false;
|
||||||
|
if (consider[i]) {
|
||||||
|
int j = 0;
|
||||||
|
Grammar.Prod[] aprod = grammar.getProds(i);
|
||||||
|
for (Grammar.Prod anAprod : aprod) {
|
||||||
|
int ai[] = anAprod.getRhs();
|
||||||
|
int l;
|
||||||
|
l = 0;
|
||||||
|
while (l < ai.length && at(ai[l])) {
|
||||||
|
l++;
|
||||||
|
}
|
||||||
|
if (l >= ai.length) {
|
||||||
|
finitary[i] = true;
|
||||||
|
consider[i] = false;
|
||||||
|
flag = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!consider[ai[l]]) {
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (j == aprod.length) {
|
||||||
|
consider[i] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean at(int i) {
|
||||||
|
return grammar.isTerminal(i) || finitary[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void display(Writer writer) throws IOException {
|
||||||
|
writer.write("Finitary = {");
|
||||||
|
int i = 0;
|
||||||
|
for (int j = 0; j < numNTs; j++) {
|
||||||
|
if (!at(j)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (i > 0) {
|
||||||
|
writer.write(", ");
|
||||||
|
}
|
||||||
|
writer.write(grammar.getSymbol(j).getName());
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
writer.write("}\n");
|
||||||
|
}
|
||||||
|
}
|
73
src/main/java/org/xbib/jacc/grammar/First.java
Normal file
73
src/main/java/org/xbib/jacc/grammar/First.java
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
package org.xbib.jacc.grammar;
|
||||||
|
|
||||||
|
import org.xbib.jacc.util.BitSet;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Writer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class First extends Analysis {
|
||||||
|
|
||||||
|
private Grammar grammar;
|
||||||
|
private Nullable nullable;
|
||||||
|
private int numNTs;
|
||||||
|
private int[][] first;
|
||||||
|
|
||||||
|
First(Grammar grammar1, Nullable nullable1) {
|
||||||
|
super(grammar1.getComponents());
|
||||||
|
grammar = grammar1;
|
||||||
|
nullable = nullable1;
|
||||||
|
numNTs = grammar1.getNumNTs();
|
||||||
|
int numTs = grammar1.getNumTs();
|
||||||
|
first = new int[numNTs][];
|
||||||
|
for (int i = 0; i < numNTs; i++) {
|
||||||
|
first[i] = BitSet.make(numTs);
|
||||||
|
}
|
||||||
|
bottomUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean analyze(int i) {
|
||||||
|
boolean flag = false;
|
||||||
|
Grammar.Prod[] aprod = grammar.getProds(i);
|
||||||
|
label0:
|
||||||
|
for (Grammar.Prod anAprod : aprod) {
|
||||||
|
int[] ai = anAprod.getRhs();
|
||||||
|
int k = 0;
|
||||||
|
do {
|
||||||
|
if (k >= ai.length) {
|
||||||
|
continue label0;
|
||||||
|
}
|
||||||
|
if (grammar.isTerminal(ai[k])) {
|
||||||
|
if (BitSet.addTo(first[i], ai[k] - numNTs)) {
|
||||||
|
flag = true;
|
||||||
|
}
|
||||||
|
continue label0;
|
||||||
|
}
|
||||||
|
if (BitSet.addTo(first[i], first[ai[k]])) {
|
||||||
|
flag = true;
|
||||||
|
}
|
||||||
|
if (!nullable.at(ai[k])) {
|
||||||
|
continue label0;
|
||||||
|
}
|
||||||
|
k++;
|
||||||
|
} while (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] at(int i) {
|
||||||
|
return first[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void display(Writer writer) throws IOException {
|
||||||
|
writer.write("First sets:\n");
|
||||||
|
for (int i = 0; i < first.length; i++) {
|
||||||
|
writer.write(" First(" + grammar.getSymbol(i) + "): {");
|
||||||
|
writer.write(grammar.displaySymbolSet(at(i), numNTs));
|
||||||
|
writer.write("}\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
83
src/main/java/org/xbib/jacc/grammar/Follow.java
Normal file
83
src/main/java/org/xbib/jacc/grammar/Follow.java
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
package org.xbib.jacc.grammar;
|
||||||
|
|
||||||
|
import org.xbib.jacc.util.BitSet;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Writer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class Follow extends Analysis {
|
||||||
|
|
||||||
|
private Grammar grammar;
|
||||||
|
private Nullable nullable;
|
||||||
|
private First first;
|
||||||
|
private int numNTs;
|
||||||
|
private int[][] follow;
|
||||||
|
|
||||||
|
Follow(Grammar grammar, Nullable nullable, First first1) {
|
||||||
|
super(grammar.getComponents());
|
||||||
|
this.grammar = grammar;
|
||||||
|
this.nullable = nullable;
|
||||||
|
first = first1;
|
||||||
|
numNTs = grammar.getNumNTs();
|
||||||
|
int numTs = grammar.getNumTs();
|
||||||
|
follow = new int[numNTs][];
|
||||||
|
for (int i = 0; i < numNTs; i++) {
|
||||||
|
follow[i] = BitSet.make(numTs);
|
||||||
|
}
|
||||||
|
BitSet.set(follow[0], numTs - 1);
|
||||||
|
topDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean analyze(int i) {
|
||||||
|
boolean flag = false;
|
||||||
|
Grammar.Prod aprod[] = grammar.getProds(i);
|
||||||
|
for (Grammar.Prod anAprod : aprod) {
|
||||||
|
int[] ai = anAprod.getRhs();
|
||||||
|
for (int k = 0; k < ai.length; k++) {
|
||||||
|
if (!grammar.isNonterminal(ai[k])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int l = k + 1;
|
||||||
|
do {
|
||||||
|
if (l >= ai.length) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (grammar.isTerminal(ai[l])) {
|
||||||
|
if (BitSet.addTo(follow[ai[k]], ai[l] - numNTs)) {
|
||||||
|
flag = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (BitSet.addTo(follow[ai[k]], first.at(ai[l]))) {
|
||||||
|
flag = true;
|
||||||
|
}
|
||||||
|
if (!nullable.at(ai[l])) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
l++;
|
||||||
|
} while (true);
|
||||||
|
if (l >= ai.length && BitSet.addTo(follow[ai[k]], follow[i])) {
|
||||||
|
flag = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] at(int i) {
|
||||||
|
return follow[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void display(Writer writer) throws IOException {
|
||||||
|
writer.write("Follow sets:\n");
|
||||||
|
for (int i = 0; i < follow.length; i++) {
|
||||||
|
writer.write(" Follow(" + grammar.getSymbol(i) + "): {");
|
||||||
|
writer.write(grammar.displaySymbolSet(at(i), numNTs));
|
||||||
|
writer.write("}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
282
src/main/java/org/xbib/jacc/grammar/Grammar.java
Normal file
282
src/main/java/org/xbib/jacc/grammar/Grammar.java
Normal file
|
@ -0,0 +1,282 @@
|
||||||
|
package org.xbib.jacc.grammar;
|
||||||
|
|
||||||
|
import org.xbib.jacc.util.BitSet;
|
||||||
|
import org.xbib.jacc.util.Interator;
|
||||||
|
import org.xbib.jacc.util.SCC;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Writer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class Grammar {
|
||||||
|
private final Symbol[] symbols;
|
||||||
|
private final Prod[][] prods;
|
||||||
|
private int numSyms;
|
||||||
|
private int numNTs;
|
||||||
|
private int numTs;
|
||||||
|
private int[][] comps;
|
||||||
|
private int[][] depends;
|
||||||
|
private int[][] revdeps;
|
||||||
|
private Nullable nullable;
|
||||||
|
private Finitary finitary;
|
||||||
|
private Left left;
|
||||||
|
private First first;
|
||||||
|
private Follow follow;
|
||||||
|
|
||||||
|
public Grammar(Symbol[] symbols, Prod[][] prods) throws Exception {
|
||||||
|
validate(symbols, prods);
|
||||||
|
this.symbols = symbols;
|
||||||
|
numSyms = symbols.length;
|
||||||
|
this.prods = prods;
|
||||||
|
numNTs = prods.length;
|
||||||
|
numTs = numSyms - numNTs;
|
||||||
|
calcDepends();
|
||||||
|
comps = SCC.get(depends, revdeps, numNTs);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void validate(Symbol[] symbol, Prod[][] prod) throws Exception {
|
||||||
|
if (symbol == null || symbol.length == 0) {
|
||||||
|
throw new Exception("No symbols specified");
|
||||||
|
}
|
||||||
|
for (int i = 0; i < symbol.length; i++) {
|
||||||
|
if (symbol[i] == null) {
|
||||||
|
throw new Exception("Symbol " + i + " is null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int j = symbol.length;
|
||||||
|
if (prod == null || prod.length == 0) {
|
||||||
|
throw new Exception("No nonterminals specified");
|
||||||
|
}
|
||||||
|
if (prod.length > j) {
|
||||||
|
throw new Exception("To many nonterminals specified");
|
||||||
|
}
|
||||||
|
if (prod.length == j) {
|
||||||
|
throw new Exception("No terminals specified");
|
||||||
|
}
|
||||||
|
for (int k = 0; k < prod.length; k++) {
|
||||||
|
if (prod[k] == null || prod[k].length == 0) {
|
||||||
|
throw new Exception("Nonterminal " + symbol[k] + " (number " + k + ") has no productions");
|
||||||
|
}
|
||||||
|
for (int l = 0; l < prod[k].length; l++) {
|
||||||
|
int[] ai = prod[k][l].getRhs();
|
||||||
|
if (ai == null) {
|
||||||
|
throw new Exception("Production " + l + " for symbol " + symbol[k] + " (number " + k + ") is null");
|
||||||
|
}
|
||||||
|
for (int m : ai) {
|
||||||
|
if (m < 0 || m >= j - 1) {
|
||||||
|
throw new Exception("Out of range symbol " + m + " in production " + l + " for symbol " +
|
||||||
|
symbol[k] + " (number " + k + ")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumSyms() {
|
||||||
|
return numSyms;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumNTs() {
|
||||||
|
return numNTs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumTs() {
|
||||||
|
return numTs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Symbol getSymbol(int i) {
|
||||||
|
return symbols[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
Symbol getStart() {
|
||||||
|
return symbols[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
Symbol getEnd() {
|
||||||
|
return symbols[numSyms - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
public Symbol getNonterminal(int i) {
|
||||||
|
return symbols[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
public Symbol getTerminal(int i) {
|
||||||
|
return symbols[numNTs + i];
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isNonterminal(int i) {
|
||||||
|
return 0 <= i && i < numNTs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isTerminal(int i) {
|
||||||
|
return numNTs <= i && i < numSyms;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumProds() {
|
||||||
|
int i = 0;
|
||||||
|
for (Prod[] prod : prods) {
|
||||||
|
i += prod.length;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Prod[] getProds(int i) {
|
||||||
|
return prods[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
int[][] getComponents() {
|
||||||
|
return comps;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void calcDepends() {
|
||||||
|
int[][] ai = new int[numNTs][];
|
||||||
|
int[] ai1 = BitSet.make(numNTs);
|
||||||
|
depends = new int[numNTs][];
|
||||||
|
for (int i = 0; i < numNTs; i++) {
|
||||||
|
ai[i] = BitSet.make(numNTs);
|
||||||
|
}
|
||||||
|
for (int j = 0; j < numNTs; j++) {
|
||||||
|
BitSet.clear(ai1);
|
||||||
|
for (int l = 0; l < prods[j].length; l++) {
|
||||||
|
int[] ai2 = prods[j][l].getRhs();
|
||||||
|
for (int anAi2 : ai2) {
|
||||||
|
if (isNonterminal(anAi2)) {
|
||||||
|
BitSet.set(ai[anAi2], j);
|
||||||
|
BitSet.set(ai1, anAi2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
depends[j] = BitSet.members(ai1);
|
||||||
|
}
|
||||||
|
revdeps = new int[numNTs][];
|
||||||
|
for (int k = 0; k < numNTs; k++) {
|
||||||
|
revdeps[k] = BitSet.members(ai[k]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Nullable getNullable() {
|
||||||
|
if (nullable == null) {
|
||||||
|
nullable = new Nullable(this);
|
||||||
|
}
|
||||||
|
return nullable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Finitary getFinitary() {
|
||||||
|
if (finitary == null) {
|
||||||
|
finitary = new Finitary(this);
|
||||||
|
}
|
||||||
|
return finitary;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Left getLeft() {
|
||||||
|
if (left == null) {
|
||||||
|
left = new Left(this);
|
||||||
|
}
|
||||||
|
return left;
|
||||||
|
}
|
||||||
|
|
||||||
|
public First getFirst() {
|
||||||
|
if (first == null) {
|
||||||
|
first = new First(this, getNullable());
|
||||||
|
}
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Follow getFollow() {
|
||||||
|
if (follow == null) {
|
||||||
|
follow = new Follow(this, getNullable(), getFirst());
|
||||||
|
}
|
||||||
|
return follow;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void display(Writer writer) throws IOException {
|
||||||
|
for (int i = 0; i < numNTs; i++) {
|
||||||
|
writer.write(symbols[i].getName() + "\n");
|
||||||
|
String s = " = ";
|
||||||
|
for (int j = 0; j < prods[i].length; j++) {
|
||||||
|
int[] ai = prods[i][j].getRhs();
|
||||||
|
writer.write(s);
|
||||||
|
writer.write(displaySymbols(ai, "/* empty */", " ") + "\n");
|
||||||
|
s = " | ";
|
||||||
|
}
|
||||||
|
writer.write(" ;\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String displaySymbols(int[] ai, String s, String s1) {
|
||||||
|
return displaySymbols(ai, 0, ai.length, s, s1);
|
||||||
|
}
|
||||||
|
|
||||||
|
String displaySymbols(int[] ai, int i, int j, String s, String s1) {
|
||||||
|
if (ai == null || i >= j) {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append(symbols[ai[i]].getName());
|
||||||
|
for (int k = i + 1; k < j; k++) {
|
||||||
|
sb.append(s1);
|
||||||
|
sb.append(symbols[ai[k]].getName());
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
String displaySymbolSet(int[] ai, int i) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
int j = 0;
|
||||||
|
for (Interator interator = BitSet.interator(ai, i); interator.hasNext();
|
||||||
|
sb.append(symbols[interator.next()].getName())) {
|
||||||
|
if (j++ != 0) {
|
||||||
|
sb.append(", ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static class Prod {
|
||||||
|
|
||||||
|
int[] rhs;
|
||||||
|
private int seqNo;
|
||||||
|
|
||||||
|
public Prod(int[] ai, int i) {
|
||||||
|
rhs = ai;
|
||||||
|
seqNo = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] getRhs() {
|
||||||
|
return rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSeqNo() {
|
||||||
|
return seqNo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLabel() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static class Symbol {
|
||||||
|
|
||||||
|
String name;
|
||||||
|
|
||||||
|
public Symbol(String s) {
|
||||||
|
name = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
218
src/main/java/org/xbib/jacc/grammar/LALRMachine.java
Normal file
218
src/main/java/org/xbib/jacc/grammar/LALRMachine.java
Normal file
|
@ -0,0 +1,218 @@
|
||||||
|
package org.xbib.jacc.grammar;
|
||||||
|
|
||||||
|
import org.xbib.jacc.util.BitSet;
|
||||||
|
import org.xbib.jacc.util.IntSet;
|
||||||
|
import org.xbib.jacc.util.SCC;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Writer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class LALRMachine extends LookaheadMachine {
|
||||||
|
|
||||||
|
private Nullable nullable;
|
||||||
|
private First first;
|
||||||
|
private int[][] predState;
|
||||||
|
private int numGotos;
|
||||||
|
private int[] stateFirstGoto;
|
||||||
|
private int[] gotoSource;
|
||||||
|
private int[] gotoTrans;
|
||||||
|
private int[][] gotoLA;
|
||||||
|
private int[][] gotoTargets;
|
||||||
|
private int[][][] laReds;
|
||||||
|
|
||||||
|
public LALRMachine(Grammar grammar) {
|
||||||
|
super(grammar);
|
||||||
|
nullable = grammar.getNullable();
|
||||||
|
first = grammar.getFirst();
|
||||||
|
predState = SCC.invert(succState, numStates);
|
||||||
|
calcGotoLA();
|
||||||
|
calcLookahead();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] getLookaheadAt(int i, int j) {
|
||||||
|
return laReds[i][j];
|
||||||
|
}
|
||||||
|
|
||||||
|
private void calcGotoLA() {
|
||||||
|
stateFirstGoto = new int[numStates];
|
||||||
|
numGotos = 0;
|
||||||
|
for (int i = 0; i < numStates; i++) {
|
||||||
|
stateFirstGoto[i] = numGotos;
|
||||||
|
numGotos += getGotosAt(i).length;
|
||||||
|
}
|
||||||
|
gotoSource = new int[numGotos];
|
||||||
|
gotoTrans = new int[numGotos];
|
||||||
|
int j = 0;
|
||||||
|
for (int k = 0; k < numStates; k++) {
|
||||||
|
int[] ai1 = getGotosAt(k);
|
||||||
|
for (int a : ai1) {
|
||||||
|
gotoSource[j] = k;
|
||||||
|
gotoTrans[j] = a;
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gotoLA = new int[numGotos][];
|
||||||
|
gotoTargets = new int[numGotos][];
|
||||||
|
for (int l = 0; l < numGotos; l++) {
|
||||||
|
calcTargets(l);
|
||||||
|
}
|
||||||
|
int[][] ai = SCC.get(gotoTargets);
|
||||||
|
for (int[] ai2 : ai) {
|
||||||
|
for (boolean flag = true; flag; ) {
|
||||||
|
flag = false;
|
||||||
|
int k1 = 0;
|
||||||
|
while (k1 < ai2.length) {
|
||||||
|
int[] ai3 = gotoTargets[ai2[k1]];
|
||||||
|
for (int a : ai3) {
|
||||||
|
if (BitSet.addTo(gotoLA[ai2[k1]], gotoLA[a])) {
|
||||||
|
flag = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
k1++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void calcTargets(int i) {
|
||||||
|
int j = gotoSource[i];
|
||||||
|
int k = gotoTrans[i];
|
||||||
|
int l = getEntry(k);
|
||||||
|
IntSet intset = getItemsAt(k);
|
||||||
|
int i1 = intset.size();
|
||||||
|
int[] ai = BitSet.make(numTs);
|
||||||
|
IntSet intset1 = IntSet.empty();
|
||||||
|
for (int j1 = 0; j1 < i1; j1++) {
|
||||||
|
LR0Items.Item item = items.getItem(intset.at(j1));
|
||||||
|
int k1 = item.getLhs();
|
||||||
|
int l1 = item.getPos();
|
||||||
|
if (k1 >= 0) {
|
||||||
|
int[] ai1 = item.getProd().getRhs();
|
||||||
|
if (l1 > 0 && ai1[--l1] == l && calcFirsts(ai, item).canReduce()) {
|
||||||
|
findTargets(intset1, j, k1, ai1, l1);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (l1 > 0) {
|
||||||
|
BitSet.set(ai, numTs - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gotoLA[i] = ai;
|
||||||
|
gotoTargets[i] = intset1.toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private LR0Items.Item calcFirsts(int[] ai, LR0Items.Item item) {
|
||||||
|
do {
|
||||||
|
if (!item.canGoto()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
int i = item.getNextSym();
|
||||||
|
if (grammar.isTerminal(i)) {
|
||||||
|
BitSet.addTo(ai, i - numNTs);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
BitSet.union(ai, first.at(i));
|
||||||
|
if (!nullable.at(i)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
item = items.getItem(item.getNextItem());
|
||||||
|
} while (true);
|
||||||
|
if (item.canAccept()) {
|
||||||
|
BitSet.set(ai, numTs - 1);
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void findTargets(IntSet intset, int i, int j, int[] ai, int k) {
|
||||||
|
if (k == 0) {
|
||||||
|
int[] ai1 = getGotosAt(i);
|
||||||
|
int i1 = 0;
|
||||||
|
do {
|
||||||
|
if (i1 >= ai1.length) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (getEntry(ai1[i1]) == j) {
|
||||||
|
intset.add(stateFirstGoto[i] + i1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i1++;
|
||||||
|
} while (true);
|
||||||
|
} else if (entry[i] == ai[--k]) {
|
||||||
|
for (int l = 0; l < predState[i].length; l++) {
|
||||||
|
findTargets(intset, predState[i][l], j, ai, k);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void calcLookahead() {
|
||||||
|
laReds = new int[numStates][][];
|
||||||
|
for (int i = 0; i < numStates; i++) {
|
||||||
|
int[] ai = getReducesAt(i);
|
||||||
|
IntSet intset = getItemsAt(i);
|
||||||
|
laReds[i] = new int[ai.length][];
|
||||||
|
for (int j = 0; j < ai.length; j++) {
|
||||||
|
LR0Items.Item item = items.getItem(intset.at(ai[j]));
|
||||||
|
int k = item.getLhs();
|
||||||
|
int[] ai1 = item.getProd().getRhs();
|
||||||
|
int[] ai2 = BitSet.make(numTs);
|
||||||
|
lookBack(ai2, i, k, ai1, ai1.length);
|
||||||
|
laReds[i][j] = ai2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void lookBack(int[] ai, int i, int j, int[] ai1, int k) {
|
||||||
|
if (k == 0) {
|
||||||
|
int[] ai2 = getGotosAt(i);
|
||||||
|
for (int i1 = 0; i1 < ai2.length; i1++) {
|
||||||
|
if (getEntry(ai2[i1]) == j) {
|
||||||
|
BitSet.union(ai, gotoLA[stateFirstGoto[i] + i1]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (entry[i] == ai1[--k]) {
|
||||||
|
for (int l = 0; l < predState[i].length; l++) {
|
||||||
|
lookBack(ai, predState[i][l], j, ai1, k);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void display(Writer writer) throws IOException {
|
||||||
|
super.display(writer);
|
||||||
|
for (int i = 0; i < numGotos; i++) {
|
||||||
|
writer.write("Goto #" + i + ", in state " + gotoSource[i] + " on symbol " +
|
||||||
|
grammar.getSymbol(getEntry(gotoTrans[i])) + " to state " + gotoTrans[i] + "\n");
|
||||||
|
writer.write(" Lookahead: {");
|
||||||
|
writer.write(grammar.displaySymbolSet(gotoLA[i], numNTs));
|
||||||
|
writer.write("}\n");
|
||||||
|
writer.write(" Targets : {");
|
||||||
|
for (int k = 0; k < gotoTargets[i].length; k++) {
|
||||||
|
if (k > 0) {
|
||||||
|
writer.write(", ");
|
||||||
|
}
|
||||||
|
writer.write(gotoTargets[i][k]);
|
||||||
|
}
|
||||||
|
writer.write("}\n");
|
||||||
|
}
|
||||||
|
for (int j = 0; j < numStates; j++) {
|
||||||
|
int[] ai = getReducesAt(j);
|
||||||
|
if (ai.length <= 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
writer.write("State " + j + ":\n");
|
||||||
|
IntSet intset = getItemsAt(j);
|
||||||
|
for (int l = 0; l < ai.length; l++) {
|
||||||
|
LR0Items.Item item = items.getItem(intset.at(ai[l]));
|
||||||
|
writer.write(" Item : ");
|
||||||
|
item.display(writer);
|
||||||
|
writer.write("\n");
|
||||||
|
writer.write(" Lookahead: {");
|
||||||
|
writer.write(grammar.displaySymbolSet(laReds[j][l], numNTs));
|
||||||
|
writer.write("}\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
158
src/main/java/org/xbib/jacc/grammar/LR0Items.java
Normal file
158
src/main/java/org/xbib/jacc/grammar/LR0Items.java
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
package org.xbib.jacc.grammar;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Writer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class LR0Items {
|
||||||
|
|
||||||
|
private Grammar grammar;
|
||||||
|
private int numItems;
|
||||||
|
private Item[] items;
|
||||||
|
private int[][] firstKernel;
|
||||||
|
|
||||||
|
LR0Items(Grammar grammar) {
|
||||||
|
this.grammar = grammar;
|
||||||
|
int i = grammar.getNumNTs();
|
||||||
|
numItems = 2;
|
||||||
|
firstKernel = new int[i][];
|
||||||
|
for (int j = 0; j < i; j++) {
|
||||||
|
Grammar.Prod[] aprod = grammar.getProds(j);
|
||||||
|
firstKernel[j] = new int[aprod.length];
|
||||||
|
for (int l = 0; l < aprod.length; l++) {
|
||||||
|
int j1 = aprod[l].getRhs().length;
|
||||||
|
firstKernel[j][l] = numItems;
|
||||||
|
numItems += j1 != 0 ? j1 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
items = new Item[numItems];
|
||||||
|
numItems = 0;
|
||||||
|
new Item(-1, 0, 0);
|
||||||
|
new Item(-1, 0, 1);
|
||||||
|
for (int k = 0; k < i; k++) {
|
||||||
|
Grammar.Prod[] aprod1 = grammar.getProds(k);
|
||||||
|
for (int i1 = 0; i1 < aprod1.length; i1++) {
|
||||||
|
int[] ai = aprod1[i1].getRhs();
|
||||||
|
for (int k1 = 1; k1 < ai.length; k1++) {
|
||||||
|
new Item(k, i1, k1);
|
||||||
|
}
|
||||||
|
new Item(k, i1, ai.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Item getItem(int i) {
|
||||||
|
return items[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
int getStartItem() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getEndItem() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getFirstKernel(int i, int j) {
|
||||||
|
return firstKernel[i][j];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class Item {
|
||||||
|
private int itemNo;
|
||||||
|
private int lhs;
|
||||||
|
private int prodNo;
|
||||||
|
private int pos;
|
||||||
|
|
||||||
|
private Item(int i, int j, int k) {
|
||||||
|
itemNo = numItems;
|
||||||
|
lhs = i;
|
||||||
|
prodNo = j;
|
||||||
|
pos = k;
|
||||||
|
items[numItems++] = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getLhs() {
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getProdNo() {
|
||||||
|
return prodNo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSeqNo() {
|
||||||
|
return getProd().getSeqNo();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Grammar.Prod getProd() {
|
||||||
|
return grammar.getProds(lhs)[prodNo];
|
||||||
|
}
|
||||||
|
|
||||||
|
int getPos() {
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean canGoto() {
|
||||||
|
if (lhs < 0) {
|
||||||
|
return pos == 0;
|
||||||
|
} else {
|
||||||
|
return pos != getProd().getRhs().length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean canReduce() {
|
||||||
|
return lhs >= 0 && pos == getProd().getRhs().length;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean canAccept() {
|
||||||
|
return lhs < 0 && pos == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getNextItem() {
|
||||||
|
if (lhs >= 0) {
|
||||||
|
return itemNo + 1;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int getNextSym() {
|
||||||
|
if (lhs >= 0) {
|
||||||
|
return grammar.getProds(lhs)[prodNo].getRhs()[pos];
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void display(Writer writer) throws IOException {
|
||||||
|
if (lhs < 0) {
|
||||||
|
if (pos == 0) {
|
||||||
|
writer.write("$accept : _" + grammar.getStart() + " " + grammar.getEnd());
|
||||||
|
} else {
|
||||||
|
writer.write("$accept : " + grammar.getStart() + "_" + grammar.getEnd());
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
writer.write(grammar.getSymbol(lhs).toString());
|
||||||
|
writer.write(" : ");
|
||||||
|
Grammar.Prod prod = grammar.getProds(lhs)[prodNo];
|
||||||
|
int[] ai = prod.getRhs();
|
||||||
|
writer.write(grammar.displaySymbols(ai, 0, pos, "", " "));
|
||||||
|
writer.write("_");
|
||||||
|
if (pos < ai.length) {
|
||||||
|
writer.write(grammar.displaySymbols(ai, pos, ai.length, "", " "));
|
||||||
|
}
|
||||||
|
String s = prod.getLabel();
|
||||||
|
if (s != null) {
|
||||||
|
writer.write(" (");
|
||||||
|
writer.write(s);
|
||||||
|
writer.write(')');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
34
src/main/java/org/xbib/jacc/grammar/LR0Machine.java
Normal file
34
src/main/java/org/xbib/jacc/grammar/LR0Machine.java
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
package org.xbib.jacc.grammar;
|
||||||
|
|
||||||
|
import org.xbib.jacc.util.BitSet;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Writer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class LR0Machine extends LookaheadMachine {
|
||||||
|
|
||||||
|
private int allTokens[];
|
||||||
|
|
||||||
|
public LR0Machine(Grammar grammar) {
|
||||||
|
super(grammar);
|
||||||
|
int i = grammar.getNumTs();
|
||||||
|
allTokens = BitSet.make(i);
|
||||||
|
for (int j = 0; j < i; j++) {
|
||||||
|
BitSet.set(allTokens, j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] getLookaheadAt(int i, int j) {
|
||||||
|
return allTokens;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void display(Writer writer) throws IOException {
|
||||||
|
super.display(writer);
|
||||||
|
writer.write("Lookahead set is {");
|
||||||
|
writer.write(grammar.displaySymbolSet(allTokens, numNTs));
|
||||||
|
writer.write("}\n");
|
||||||
|
}
|
||||||
|
}
|
52
src/main/java/org/xbib/jacc/grammar/Left.java
Normal file
52
src/main/java/org/xbib/jacc/grammar/Left.java
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
package org.xbib.jacc.grammar;
|
||||||
|
|
||||||
|
import org.xbib.jacc.util.BitSet;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Writer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
final class Left extends Analysis {
|
||||||
|
|
||||||
|
private Grammar grammar;
|
||||||
|
private int[][] left;
|
||||||
|
|
||||||
|
Left(Grammar grammar1) {
|
||||||
|
super(grammar1.getComponents());
|
||||||
|
grammar = grammar1;
|
||||||
|
int numNTs = grammar1.getNumNTs();
|
||||||
|
left = new int[numNTs][];
|
||||||
|
for (int i = 0; i < numNTs; i++) {
|
||||||
|
left[i] = BitSet.make(numNTs);
|
||||||
|
BitSet.set(left[i], i);
|
||||||
|
}
|
||||||
|
bottomUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean analyze(int i) {
|
||||||
|
boolean flag = false;
|
||||||
|
Grammar.Prod aprod[] = grammar.getProds(i);
|
||||||
|
for (Grammar.Prod anAprod : aprod) {
|
||||||
|
int ai[] = anAprod.getRhs();
|
||||||
|
if (ai.length > 0 && grammar.isNonterminal(ai[0]) && BitSet.addTo(left[i], left[ai[0]])) {
|
||||||
|
flag = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] at(int i) {
|
||||||
|
return left[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void display(Writer writer) throws IOException {
|
||||||
|
writer.write("Left nonterminal sets:\n");
|
||||||
|
for (int i = 0; i < left.length; i++) {
|
||||||
|
writer.write(" Left(" + grammar.getSymbol(i) + "): {");
|
||||||
|
writer.write(grammar.displaySymbolSet(left[i], 0));
|
||||||
|
writer.write("}\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
13
src/main/java/org/xbib/jacc/grammar/LookaheadMachine.java
Normal file
13
src/main/java/org/xbib/jacc/grammar/LookaheadMachine.java
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
package org.xbib.jacc.grammar;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public abstract class LookaheadMachine extends Machine {
|
||||||
|
|
||||||
|
LookaheadMachine(Grammar grammar) {
|
||||||
|
super(grammar);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract int[] getLookaheadAt(int i, int j);
|
||||||
|
}
|
269
src/main/java/org/xbib/jacc/grammar/Machine.java
Normal file
269
src/main/java/org/xbib/jacc/grammar/Machine.java
Normal file
|
@ -0,0 +1,269 @@
|
||||||
|
package org.xbib.jacc.grammar;
|
||||||
|
|
||||||
|
import org.xbib.jacc.util.BitSet;
|
||||||
|
import org.xbib.jacc.util.IntSet;
|
||||||
|
import org.xbib.jacc.util.Interator;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Writer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class Machine {
|
||||||
|
|
||||||
|
private final IntSet acceptItems = IntSet.singleton(-1);
|
||||||
|
protected Grammar grammar;
|
||||||
|
protected int numNTs;
|
||||||
|
protected int numTs;
|
||||||
|
protected Left left;
|
||||||
|
LR0Items items;
|
||||||
|
int numStates;
|
||||||
|
int[] entry;
|
||||||
|
int[][] succState;
|
||||||
|
private int numSyms;
|
||||||
|
private IntSet[] stateSets;
|
||||||
|
private IntSet[] nullReds;
|
||||||
|
private int[][] gotos;
|
||||||
|
private int[][] shifts;
|
||||||
|
private int[][] reduceOffsets;
|
||||||
|
|
||||||
|
Machine(Grammar grammar) {
|
||||||
|
this.grammar = grammar;
|
||||||
|
numSyms = grammar.getNumSyms();
|
||||||
|
numNTs = grammar.getNumNTs();
|
||||||
|
numTs = grammar.getNumTs();
|
||||||
|
left = grammar.getLeft();
|
||||||
|
items = new LR0Items(grammar);
|
||||||
|
calcLR0states();
|
||||||
|
calcGotosShifts();
|
||||||
|
calcReduceOffsets();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Grammar getGrammar() {
|
||||||
|
return grammar;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumStates() {
|
||||||
|
return numStates;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LR0Items getItems() {
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LR0Items.Item reduceItem(int i, int j) {
|
||||||
|
return items.getItem(stateSets[i].at(j));
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getEntry(int i) {
|
||||||
|
return i >= 0 ? entry[i] : numSyms - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntSet getItemsAt(int i) {
|
||||||
|
return stateSets[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] getGotosAt(int i) {
|
||||||
|
return gotos[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] getShiftsAt(int i) {
|
||||||
|
return shifts[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
int[] getReducesAt(int i) {
|
||||||
|
return reduceOffsets[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
private void calcLR0states() {
|
||||||
|
stateSets = new IntSet[16];
|
||||||
|
succState = new int[16][];
|
||||||
|
entry = new int[16];
|
||||||
|
nullReds = new IntSet[16];
|
||||||
|
stateSets[0] = IntSet.singleton(items.getStartItem());
|
||||||
|
numStates = 1;
|
||||||
|
IntSet[] aintset = new IntSet[numSyms];
|
||||||
|
int i = 0;
|
||||||
|
int[] ai = BitSet.make(numNTs);
|
||||||
|
for (int j = 0; j < numStates; j++) {
|
||||||
|
IntSet intset = stateSets[j];
|
||||||
|
BitSet.clear(ai);
|
||||||
|
Interator interator = intset.interator();
|
||||||
|
do {
|
||||||
|
if (!interator.hasNext()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
LR0Items.Item item = items.getItem(interator.next());
|
||||||
|
if (item.canGoto()) {
|
||||||
|
int k = item.getNextSym();
|
||||||
|
int i1 = item.getNextItem();
|
||||||
|
if (grammar.isNonterminal(k)) {
|
||||||
|
BitSet.addTo(ai, left.at(k));
|
||||||
|
}
|
||||||
|
if (addValue(aintset, k, i1)) {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (true);
|
||||||
|
if (!BitSet.isEmpty(ai)) {
|
||||||
|
for (Interator interator1 = BitSet.interator(ai, 0); interator1.hasNext(); ) {
|
||||||
|
int l = interator1.next();
|
||||||
|
Grammar.Prod[] aprod = grammar.getProds(l);
|
||||||
|
int k1 = 0;
|
||||||
|
while (k1 < aprod.length) {
|
||||||
|
int[] ai3 = aprod[k1].getRhs();
|
||||||
|
int i2 = items.getFirstKernel(l, k1);
|
||||||
|
if (ai3.length != 0) {
|
||||||
|
if (addValue(aintset, ai3[0], i2)) {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
addValue(nullReds, j, i2);
|
||||||
|
}
|
||||||
|
k1++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int[] ai1 = new int[i];
|
||||||
|
int j1 = 0;
|
||||||
|
for (int l1 = 0; j1 < i; l1++) {
|
||||||
|
if (aintset[l1] != null) {
|
||||||
|
ai1[j1] = addState(l1, aintset[l1]);
|
||||||
|
aintset[l1] = null;
|
||||||
|
j1++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i = 0;
|
||||||
|
succState[j] = ai1;
|
||||||
|
}
|
||||||
|
mergeNullReds();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean addValue(IntSet[] aintset, int i, int j) {
|
||||||
|
if (aintset[i] == null) {
|
||||||
|
aintset[i] = IntSet.singleton(j);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
aintset[i].add(j);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int addState(int i, IntSet intset) {
|
||||||
|
for (int j = 0; j < numStates; j++) {
|
||||||
|
if (stateSets[j].equals(intset)) {
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (acceptItems.equals(intset)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (numStates >= stateSets.length) {
|
||||||
|
int k = 2 * stateSets.length;
|
||||||
|
IntSet[] aintset = new IntSet[k];
|
||||||
|
int[][] ai = new int[k][];
|
||||||
|
IntSet[] aintset1 = new IntSet[k];
|
||||||
|
int[] ai1 = new int[k];
|
||||||
|
for (int l = 0; l < numStates; l++) {
|
||||||
|
aintset[l] = stateSets[l];
|
||||||
|
ai[l] = succState[l];
|
||||||
|
ai1[l] = entry[l];
|
||||||
|
aintset1[l] = nullReds[l];
|
||||||
|
}
|
||||||
|
stateSets = aintset;
|
||||||
|
succState = ai;
|
||||||
|
entry = ai1;
|
||||||
|
nullReds = aintset1;
|
||||||
|
}
|
||||||
|
stateSets[numStates] = intset;
|
||||||
|
entry[numStates] = i;
|
||||||
|
return numStates++;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void mergeNullReds() {
|
||||||
|
for (int i = 0; i < numStates; i++) {
|
||||||
|
if (nullReds[i] == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Interator interator = nullReds[i].interator();
|
||||||
|
while (interator.hasNext()) {
|
||||||
|
stateSets[i].add(interator.next());
|
||||||
|
}
|
||||||
|
nullReds[i] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void calcGotosShifts() {
|
||||||
|
gotos = new int[numStates][];
|
||||||
|
shifts = new int[numStates][];
|
||||||
|
for (int i = 0; i < numStates; i++) {
|
||||||
|
int j = 0;
|
||||||
|
int k = 0;
|
||||||
|
for (int l = 0; l < succState[i].length; l++) {
|
||||||
|
int j1 = succState[i][l];
|
||||||
|
if (grammar.isTerminal(entry[j1])) {
|
||||||
|
k++;
|
||||||
|
} else {
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (stateSets[i].contains(items.getEndItem())) {
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
gotos[i] = new int[j];
|
||||||
|
shifts[i] = new int[k];
|
||||||
|
for (int i1 = succState[i].length; 0 < i1--; ) {
|
||||||
|
int k1 = succState[i][i1];
|
||||||
|
if (grammar.isTerminal(entry[k1])) {
|
||||||
|
shifts[i][--k] = k1;
|
||||||
|
} else {
|
||||||
|
gotos[i][--j] = k1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (k > 0) {
|
||||||
|
shifts[i][0] = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void calcReduceOffsets() {
|
||||||
|
reduceOffsets = new int[numStates][];
|
||||||
|
for (int i = 0; i < numStates; i++) {
|
||||||
|
int j = 0;
|
||||||
|
IntSet intset = stateSets[i];
|
||||||
|
int k = intset.size();
|
||||||
|
for (int l = 0; l < k; l++) {
|
||||||
|
if (items.getItem(intset.at(l)).canReduce()) {
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reduceOffsets[i] = new int[j];
|
||||||
|
int i1 = 0;
|
||||||
|
for (int j1 = 0; j1 < k; j1++) {
|
||||||
|
if (items.getItem(intset.at(j1)).canReduce()) {
|
||||||
|
reduceOffsets[i][i1++] = j1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void display(Writer writer) throws IOException {
|
||||||
|
for (int i = 0; i < numStates; i++) {
|
||||||
|
writer.write("state " + i + "\n");
|
||||||
|
for (Interator interator = stateSets[i].interator(); interator.hasNext(); writer.write("\n")) {
|
||||||
|
writer.write("\t");
|
||||||
|
items.getItem(interator.next()).display(writer);
|
||||||
|
}
|
||||||
|
writer.write("\n");
|
||||||
|
if (succState[i].length <= 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (int j = 0; j < succState[i].length; j++) {
|
||||||
|
int k = succState[i][j];
|
||||||
|
writer.write("\t" + grammar.getSymbol(entry[k]) + " goto " + succState[i][j] + "\n");
|
||||||
|
}
|
||||||
|
writer.write("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
77
src/main/java/org/xbib/jacc/grammar/Nullable.java
Normal file
77
src/main/java/org/xbib/jacc/grammar/Nullable.java
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
package org.xbib.jacc.grammar;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Writer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class Nullable extends Analysis {
|
||||||
|
|
||||||
|
private boolean nullable[];
|
||||||
|
private boolean consider[];
|
||||||
|
private Grammar grammar;
|
||||||
|
private int numNTs;
|
||||||
|
|
||||||
|
Nullable(Grammar grammar) {
|
||||||
|
super(grammar.getComponents());
|
||||||
|
this.grammar = grammar;
|
||||||
|
numNTs = grammar.getNumNTs();
|
||||||
|
nullable = new boolean[numNTs];
|
||||||
|
consider = new boolean[numNTs];
|
||||||
|
for (int i = 0; i < numNTs; i++) {
|
||||||
|
nullable[i] = false;
|
||||||
|
consider[i] = true;
|
||||||
|
}
|
||||||
|
bottomUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean analyze(int i) {
|
||||||
|
boolean flag = false;
|
||||||
|
if (consider[i]) {
|
||||||
|
int j = 0;
|
||||||
|
Grammar.Prod aprod[] = grammar.getProds(i);
|
||||||
|
for (Grammar.Prod anAprod : aprod) {
|
||||||
|
int ai[] = anAprod.getRhs();
|
||||||
|
int l;
|
||||||
|
l = 0;
|
||||||
|
while (l < ai.length && at(ai[l])) {
|
||||||
|
l++;
|
||||||
|
}
|
||||||
|
if (l >= ai.length) {
|
||||||
|
nullable[i] = true;
|
||||||
|
consider[i] = false;
|
||||||
|
flag = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (grammar.isTerminal(ai[l]) || grammar.isNonterminal(ai[l]) && !consider[ai[l]]) {
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (j == aprod.length) {
|
||||||
|
consider[i] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean at(int i) {
|
||||||
|
return grammar.isNonterminal(i) && nullable[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void display(Writer writer) throws IOException {
|
||||||
|
writer.write("Nullable = {");
|
||||||
|
int i = 0;
|
||||||
|
for (int j = 0; j < numNTs; j++) {
|
||||||
|
if (!at(j)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (i > 0) {
|
||||||
|
writer.write(", ");
|
||||||
|
}
|
||||||
|
writer.write(grammar.getSymbol(j).getName());
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
writer.write("}\n");
|
||||||
|
}
|
||||||
|
}
|
197
src/main/java/org/xbib/jacc/grammar/Parser.java
Normal file
197
src/main/java/org/xbib/jacc/grammar/Parser.java
Normal file
|
@ -0,0 +1,197 @@
|
||||||
|
package org.xbib.jacc.grammar;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Writer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class Parser {
|
||||||
|
|
||||||
|
private static final int ACCEPT = 0;
|
||||||
|
private static final int ERROR = 1;
|
||||||
|
private static final int SHIFT = 2;
|
||||||
|
private static final int GOTO = 3;
|
||||||
|
private static final int REDUCE = 4;
|
||||||
|
private Tables tables;
|
||||||
|
private int input[];
|
||||||
|
private Machine machine;
|
||||||
|
private Grammar grammar;
|
||||||
|
private int position;
|
||||||
|
private int currSymbol;
|
||||||
|
private int reducedNT;
|
||||||
|
private Stack stack;
|
||||||
|
private int state;
|
||||||
|
|
||||||
|
public Parser(Tables tables, int ai[]) {
|
||||||
|
position = 0;
|
||||||
|
currSymbol = -1;
|
||||||
|
reducedNT = -1;
|
||||||
|
stack = new Stack();
|
||||||
|
state = ACCEPT;
|
||||||
|
this.tables = tables;
|
||||||
|
input = ai;
|
||||||
|
machine = tables.getMachine();
|
||||||
|
grammar = machine.getGrammar();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getState() {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNextSymbol() {
|
||||||
|
return reducedNT < 0 ? currSymbol : reducedNT;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int step() {
|
||||||
|
if (state < 0) {
|
||||||
|
return ACCEPT;
|
||||||
|
}
|
||||||
|
if (reducedNT >= 0) {
|
||||||
|
shift(reducedNT);
|
||||||
|
if (!gotoState(reducedNT)) {
|
||||||
|
return ERROR;
|
||||||
|
} else {
|
||||||
|
reducedNT = -1;
|
||||||
|
return GOTO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (currSymbol < 0) {
|
||||||
|
currSymbol = position < input.length ? input[position++] : grammar.getNumSyms() - 1;
|
||||||
|
}
|
||||||
|
if (grammar.isNonterminal(currSymbol)) {
|
||||||
|
shift(currSymbol);
|
||||||
|
if (!gotoState(currSymbol)) {
|
||||||
|
return ERROR;
|
||||||
|
} else {
|
||||||
|
currSymbol = -1;
|
||||||
|
return GOTO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
byte[] b = tables.getActionAt(state);
|
||||||
|
int[] ai = tables.getArgAt(state);
|
||||||
|
int i = currSymbol - grammar.getNumNTs();
|
||||||
|
switch (b[i]) {
|
||||||
|
case 1:
|
||||||
|
if (ai[i] < 0) {
|
||||||
|
return ACCEPT;
|
||||||
|
} else {
|
||||||
|
shift(currSymbol);
|
||||||
|
currSymbol = -1;
|
||||||
|
state = ai[i];
|
||||||
|
return SHIFT;
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
reduce(ai[i]);
|
||||||
|
return REDUCE;
|
||||||
|
}
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void shift(int i) {
|
||||||
|
stack = stack.push(state, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reduce(int i) {
|
||||||
|
LR0Items.Item item = machine.reduceItem(state, i);
|
||||||
|
int j = item.getProd().getRhs().length;
|
||||||
|
if (j > 0) {
|
||||||
|
for (; j > 1; j--) {
|
||||||
|
stack = stack.pop();
|
||||||
|
}
|
||||||
|
state = stack.getState();
|
||||||
|
stack = stack.pop();
|
||||||
|
}
|
||||||
|
reducedNT = item.getLhs();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean gotoState(int i) {
|
||||||
|
int ai[] = machine.getGotosAt(state);
|
||||||
|
for (int anAi : ai) {
|
||||||
|
if (i == machine.getEntry(anAi)) {
|
||||||
|
state = anAi;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void display(Writer writer, boolean flag) throws IOException {
|
||||||
|
stack.display(writer, grammar, flag);
|
||||||
|
if (flag) {
|
||||||
|
writer.write(state);
|
||||||
|
writer.write(" ");
|
||||||
|
}
|
||||||
|
writer.write("_ ");
|
||||||
|
if (reducedNT >= 0) {
|
||||||
|
writer.write(grammar.getSymbol(reducedNT).toString());
|
||||||
|
writer.write(" ");
|
||||||
|
}
|
||||||
|
if (currSymbol >= 0) {
|
||||||
|
writer.write(grammar.getSymbol(currSymbol).toString());
|
||||||
|
if (position < input.length) {
|
||||||
|
writer.write(" ...");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (position < input.length) {
|
||||||
|
writer.write(grammar.getSymbol(input[position]).toString());
|
||||||
|
writer.write(" ...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writer.write("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static class Stack {
|
||||||
|
|
||||||
|
private int state;
|
||||||
|
private int symbol;
|
||||||
|
private Stack up;
|
||||||
|
private Stack down;
|
||||||
|
|
||||||
|
Stack() {
|
||||||
|
this(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Stack(Stack stack) {
|
||||||
|
down = stack;
|
||||||
|
up = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getState() {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSymbol() {
|
||||||
|
return symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
Stack pop() {
|
||||||
|
return down;
|
||||||
|
}
|
||||||
|
|
||||||
|
Stack push(int i, int j) {
|
||||||
|
Stack stack1 = up;
|
||||||
|
if (stack1 == null) {
|
||||||
|
stack1 = up = new Stack(this);
|
||||||
|
}
|
||||||
|
stack1.state = i;
|
||||||
|
stack1.symbol = j;
|
||||||
|
return stack1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void display(Writer writer, Grammar grammar1, boolean flag) throws IOException {
|
||||||
|
if (down != null) {
|
||||||
|
down.display(writer, grammar1, flag);
|
||||||
|
if (flag) {
|
||||||
|
writer.write(state);
|
||||||
|
writer.write(" ");
|
||||||
|
}
|
||||||
|
writer.write(grammar1.getSymbol(symbol).toString());
|
||||||
|
writer.write(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
src/main/java/org/xbib/jacc/grammar/Resolver.java
Normal file
11
src/main/java/org/xbib/jacc/grammar/Resolver.java
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
package org.xbib.jacc.grammar;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface Resolver {
|
||||||
|
|
||||||
|
void srResolve(Tables tables, int i, int j, int k);
|
||||||
|
|
||||||
|
void rrResolve(Tables tables, int i, int j, int k);
|
||||||
|
}
|
58
src/main/java/org/xbib/jacc/grammar/SLRMachine.java
Normal file
58
src/main/java/org/xbib/jacc/grammar/SLRMachine.java
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
package org.xbib.jacc.grammar;
|
||||||
|
|
||||||
|
import org.xbib.jacc.util.IntSet;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Writer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class SLRMachine extends LookaheadMachine {
|
||||||
|
|
||||||
|
private Follow follow;
|
||||||
|
private int[][][] laReds;
|
||||||
|
|
||||||
|
public SLRMachine(Grammar grammar) {
|
||||||
|
super(grammar);
|
||||||
|
follow = grammar.getFollow();
|
||||||
|
calcLookahead();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] getLookaheadAt(int i, int j) {
|
||||||
|
return laReds[i][j];
|
||||||
|
}
|
||||||
|
|
||||||
|
private void calcLookahead() {
|
||||||
|
laReds = new int[numStates][][];
|
||||||
|
for (int i = 0; i < numStates; i++) {
|
||||||
|
IntSet intset = getItemsAt(i);
|
||||||
|
int[] ai = getReducesAt(i);
|
||||||
|
laReds[i] = new int[ai.length][];
|
||||||
|
for (int j = 0; j < ai.length; j++) {
|
||||||
|
int k = items.getItem(intset.at(ai[j])).getLhs();
|
||||||
|
laReds[i][j] = follow.at(k);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void display(Writer writer) throws IOException {
|
||||||
|
super.display(writer);
|
||||||
|
for (int i = 0; i < numStates; i++) {
|
||||||
|
IntSet intset = getItemsAt(i);
|
||||||
|
int[] ai = getReducesAt(i);
|
||||||
|
if (ai.length <= 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
writer.write("In state " + i + ":");
|
||||||
|
for (int j = 0; j < ai.length; j++) {
|
||||||
|
writer.write(" Item: ");
|
||||||
|
items.getItem(intset.at(ai[j])).display(writer);
|
||||||
|
writer.write("\n");
|
||||||
|
writer.write(" Lookahead: {");
|
||||||
|
writer.write(grammar.displaySymbolSet(laReds[i][j], numNTs));
|
||||||
|
writer.write("}\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
118
src/main/java/org/xbib/jacc/grammar/Tables.java
Normal file
118
src/main/java/org/xbib/jacc/grammar/Tables.java
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
package org.xbib.jacc.grammar;
|
||||||
|
|
||||||
|
import org.xbib.jacc.util.BitSet;
|
||||||
|
import org.xbib.jacc.util.IntSet;
|
||||||
|
import org.xbib.jacc.util.Interator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class Tables {
|
||||||
|
|
||||||
|
private static final byte NONE = 0;
|
||||||
|
private static final byte SHIFT = 1;
|
||||||
|
private static final byte REDUCE = 2;
|
||||||
|
protected LookaheadMachine machine;
|
||||||
|
protected int numNTs;
|
||||||
|
protected int numTs;
|
||||||
|
protected byte[][] action;
|
||||||
|
protected int[][] arg;
|
||||||
|
private Resolver resolver;
|
||||||
|
private boolean[][] prodUsed;
|
||||||
|
private int prodUnused;
|
||||||
|
|
||||||
|
public Tables(LookaheadMachine lookaheadmachine, Resolver resolver) {
|
||||||
|
machine = lookaheadmachine;
|
||||||
|
this.resolver = resolver;
|
||||||
|
Grammar grammar = lookaheadmachine.getGrammar();
|
||||||
|
numNTs = grammar.getNumNTs();
|
||||||
|
numTs = grammar.getNumTs();
|
||||||
|
int i = lookaheadmachine.getNumStates();
|
||||||
|
action = new byte[i][];
|
||||||
|
arg = new int[i][];
|
||||||
|
prodUsed = new boolean[numNTs][];
|
||||||
|
prodUnused = 0;
|
||||||
|
for (int j = 0; j < numNTs; j++) {
|
||||||
|
prodUsed[j] = new boolean[grammar.getProds(j).length];
|
||||||
|
prodUnused += prodUsed[j].length;
|
||||||
|
}
|
||||||
|
for (int k = 0; k < i; k++) {
|
||||||
|
fillTablesAt(k);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public LookaheadMachine getMachine() {
|
||||||
|
return machine;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getActionAt(int i) {
|
||||||
|
return action[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] getArgAt(int i) {
|
||||||
|
return arg[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getProdUnused() {
|
||||||
|
return prodUnused;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean[] getProdsUsedAt(int i) {
|
||||||
|
return prodUsed[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setShift(int i, int j, int k) {
|
||||||
|
action[i][j] = SHIFT;
|
||||||
|
arg[i][j] = k;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReduce(int i, int j, int k) {
|
||||||
|
action[i][j] = REDUCE;
|
||||||
|
arg[i][j] = k;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fillTablesAt(int i) {
|
||||||
|
int ai1[];
|
||||||
|
action[i] = new byte[numTs];
|
||||||
|
arg[i] = new int[numTs];
|
||||||
|
int ai[] = machine.getShiftsAt(i);
|
||||||
|
ai1 = machine.getReducesAt(i);
|
||||||
|
for (int anAi : ai) {
|
||||||
|
setShift(i, machine.getEntry(anAi) - numNTs, anAi);
|
||||||
|
}
|
||||||
|
for (int k = 0; k < ai1.length; k++) {
|
||||||
|
for (Interator interator = BitSet.interator(machine.getLookaheadAt(i, k), 0);
|
||||||
|
interator.hasNext(); ) {
|
||||||
|
int l = interator.next();
|
||||||
|
switch (action[i][l]) {
|
||||||
|
case NONE:
|
||||||
|
setReduce(i, l, ai1[k]);
|
||||||
|
break;
|
||||||
|
case SHIFT:
|
||||||
|
resolver.srResolve(this, i, l, ai1[k]);
|
||||||
|
break;
|
||||||
|
case REDUCE:
|
||||||
|
resolver.rrResolve(this, i, l, ai1[k]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LR0Items lr0items = machine.getItems();
|
||||||
|
IntSet intset = machine.getItemsAt(i);
|
||||||
|
for (int anAi1 : ai1) {
|
||||||
|
for (int j1 = 0; j1 < numTs; j1++) {
|
||||||
|
if (action[i][j1] == REDUCE && arg[i][j1] == anAi1) {
|
||||||
|
LR0Items.Item item = lr0items.getItem(intset.at(anAi1));
|
||||||
|
int k1 = item.getLhs();
|
||||||
|
int l1 = item.getProdNo();
|
||||||
|
if (!prodUsed[k1][l1]) {
|
||||||
|
prodUsed[k1][l1] = true;
|
||||||
|
prodUnused--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
4
src/main/java/org/xbib/jacc/grammar/package-info.java
Normal file
4
src/main/java/org/xbib/jacc/grammar/package-info.java
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
/**
|
||||||
|
* Classes for grammar construction.
|
||||||
|
*/
|
||||||
|
package org.xbib.jacc.grammar;
|
4
src/main/java/org/xbib/jacc/package-info.java
Normal file
4
src/main/java/org/xbib/jacc/package-info.java
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
/**
|
||||||
|
* Classes for compiler generation.
|
||||||
|
*/
|
||||||
|
package org.xbib.jacc;
|
169
src/main/java/org/xbib/jacc/util/BitSet.java
Normal file
169
src/main/java/org/xbib/jacc/util/BitSet.java
Normal file
|
@ -0,0 +1,169 @@
|
||||||
|
package org.xbib.jacc.util;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class BitSet {
|
||||||
|
private static final int LOG_BITS_PER_WORD = 5;
|
||||||
|
private static final int BITS_PER_WORD = 32;
|
||||||
|
|
||||||
|
private BitSet() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int[] make(int i) {
|
||||||
|
return new int[(i + 32) - 1 >> 5];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void clear(int[] ai) {
|
||||||
|
for (int i = 0; i < ai.length; i++) {
|
||||||
|
ai[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isEmpty(int[] ai) {
|
||||||
|
for (int anAi : ai) {
|
||||||
|
if (anAi != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void union(int[] ai, int[] ai1) {
|
||||||
|
for (int i = 0; i < ai.length; i++) {
|
||||||
|
ai[i] |= ai1[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean addTo(int[] ai, int[] ai1) {
|
||||||
|
if (ai.length < ai1.length) {
|
||||||
|
throw new Error("bitset arguments do not match");
|
||||||
|
}
|
||||||
|
int i = 0;
|
||||||
|
boolean flag = false;
|
||||||
|
for (; i < ai1.length; i++) {
|
||||||
|
if (ai1[i] == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int j = ai[i] | ai1[i];
|
||||||
|
if (j != ai[i]) {
|
||||||
|
flag = true;
|
||||||
|
}
|
||||||
|
ai[i] = j;
|
||||||
|
}
|
||||||
|
return flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean addTo(int[] ai, int i) {
|
||||||
|
int j = 1 << (i & 0x1f);
|
||||||
|
int k = i >> LOG_BITS_PER_WORD;
|
||||||
|
int l = ai[k] | j;
|
||||||
|
if (l != ai[k]) {
|
||||||
|
ai[k] = l;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void set(int[] ai, int i) {
|
||||||
|
int j = 1 << (i & 0x1f);
|
||||||
|
int k = i >> LOG_BITS_PER_WORD;
|
||||||
|
ai[k] |= j;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean get(int[] ai, int i) {
|
||||||
|
int j = 1 << (i & 0x1f);
|
||||||
|
int k = i >> LOG_BITS_PER_WORD;
|
||||||
|
return (ai[k] & j) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int[] members(int[] ai) {
|
||||||
|
int i = 0;
|
||||||
|
label0:
|
||||||
|
for (int anAi : ai) {
|
||||||
|
if (anAi == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int k = anAi;
|
||||||
|
int i1 = 0;
|
||||||
|
do {
|
||||||
|
if (i1 >= BITS_PER_WORD || k == 0) {
|
||||||
|
continue label0;
|
||||||
|
}
|
||||||
|
if ((k & 1) != 0) {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
k >>= 1;
|
||||||
|
i1++;
|
||||||
|
} while (true);
|
||||||
|
}
|
||||||
|
int[] ai1 = new int[i];
|
||||||
|
int l = 0;
|
||||||
|
label1:
|
||||||
|
for (int j1 = 0; j1 < ai.length && l < i; j1++) {
|
||||||
|
if (ai[j1] == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int k1 = j1 << LOG_BITS_PER_WORD;
|
||||||
|
int l1 = ai[j1];
|
||||||
|
int i2 = 0;
|
||||||
|
do {
|
||||||
|
if (i2 >= BITS_PER_WORD || l1 == 0) {
|
||||||
|
continue label1;
|
||||||
|
}
|
||||||
|
if ((l1 & 1) != 0) {
|
||||||
|
ai1[l++] = k1 + i2;
|
||||||
|
}
|
||||||
|
l1 >>= 1;
|
||||||
|
i2++;
|
||||||
|
} while (true);
|
||||||
|
}
|
||||||
|
return ai1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Interator interator(int[] ai, int i) {
|
||||||
|
return new BitSetInterator(ai, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class BitSetInterator extends Interator {
|
||||||
|
|
||||||
|
int[] set;
|
||||||
|
int pos;
|
||||||
|
int mask;
|
||||||
|
int num;
|
||||||
|
int bitCount;
|
||||||
|
|
||||||
|
BitSetInterator(int[] ai, int i) {
|
||||||
|
set = ai;
|
||||||
|
num = i;
|
||||||
|
pos = 0;
|
||||||
|
mask = 1;
|
||||||
|
bitCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void advance() {
|
||||||
|
num++;
|
||||||
|
if (++bitCount == 32) {
|
||||||
|
pos++;
|
||||||
|
bitCount = 0;
|
||||||
|
mask = 1;
|
||||||
|
} else {
|
||||||
|
mask <<= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int next() {
|
||||||
|
int i = num;
|
||||||
|
advance();
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasNext() {
|
||||||
|
while (pos < set.length && (set[pos] & mask) == 0) {
|
||||||
|
advance();
|
||||||
|
}
|
||||||
|
return pos < set.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
29
src/main/java/org/xbib/jacc/util/ElemInterator.java
Normal file
29
src/main/java/org/xbib/jacc/util/ElemInterator.java
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
package org.xbib.jacc.util;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class ElemInterator extends Interator {
|
||||||
|
|
||||||
|
private int count;
|
||||||
|
private int limit;
|
||||||
|
private int[] a;
|
||||||
|
|
||||||
|
ElemInterator(int[] ai, int i, int j) {
|
||||||
|
a = ai;
|
||||||
|
count = i;
|
||||||
|
limit = j;
|
||||||
|
}
|
||||||
|
|
||||||
|
ElemInterator(int[] ai) {
|
||||||
|
this(ai, 0, ai.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int next() {
|
||||||
|
return a[count++];
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasNext() {
|
||||||
|
return count < limit;
|
||||||
|
}
|
||||||
|
}
|
127
src/main/java/org/xbib/jacc/util/IntSet.java
Normal file
127
src/main/java/org/xbib/jacc/util/IntSet.java
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
package org.xbib.jacc.util;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Writer;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class IntSet {
|
||||||
|
|
||||||
|
private int[] elems;
|
||||||
|
private int used;
|
||||||
|
|
||||||
|
private IntSet() {
|
||||||
|
elems = new int[1];
|
||||||
|
used = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IntSet empty() {
|
||||||
|
return new IntSet();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IntSet singleton(int i) {
|
||||||
|
IntSet intset = new IntSet();
|
||||||
|
intset.add(i);
|
||||||
|
return intset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int size() {
|
||||||
|
return used;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int at(int i) {
|
||||||
|
return elems[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] toArray() {
|
||||||
|
int[] ai = new int[used];
|
||||||
|
System.arraycopy(elems, 0, ai, 0, used);
|
||||||
|
return ai;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean contains(int i) {
|
||||||
|
int j = 0;
|
||||||
|
for (int k = used; j < k; ) {
|
||||||
|
int l = j + ((k - j) / 2);
|
||||||
|
int i1 = elems[l];
|
||||||
|
if (i == i1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (i < i1) {
|
||||||
|
k = l;
|
||||||
|
} else {
|
||||||
|
j = l + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void add(int i) {
|
||||||
|
int j = 0;
|
||||||
|
for (int k = used; j < k; ) {
|
||||||
|
int l = j + ((k - j) / 2);
|
||||||
|
int j1 = elems[l];
|
||||||
|
if (i < j1) {
|
||||||
|
k = l;
|
||||||
|
} else {
|
||||||
|
if (i == j1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
j = l + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (used >= elems.length) {
|
||||||
|
int[] ai = new int[elems.length * 2];
|
||||||
|
System.arraycopy(elems, 0, ai, 0, j);
|
||||||
|
ai[j] = i;
|
||||||
|
System.arraycopy(elems, j, ai, j + 1, used - j);
|
||||||
|
elems = ai;
|
||||||
|
} else {
|
||||||
|
System.arraycopy(elems, j, elems, j + 1, used - j);
|
||||||
|
elems[j] = i;
|
||||||
|
}
|
||||||
|
used++;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (!(o instanceof IntSet)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
IntSet intset = (IntSet) o;
|
||||||
|
if (used == intset.used) {
|
||||||
|
for (int i = 0; i < used; i++) {
|
||||||
|
if (elems[i] != intset.elems[i]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Arrays.hashCode(elems);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Interator interator() {
|
||||||
|
return new ElemInterator(elems, 0, used);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void display(Writer writer) throws IOException {
|
||||||
|
Interator interator1 = interator();
|
||||||
|
writer.write("{");
|
||||||
|
for (int i = 0; interator1.hasNext(); i++) {
|
||||||
|
if (i != 0) {
|
||||||
|
writer.write(", ");
|
||||||
|
}
|
||||||
|
writer.write(interator1.next());
|
||||||
|
}
|
||||||
|
writer.write("}");
|
||||||
|
writer.write(": used = " + used + ", length = " + elems.length + "\n");
|
||||||
|
}
|
||||||
|
}
|
11
src/main/java/org/xbib/jacc/util/Interator.java
Normal file
11
src/main/java/org/xbib/jacc/util/Interator.java
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
package org.xbib.jacc.util;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public abstract class Interator {
|
||||||
|
|
||||||
|
public abstract int next();
|
||||||
|
|
||||||
|
public abstract boolean hasNext();
|
||||||
|
}
|
141
src/main/java/org/xbib/jacc/util/SCC.java
Normal file
141
src/main/java/org/xbib/jacc/util/SCC.java
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
package org.xbib.jacc.util;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class SCC {
|
||||||
|
|
||||||
|
public static int[][] get(int[][] ai, int[][] ai1, int i) {
|
||||||
|
return new GetComponents(ai, i, new ArrangeByFinish(ai1, i).getFinishOrder()).getComponents();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int[][] get(int[][] ai) {
|
||||||
|
return get(ai, invert(ai), ai.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int[][] invert(int[][] ai) {
|
||||||
|
return invert(ai, ai.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int[][] invert(int[][] ai, int i) {
|
||||||
|
int[] ai1 = new int[i];
|
||||||
|
for (int j = 0; j < i; j++) {
|
||||||
|
for (int k = 0; k < ai[j].length; k++) {
|
||||||
|
ai1[ai[j][k]]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int[][] ai2 = new int[i][];
|
||||||
|
for (int l = 0; l < i; l++) {
|
||||||
|
ai2[l] = new int[ai1[l]];
|
||||||
|
}
|
||||||
|
for (int i1 = 0; i1 < i; i1++) {
|
||||||
|
for (int j1 = 0; j1 < ai[i1].length; j1++) {
|
||||||
|
int k1 = ai[i1][j1];
|
||||||
|
ai1[k1]--;
|
||||||
|
ai2[k1][ai1[k1]] = i1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ai2;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class GetComponents extends DepthFirst {
|
||||||
|
|
||||||
|
private int numComps;
|
||||||
|
private int[] compNo;
|
||||||
|
|
||||||
|
GetComponents(int[][] ai, int i, int[] ai1) {
|
||||||
|
super(new ElemInterator(ai1), ai);
|
||||||
|
numComps = 0;
|
||||||
|
compNo = new int[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
void doneVisit(int i) {
|
||||||
|
compNo[i] = numComps;
|
||||||
|
}
|
||||||
|
|
||||||
|
void doneTree() {
|
||||||
|
numComps++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int[][] getComponents() {
|
||||||
|
search();
|
||||||
|
int[] ai = new int[numComps];
|
||||||
|
for (int aCompNo : compNo) {
|
||||||
|
ai[aCompNo]++;
|
||||||
|
}
|
||||||
|
int ai1[][] = new int[numComps][];
|
||||||
|
for (int j = 0; j < numComps; j++) {
|
||||||
|
ai1[j] = new int[ai[j]];
|
||||||
|
}
|
||||||
|
for (int k = 0; k < compNo.length; k++) {
|
||||||
|
int l = compNo[k];
|
||||||
|
ai1[l][--ai[l]] = k;
|
||||||
|
}
|
||||||
|
return ai1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ArrangeByFinish extends DepthFirst {
|
||||||
|
private int dfsNum;
|
||||||
|
private int[] order;
|
||||||
|
|
||||||
|
ArrangeByFinish(int[][] ai, int i) {
|
||||||
|
super(new SeqInterator(0, i), ai);
|
||||||
|
dfsNum = i;
|
||||||
|
order = new int[dfsNum];
|
||||||
|
}
|
||||||
|
|
||||||
|
void doneVisit(int i) {
|
||||||
|
order[--dfsNum] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
int[] getFinishOrder() {
|
||||||
|
search();
|
||||||
|
return order;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract static class DepthFirst {
|
||||||
|
|
||||||
|
private Interator seq;
|
||||||
|
private int[][] adjs;
|
||||||
|
private int[] visited;
|
||||||
|
|
||||||
|
DepthFirst(Interator interator, int[][] ai) {
|
||||||
|
seq = interator;
|
||||||
|
adjs = ai;
|
||||||
|
visited = BitSet.make(ai.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
void search() {
|
||||||
|
do {
|
||||||
|
if (!seq.hasNext()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (visit(seq.next())) {
|
||||||
|
doneTree();
|
||||||
|
}
|
||||||
|
} while (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean visit(int i) {
|
||||||
|
if (BitSet.addTo(visited, i)) {
|
||||||
|
int[] ai = adjs[i];
|
||||||
|
for (int j : ai) {
|
||||||
|
visit(j);
|
||||||
|
}
|
||||||
|
doneVisit(i);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void doneVisit(int i) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void doneTree() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
23
src/main/java/org/xbib/jacc/util/SeqInterator.java
Normal file
23
src/main/java/org/xbib/jacc/util/SeqInterator.java
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
package org.xbib.jacc.util;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class SeqInterator extends Interator {
|
||||||
|
|
||||||
|
private int count;
|
||||||
|
private int limit;
|
||||||
|
|
||||||
|
SeqInterator(int i, int j) {
|
||||||
|
count = i;
|
||||||
|
limit = j;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int next() {
|
||||||
|
return count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasNext() {
|
||||||
|
return count < limit;
|
||||||
|
}
|
||||||
|
}
|
4
src/main/java/org/xbib/jacc/util/package-info.java
Normal file
4
src/main/java/org/xbib/jacc/util/package-info.java
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
/**
|
||||||
|
* Utility classes.
|
||||||
|
*/
|
||||||
|
package org.xbib.jacc.util;
|
165
src/site/resources/Calc.jacc
Normal file
165
src/site/resources/Calc.jacc
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
// To compile and run this program using jacc and Sun's JDK:
|
||||||
|
//
|
||||||
|
// In a directory containing only the file Calc.jacc:
|
||||||
|
//
|
||||||
|
// jacc Calc.jacc
|
||||||
|
// javac *.java
|
||||||
|
// java CalcParser
|
||||||
|
// ... enter arithmetic expressions ... hit EOF to terminate
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
%{
|
||||||
|
abstract class Expr {
|
||||||
|
abstract int eval();
|
||||||
|
}
|
||||||
|
|
||||||
|
class IntExpr extends Expr {
|
||||||
|
private int value;
|
||||||
|
IntExpr(int value) { this.value = value; }
|
||||||
|
int eval() { return value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class BinExpr extends Expr {
|
||||||
|
protected Expr left, right;
|
||||||
|
BinExpr(Expr left, Expr right) {
|
||||||
|
this.left = left; this.right = right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AddExpr extends BinExpr {
|
||||||
|
AddExpr(Expr left, Expr right) { super(left, right); }
|
||||||
|
int eval() { return left.eval() + right.eval(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
class SubExpr extends BinExpr {
|
||||||
|
SubExpr(Expr left, Expr right) { super(left, right); }
|
||||||
|
int eval() { return left.eval() - right.eval(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
class MulExpr extends BinExpr {
|
||||||
|
MulExpr(Expr left, Expr right) { super(left, right); }
|
||||||
|
int eval() { return left.eval() * right.eval(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
class DivExpr extends BinExpr {
|
||||||
|
DivExpr(Expr left, Expr right) { super(left, right); }
|
||||||
|
int eval() { return left.eval() / right.eval(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
class CalcLexer implements CalcTokens {
|
||||||
|
private int c = ' ';
|
||||||
|
|
||||||
|
/** Read a single input character from standard input.
|
||||||
|
*/
|
||||||
|
private void nextChar() {
|
||||||
|
if (c>=0) {
|
||||||
|
try {
|
||||||
|
c = System.in.read();
|
||||||
|
} catch (Exception e) {
|
||||||
|
c = (-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int token;
|
||||||
|
private IntExpr yylval;
|
||||||
|
|
||||||
|
/** Read the next token and return the
|
||||||
|
* corresponding integer code.
|
||||||
|
*/
|
||||||
|
int nextToken() {
|
||||||
|
for (;;) {
|
||||||
|
// Skip whitespace
|
||||||
|
while (c==' ' || c=='\n' || c=='\t' || c=='\r') {
|
||||||
|
nextChar();
|
||||||
|
}
|
||||||
|
if (c<0) {
|
||||||
|
return (token=ENDINPUT);
|
||||||
|
}
|
||||||
|
switch (c) {
|
||||||
|
case '+' : nextChar();
|
||||||
|
return token='+';
|
||||||
|
case '-' : nextChar();
|
||||||
|
return token='-';
|
||||||
|
case '*' : nextChar();
|
||||||
|
return token='*';
|
||||||
|
case '/' : nextChar();
|
||||||
|
return token='/';
|
||||||
|
case '(' : nextChar();
|
||||||
|
return token='(';
|
||||||
|
case ')' : nextChar();
|
||||||
|
return token=')';
|
||||||
|
case ';' : nextChar();
|
||||||
|
return token=';';
|
||||||
|
default : if (Character.isDigit((char)c)) {
|
||||||
|
int n = 0;
|
||||||
|
do {
|
||||||
|
n = 10*n + (c - '0');
|
||||||
|
nextChar();
|
||||||
|
} while (Character.isDigit((char)c));
|
||||||
|
yylval = new IntExpr(n);
|
||||||
|
return token=INTEGER;
|
||||||
|
} else {
|
||||||
|
Main.error("Illegal character "+c);
|
||||||
|
nextChar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return the token code for the current lexeme.
|
||||||
|
*/
|
||||||
|
int getToken() {
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return the semantic value for the current lexeme.
|
||||||
|
*/
|
||||||
|
IntExpr getSemantic() {
|
||||||
|
return yylval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Main {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
CalcLexer lexer = new CalcLexer();
|
||||||
|
lexer.nextToken();
|
||||||
|
CalcParser parser = new CalcParser(lexer);
|
||||||
|
parser.parse();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void error(String msg) {
|
||||||
|
System.out.println("ERROR: " + msg);
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
%}
|
||||||
|
|
||||||
|
%semantic Expr
|
||||||
|
%token '+' '-' '*' '/' '(' ')' ';' INTEGER
|
||||||
|
%left '+' '-'
|
||||||
|
%left '*' '/'
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
prog : prog ';' expr { System.out.println($3.eval()); }
|
||||||
|
| expr { System.out.println($1.eval()); }
|
||||||
|
;
|
||||||
|
expr : expr '+' expr { $$ = new AddExpr($1, $3); }
|
||||||
|
| expr '-' expr { $$ = new SubExpr($1, $3); }
|
||||||
|
| expr '*' expr { $$ = new MulExpr($1, $3); }
|
||||||
|
| expr '/' expr { $$ = new DivExpr($1, $3); }
|
||||||
|
| '(' expr ')' { $$ = $2; }
|
||||||
|
| INTEGER { $$ = $1; }
|
||||||
|
;
|
||||||
|
|
||||||
|
%%
|
||||||
|
private CalcLexer lexer;
|
||||||
|
|
||||||
|
CalcParser(CalcLexer lexer) { this.lexer = lexer; }
|
||||||
|
|
||||||
|
private void yyerror(String msg) {
|
||||||
|
Main.error(yyerrno<0 ? msg : yyerrmsgs[yyerrno]);
|
||||||
|
}
|
||||||
|
|
232
src/site/resources/Layer2.jacc
Normal file
232
src/site/resources/Layer2.jacc
Normal file
|
@ -0,0 +1,232 @@
|
||||||
|
%{
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright (C) 2006 David Massart and Chea Sereyvath, European Schoolnet
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.lang.String;
|
||||||
|
import java.util.StringTokenizer;
|
||||||
|
%}
|
||||||
|
|
||||||
|
%token NL /* newline */
|
||||||
|
%token <sval> AND /* Second kind of keyword */
|
||||||
|
%token <sval> LEFT_PATENTHESIS /* Second kind of keyword */
|
||||||
|
%token <sval> RIGHT_PATENTHESIS /* Second kind of keyword */
|
||||||
|
%token <sval> CHARSTRING1 /* First kind of keyword */
|
||||||
|
%token <sval> CHARSTRING2 /* Second kind of keyword */
|
||||||
|
%token <sval> DOT /* Dot signe*/
|
||||||
|
%token <sval> OPERATORS /* the operator between the signs */
|
||||||
|
%token <sval> STANDARD /* the standard to use */
|
||||||
|
%token <ival> INTEGER /* Integer number */
|
||||||
|
%token <dval> REAL /* real number */
|
||||||
|
|
||||||
|
/* The type of rules*/
|
||||||
|
%type <sval> plql
|
||||||
|
%type <sval> clause
|
||||||
|
%type <sval> keywordClause
|
||||||
|
%type <sval> operand
|
||||||
|
%type <sval> term1
|
||||||
|
%type <sval> term2
|
||||||
|
%type <sval> charString1
|
||||||
|
%type <sval> charString2
|
||||||
|
%type <sval> integer
|
||||||
|
%type <sval> real
|
||||||
|
|
||||||
|
%type <sval> exactClause
|
||||||
|
%type <sval> path
|
||||||
|
%type <sval> operator
|
||||||
|
%type <sval> standard
|
||||||
|
|
||||||
|
%type <sval> pathExp
|
||||||
|
%type <sval> selector
|
||||||
|
%type <sval> standard
|
||||||
|
|
||||||
|
%start plql
|
||||||
|
|
||||||
|
|
||||||
|
%%
|
||||||
|
/* rule 2-1 */
|
||||||
|
plql: clause { $$ = "rule number = 2-1 : " + $1;
|
||||||
|
query = $$;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
/* rule 2-2 */
|
||||||
|
clause: keywordClause {
|
||||||
|
System.out.println("rule number = 2-2.1 : " + $1);
|
||||||
|
}
|
||||||
|
|standard DOT exactClause {
|
||||||
|
$1 = $1 + "." + $3;
|
||||||
|
System.out.println("rule number = 2-2.2 : " + $1);
|
||||||
|
}
|
||||||
|
|LEFT_PATENTHESIS clause RIGHT_PATENTHESIS {
|
||||||
|
$1 = " ( " + $2 + " ) ";
|
||||||
|
System.out.println("rule number = 2-2.3 : " + $1);
|
||||||
|
}
|
||||||
|
|clause AND clause {
|
||||||
|
$1 = $1 + " and " + $3;
|
||||||
|
System.out.println("rule number = 2-2.4 : " + $1);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
/* rule 2-3 */
|
||||||
|
keywordClause: operand {
|
||||||
|
System.out.println("rule number = 2-3 : " + $1);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
/* rule 2-4 */
|
||||||
|
operand: term1 {
|
||||||
|
System.out.println("rule number = 2-4.1 : " + $1);
|
||||||
|
}
|
||||||
|
|term2 {
|
||||||
|
System.out.println("rule number = 2-4.2 : " + $1);
|
||||||
|
}
|
||||||
|
|integer {
|
||||||
|
System.out.println("rule number = 2-4.3 : " + $1);
|
||||||
|
}
|
||||||
|
|real {
|
||||||
|
System.out.println("rule number = 2-4.4 : " + $1);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
/* rule 2-5 */
|
||||||
|
term1: charString1 {
|
||||||
|
System.out.println("rule number = 2-5 : " + $1);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
/* rule 2-6 */
|
||||||
|
term2: charString2 {
|
||||||
|
System.out.println("rule number = 2-6 : " + $1);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
/* rule 2-7 */
|
||||||
|
charString1: CHARSTRING1 {
|
||||||
|
System.out.println("rule number = 2-7 : " + $1);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
/* rule 2-8 */
|
||||||
|
charString2: CHARSTRING2 {
|
||||||
|
System.out.println("rule number = 2-8 : " + $1);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
/* rule 2-9 */
|
||||||
|
integer: INTEGER {
|
||||||
|
System.out.println("rule number = 2-9 : " + $1);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
/* rule 2-10 */
|
||||||
|
real: REAL {
|
||||||
|
System.out.println("rule number = 2-10 : " + $1);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
/* rule 2-11 */
|
||||||
|
exactClause: path OPERATORS operand {
|
||||||
|
$1 = $1 + " " + $2 + " " + $3;
|
||||||
|
System.out.println("rule number = 2-11.1 : " + $1 );
|
||||||
|
}
|
||||||
|
|pathExp {
|
||||||
|
System.out.println("rule number = 2-11.2 : " + $1 );
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
/* rule 2-12 */
|
||||||
|
path: term1 {
|
||||||
|
System.out.println("rule number = 2-12.1 : " + $1);
|
||||||
|
}
|
||||||
|
|path DOT path {
|
||||||
|
$1 = $1 + $2 + $3;
|
||||||
|
System.out.println("rule number = 2-12.2 : " + $1);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
/* rule 2-13 */
|
||||||
|
operator: OPERATORS {
|
||||||
|
System.out.println("rule number = 2-13 : " + $1);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
/* rule 2-14 */
|
||||||
|
standard: STANDARD {
|
||||||
|
System.out.println("rule number = 2-14.1 : " + $1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|term1 {
|
||||||
|
System.out.println("rule number = 2-14.2 : " + $1);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
/* rule 2-15 */
|
||||||
|
pathExp: path DOT pathExp{
|
||||||
|
$1 = $1 + $2 + $3 ;
|
||||||
|
System.out.println("rule number = 2-15.1 : " + $1);
|
||||||
|
}
|
||||||
|
|path DOT LEFT_PATENTHESIS selector AND selector RIGHT_PATENTHESIS {
|
||||||
|
$1 = $1 + $2 + $3 + " " + $4 + $5 + $6 + " " + $7;
|
||||||
|
System.out.println("rule number = 2-15.2 : " + $1);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
/* rule 2-16 */
|
||||||
|
selector: term1 OPERATORS operand {
|
||||||
|
$1 = $1 + " " + $2 + " " + $3;
|
||||||
|
System.out.println("rule number = 2-16.1 : "+ $1);
|
||||||
|
}
|
||||||
|
|selector AND selector {
|
||||||
|
$1 = $1 + " " + $2 + " " + $3 ;
|
||||||
|
System.out.println("rule number = 2-16.2 : "+ $1);
|
||||||
|
}
|
||||||
|
|LEFT_PATENTHESIS selector RIGHT_PATENTHESIS {
|
||||||
|
$1 = $1 + " " + $2 + " " + $3 ;
|
||||||
|
System.out.println("rule number = 2-16.3 : " + $1);
|
||||||
|
}
|
||||||
|
|LEFT_PATENTHESIS selector AND selector RIGHT_PATENTHESIS {
|
||||||
|
$1 = $1 + " " + $2 + " " + $3 + " " + $4 + " " + $5 ;
|
||||||
|
System.out.println("rule number = 2-16.4 : " + $1);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
private PlqlLayer2Parser lexer;
|
||||||
|
private String query ;
|
||||||
|
|
||||||
|
private int yylex () {
|
||||||
|
int yyl_return = -1;
|
||||||
|
try {
|
||||||
|
yylval = new PlqlLayer2AnalyzerVal(0);
|
||||||
|
yyl_return = lexer.yylex();
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
System.err.println("IO error :"+e);
|
||||||
|
}
|
||||||
|
return yyl_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void yyerror (String error) {
|
||||||
|
System.err.println ("Syntax Error\n" + error);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlqlLayer2Analyzer(Reader r) {/***/
|
||||||
|
lexer = new PlqlLayer2Parser(r, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getQuery()
|
||||||
|
{
|
||||||
|
return query ;
|
||||||
|
}
|
29
src/site/resources/Unary.jacc
Normal file
29
src/site/resources/Unary.jacc
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
// This file contains an extension to the calculator program in Calc.jacc
|
||||||
|
// that adds support for unary minus. It is intended as a simple example
|
||||||
|
// to illustrate jacc's ability to take input from multiple files.
|
||||||
|
//
|
||||||
|
// To compile and run this program using jacc and Sun's JDK:
|
||||||
|
//
|
||||||
|
// In a directory containing only the files Calc.jacc and Unary.jacc:
|
||||||
|
//
|
||||||
|
// jacc Calc.jacc Unary.jacc
|
||||||
|
// javac *.java
|
||||||
|
// java Calc
|
||||||
|
// ... enter arithmetic expressions ... hit EOF to terminate
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
%{
|
||||||
|
class UminusExpr extends Expr {
|
||||||
|
private Expr expr;
|
||||||
|
UminusExpr(Expr expr) { this.expr = expr; }
|
||||||
|
int eval() { return -expr.eval(); }
|
||||||
|
}
|
||||||
|
%}
|
||||||
|
|
||||||
|
%left UMINUS
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
expr : '-' expr %prec UMINUS { $$ = new UminusExpr($2); }
|
||||||
|
;
|
7
src/site/resources/dang.ex
Normal file
7
src/site/resources/dang.ex
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
|
||||||
|
IF expr THEN
|
||||||
|
IF expr THEN
|
||||||
|
stmt
|
||||||
|
ELSE
|
||||||
|
stmt
|
||||||
|
|
7
src/site/resources/dang.jacc
Normal file
7
src/site/resources/dang.jacc
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
%token IF THEN ELSE expr other
|
||||||
|
%%
|
||||||
|
stmt : IF expr THEN stmt ELSE stmt
|
||||||
|
| IF expr THEN stmt
|
||||||
|
| other
|
||||||
|
;
|
||||||
|
|
4
src/site/resources/example1
Normal file
4
src/site/resources/example1
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
INTEGER '+' INTEGER '*' INTEGER ';'
|
||||||
|
INTEGER '*' INTEGER '+' INTEGER
|
||||||
|
|
4
src/site/resources/example2
Normal file
4
src/site/resources/example2
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
expr '+' expr '*' expr ';'
|
||||||
|
expr '*' expr '+' expr
|
||||||
|
|
BIN
src/site/resources/jacc.pdf
Normal file
BIN
src/site/resources/jacc.pdf
Normal file
Binary file not shown.
104
src/site/resources/simpleCalc.jacc
Normal file
104
src/site/resources/simpleCalc.jacc
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
// To compile and run this program using jacc and Sun's JDK:
|
||||||
|
//
|
||||||
|
// jacc simpleCalc.jacc
|
||||||
|
// javac Calc.java CalcTokens.java
|
||||||
|
// java Calc
|
||||||
|
// ... enter arithmetic expressions ... hit EOF to terminate
|
||||||
|
//
|
||||||
|
|
||||||
|
%class Calc
|
||||||
|
%interface CalcTokens
|
||||||
|
%semantic int : yylval
|
||||||
|
%get token
|
||||||
|
%next yylex()
|
||||||
|
|
||||||
|
%token '+' '-' '*' '/' '(' ')' ';' INTEGER
|
||||||
|
%left '+' '-'
|
||||||
|
%left '*' '/'
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
prog : prog ';' expr { System.out.println($3); }
|
||||||
|
| expr { System.out.println($1); }
|
||||||
|
;
|
||||||
|
expr : expr '+' expr { $$ = $1 + $3; }
|
||||||
|
| expr '-' expr { $$ = $1 - $3; }
|
||||||
|
| expr '*' expr { $$ = $1 * $3; }
|
||||||
|
| expr '/' expr { $$ = $1 / $3; }
|
||||||
|
| '(' expr ')' { $$ = $2; }
|
||||||
|
| INTEGER { $$ = $1; }
|
||||||
|
;
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
private void yyerror(String msg) {
|
||||||
|
System.out.println("ERROR: " + msg);
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int c;
|
||||||
|
|
||||||
|
/** Read a single input character from standard input.
|
||||||
|
*/
|
||||||
|
private void nextChar() {
|
||||||
|
if (c>=0) {
|
||||||
|
try {
|
||||||
|
c = System.in.read();
|
||||||
|
} catch (Exception e) {
|
||||||
|
c = (-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int token;
|
||||||
|
int yylval;
|
||||||
|
|
||||||
|
/** Read the next token and return the
|
||||||
|
* corresponding integer code.
|
||||||
|
*/
|
||||||
|
int yylex() {
|
||||||
|
for (;;) {
|
||||||
|
// Skip whitespace
|
||||||
|
while (c==' ' || c=='\n' || c=='\t' || c=='\r') {
|
||||||
|
nextChar();
|
||||||
|
}
|
||||||
|
if (c<0) {
|
||||||
|
return (token=ENDINPUT);
|
||||||
|
}
|
||||||
|
switch (c) {
|
||||||
|
case '+' : nextChar();
|
||||||
|
return token='+';
|
||||||
|
case '-' : nextChar();
|
||||||
|
return token='-';
|
||||||
|
case '*' : nextChar();
|
||||||
|
return token='*';
|
||||||
|
case '/' : nextChar();
|
||||||
|
return token='/';
|
||||||
|
case '(' : nextChar();
|
||||||
|
return token='(';
|
||||||
|
case ')' : nextChar();
|
||||||
|
return token=')';
|
||||||
|
case ';' : nextChar();
|
||||||
|
return token=';';
|
||||||
|
default : if (Character.isDigit((char)c)) {
|
||||||
|
int n = 0;
|
||||||
|
do {
|
||||||
|
n = 10*n + (c - '0');
|
||||||
|
nextChar();
|
||||||
|
} while (Character.isDigit((char)c));
|
||||||
|
yylval = n;
|
||||||
|
return token=INTEGER;
|
||||||
|
} else {
|
||||||
|
yyerror("Illegal character "+c);
|
||||||
|
nextChar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
Calc calc = new Calc();
|
||||||
|
calc.nextChar(); // prime the character input stream
|
||||||
|
calc.yylex(); // prime the token input stream
|
||||||
|
calc.parse(); // parse the input
|
||||||
|
}
|
Loading…
Reference in a new issue