Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Alexandru Dura
SPPF Earley Parser
Commits
c5e65f59
Commit
c5e65f59
authored
Jan 27, 2020
by
Alexandru Dura
Browse files
Scott's parser processing empty productions
parent
6c2c218f
Changes
4
Hide whitespace changes
Inline
Side-by-side
src/main/java/EarleyParser.java
View file @
c5e65f59
import
javax.swing.plaf.nimbus.State
;
import
java.io.File
;
import
java.io.FileNotFoundException
;
import
java.io.PrintStream
;
import
java.util.ArrayList
;
import
java.util.Collection
;
import
java.util.HashMap
;
...
...
@@ -181,7 +185,7 @@ public class EarleyParser implements PrettyPrintingInfo {
for
(
int
i
=
0
;
i
<
s
.
length
+
1
;
++
i
)
{
System
.
out
.
println
(
"=== Item set at position "
+
i
+
" ==="
);
for
(
EarleyItem
item
:
state
[
i
])
{
if
(
item
.
isComplete
())
if
(
true
||
item
.
isComplete
())
System
.
out
.
println
(
item
.
prettyPrint
(
this
));
}
}
...
...
@@ -189,13 +193,26 @@ public class EarleyParser implements PrettyPrintingInfo {
StateSet
finalState
=
state
[
s
.
length
];
System
.
out
.
println
(
"==========================="
);
boolean
recognized
=
false
;
int
count
=
0
;
for
(
EarleyItem
item
:
finalState
)
{
if
(
item
.
isComplete
()
&&
item
.
start
==
0
&&
item
.
rule
.
r
.
head
==
start
)
{
return
true
;
try
{
PrintStream
out
=
new
PrintStream
(
new
File
(
"sppf_"
+
count
++
+
".dot"
));
DotVisitor
visitor
=
new
DotVisitor
(
out
,
this
);
visitor
.
prologue
();
item
.
getSPPF
().
accept
(
visitor
);
visitor
.
epilogue
();
}
catch
(
FileNotFoundException
e
)
{
// TODO Auto-generated catch block
e
.
printStackTrace
();
}
recognized
=
true
;
}
}
return
false
;
return
recognized
;
}
public
void
parse
(
Category
s
[],
Category
startSymbol
)
{
...
...
@@ -217,7 +234,8 @@ public class EarleyParser implements PrettyPrintingInfo {
HashMap
<
NodeLabel
,
SPPFNode
>
V
=
new
HashMap
<>();
for
(
EarleyRule
r
:
rules
.
get
(
startSymbol
))
{
state
[
0
].
add
(
new
EarleyItem
(
r
,
0
));
if
(
r
.
startsWithNonTerminal
())
state
[
0
].
add
(
new
EarleyItem
(
r
,
0
));
if
(!
r
.
isEmpty
()
&&
r
.
body
[
0
]
==
symbols
[
0
])
{
Q_next
.
add
(
new
EarleyItem
(
r
,
0
));
}
...
...
@@ -239,8 +257,7 @@ public class EarleyParser implements PrettyPrintingInfo {
if
(
state
[
i
].
add
(
C
))
{
R
.
add
(
C
);
}
}
if
(
r
.
body
[
0
]
==
symbols
[
i
])
{
// 1.1.2
}
else
if
(
r
.
body
[
0
]
==
symbols
[
i
])
{
// 1.1.2
assert
!
r
.
startsWithNonTerminal
();
Q
.
add
(
C
);
}
...
...
@@ -278,21 +295,25 @@ public class EarleyParser implements PrettyPrintingInfo {
H
.
put
(
Lambda
.
rule
.
r
.
head
,
Lambda
.
getSPPF
());
}
HashSet
<
EarleyItem
>
RTemp
=
new
HashSet
<>();
// this is needed to avoid concurrent modification which occurs when Lambda.start == i
for
(
EarleyItem
item
:
state
[
Lambda
.
start
])
{
// 2.3
if
(!
item
.
isComplete
()
&&
item
.
afterDot
()
==
Lambda
.
rule
.
r
.
head
)
{
EarleyItem
itemNext
=
item
.
advance
();
SPPFNode
y
=
makeNode
(
itemNext
.
getDottedRule
(),
itemNext
.
start
,
i
,
item
.
getSPPF
(),
Lambda
.
getSPPF
(),
V
);
// EarleyItem newItem = new EarleyItem(itemNext.rule, itemNext.start);
itemNext
.
setSPPF
(
y
);
if
(
itemNext
.
isComplete
()
||
!
isTerminal
(
itemNext
.
afterDot
()))
{
// 2.3.1
if
(
state
[
i
].
add
(
itemNext
))
{
// 2.3.1
R
.
add
(
itemNext
);
// assert i != Lambda.start;
if
(!
state
[
i
].
contains
(
itemNext
))
{
// 2.3.1
RTemp
.
add
(
itemNext
);
}
}
else
if
(
itemNext
.
afterDot
()
==
symbols
[
i
])
{
// 2.3.2
Q
.
add
(
itemNext
);
}
}
}
R
.
addAll
(
RTemp
);
state
[
i
].
addAll
(
RTemp
);
}
}
...
...
src/main/java/Rule.java
View file @
c5e65f59
...
...
@@ -7,7 +7,7 @@ public class Rule {
public
Rule
(
Category
head
,
Category
...
body
)
{
this
.
head
=
head
;
assert
body
.
length
>
0
;
//
assert body.length > 0;
this
.
body
=
body
;
}
...
...
src/main/java/SPPFNode.java
View file @
c5e65f59
import
java.io.PrintStream
;
import
java.util.ArrayList
;
import
java.util.HashMap
;
import
java.util.HashSet
;
import
java.util.List
;
...
...
@@ -42,9 +44,13 @@ public class SPPFNode {
return
false
;
return
true
;
}
public
void
accept
(
SPPFNodeVisitor
visitor
)
{
visitor
.
visit
(
this
);
}
}
private
HashSet
<
FamilyNode
>
children
=
new
HashSet
<>();
HashSet
<
FamilyNode
>
children
=
new
HashSet
<>();
private
NodeLabel
label
;
public
SPPFNode
()
{
...
...
@@ -70,8 +76,77 @@ public class SPPFNode {
public
String
prettyPrint
(
PrettyPrintingInfo
info
)
{
return
label
.
prettyPrint
(
info
);
}
public
void
accept
(
SPPFNodeVisitor
visitor
)
{
visitor
.
visit
(
this
);
}
}
interface
SPPFNodeVisitor
{
public
void
visit
(
SPPFNode
.
FamilyNode
familyNode
);
public
void
visit
(
SPPFNode
n
);
}
class
DotVisitor
implements
SPPFNodeVisitor
{
private
PrintStream
ps
;
private
int
nodeID
=
0
;
private
HashMap
<
SPPFNode
,
Integer
>
visitedNodes
=
new
HashMap
<>();
private
HashMap
<
SPPFNode
.
FamilyNode
,
Integer
>
visitedFamilies
=
new
HashMap
<>();
private
PrettyPrintingInfo
info
;
public
DotVisitor
(
PrintStream
ps
,
PrettyPrintingInfo
info
)
{
this
.
info
=
info
;
this
.
ps
=
ps
;
}
public
void
prologue
()
{
ps
.
println
(
"digraph G {"
);
}
public
void
epilogue
()
{
ps
.
println
(
"}"
);
}
@Override
public
void
visit
(
SPPFNode
.
FamilyNode
f
)
{
if
(
visitedFamilies
.
containsKey
(
f
))
return
;
int
currentID
=
nodeID
++;
visitedFamilies
.
put
(
f
,
currentID
);
if
(
f
.
child1
==
null
)
{
// epsilon
ps
.
print
(
currentID
+
" [label=\u03b5];\n"
);
}
else
{
ps
.
print
(
currentID
+
" [shape=circle];\n"
);
f
.
child1
.
accept
(
this
);
if
(
f
.
child2
!=
null
)
{
f
.
child2
.
accept
(
this
);
}
}
if
(
f
.
child1
!=
null
)
ps
.
print
(
currentID
+
" -> "
+
visitedNodes
.
get
(
f
.
child1
)
+
";\n"
);
if
(
f
.
child2
!=
null
)
ps
.
print
(
currentID
+
" -> "
+
visitedNodes
.
get
(
f
.
child2
)
+
";\n"
);
}
@Override
public
void
visit
(
SPPFNode
n
)
{
if
(
visitedNodes
.
containsKey
(
n
))
return
;
int
currentID
=
nodeID
++;
visitedNodes
.
put
(
n
,
currentID
);
ps
.
print
(
currentID
+
" [shape=box,label=\""
+
n
.
prettyPrint
(
info
)
+
"\"];\n"
);
for
(
SPPFNode
.
FamilyNode
f
:
n
.
children
)
{
f
.
accept
(
this
);
ps
.
print
(
currentID
+
" -> "
+
visitedFamilies
.
get
(
f
)
+
";\n"
);
}
}
}
src/test/java/EarleyParserTest.java
View file @
c5e65f59
...
...
@@ -90,4 +90,50 @@ public class EarleyParserTest {
EarleyParser
parser
=
makeAmbiguousParser
();
assertTrue
(
parser
.
recognize
(
str
,
s
));
}
@Test
public
void
testScottExample2
()
{
EarleyParser
parser
=
new
EarleyParser
();
Category
S
=
new
Category
(
"S"
,
false
);
Category
b
=
new
Category
(
"b"
,
true
);
parser
.
addCategory
(
S
);
parser
.
addCategory
(
b
);
parser
.
addRule
(
new
Rule
(
S
,
S
,
S
));
parser
.
addRule
(
new
Rule
(
S
,
b
));
parser
.
done
();
Category
str
[]
=
{
b
,
b
,
b
};
assertTrue
(
parser
.
recognize
(
str
,
S
));
}
@Test
public
void
testScottExample3
()
{
EarleyParser
parser
=
new
EarleyParser
();
Category
S
=
new
Category
(
"S"
,
false
);
Category
A
=
new
Category
(
"A"
,
false
);
Category
B
=
new
Category
(
"B"
,
false
);
Category
T
=
new
Category
(
"T"
,
false
);
Category
a
=
new
Category
(
"a"
,
true
);
Category
b
=
new
Category
(
"b"
,
true
);
parser
.
addCategory
(
S
);
parser
.
addCategory
(
A
);
parser
.
addCategory
(
B
);
parser
.
addCategory
(
T
);
parser
.
addCategory
(
a
);
parser
.
addCategory
(
b
);
parser
.
addRule
(
new
Rule
(
S
,
A
,
T
));
parser
.
addRule
(
new
Rule
(
S
,
a
,
T
));
parser
.
addRule
(
new
Rule
(
A
,
a
));
parser
.
addRule
(
new
Rule
(
A
,
B
,
A
));
parser
.
addRule
(
new
Rule
(
B
));
// epsilon production
parser
.
addRule
(
new
Rule
(
T
,
b
,
b
,
b
));
parser
.
done
();
Category
str
[]
=
{
a
,
b
,
b
,
b
};
assertTrue
(
parser
.
recognize
(
str
,
S
));
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment