Create a new Xcode playground for Swift.

This takes the example from
https://github.com/janyou/Antlr-Swift-Runtime/tree/master/Test and packages
it into an Xcode playground.  This allows the user to interact with the
grammar directly inside Xcode, and serves as a live demo of the Swift support.

Update the docs to match.
This commit is contained in:
Ewan Mellor 2016-12-01 01:19:52 -08:00
parent aff8cba61a
commit b0c3824357
18 changed files with 426 additions and 83 deletions

View File

@ -21,93 +21,27 @@ You will find Swift runtime (framework project) in
antlr4/runtime/Swift
```
#### 4. Example
#### 4. Example playground
The example from [here](https://github.com/janyou/Antlr-Swift-Runtime/tree/master/Test)
The Swift runtime includes an Xcode playground to get started with.
(1). Hello.g4
In Xcode, open `antlr4/runtime/Swift/Antlr4.xcworkspace`. Select
"Antlr4 OSX > My Mac" as the build target, and build the project as normal.
The playground should then be active.
The playground includes a simple grammar called "Hello", and an example for
walking the parse tree. You should see in the playground output that it is
printing messages for each node in the parse tree as it walks.
The playground shows how to create a lexer, token stream, and parser, and
how to execute the parse.
The grammar is defined in the playground's `Resources/Hello.g4`. The parser
was generated from the grammar using Antlr4 like this:
```
grammar Hello;
r : 'hello' ID ;
ID : [a-z]+ ;
WS : [ \t\r\n]+ -> skip ;
```
(2). generate lexer/parser/visitor from Hello.g4 file
```
$ antlr4 -Dlanguage=Swift -visitor -o gen Hello.g4
```
in gen folder
```
Hello.tokens
HelloBaseListener.swift
HelloBaseVisitor.swift
HelloLexer.swift
HelloLexer.tokens
HelloLexerATN.swift
HelloListener.swift
HelloParser.swift
HelloParserATN.swift
HelloVisitor.swift
```
(3). make a custom listener
```
public class HelloWalker: HelloBaseListener{
public override func enterR(_ ctx: HelloParser.RContext) {
print( "enterR: " + ((ctx.ID()?.getText()) ?? ""))
}
public override func exitR(_ ctx: HelloParser.RContext) {
print( "exitR ")
}
}
```
(4). call and run
add TestHello.txt
```
hello world
```
run:
```
import Antlr4
....
do {
let textFileName = "TestHello.txt"
if let textFilePath = Bundle.main.path(forResource: textFileName, ofType: nil) {
let lexer = HelloLexer(ANTLRFileStream(textFilePath))
let tokens = CommonTokenStream(lexer)
let parser = try HelloParser(tokens)
let tree = try parser.r()
let walker = ParseTreeWalker()
try walker.walk(HelloWalker(),tree)
} else {
print("error occur: can not open \(textFileName)")
}
}catch ANTLRException.cannotInvokeStartRule {
print("error occur: CannotInvokeStartRule")
}catch ANTLRException.recognition(let e ) {
print("error occur\(e)")
}catch {
print("error occur")
}
cd 'antlr4/runtime/Swift/Antlr4 playground.playground/Resources'
antlr4 -Dlanguage=Swift -visitor -o ../Sources/Autogen Hello.g4
```
The example tree walker is in `Sources/HelloWalker.swift`.

View File

@ -0,0 +1,23 @@
import Antlr4
var input = "hello world"
let lexer = HelloLexer(ANTLRInputStream(input))
let tokens = CommonTokenStream(lexer)
do {
let parser = try HelloParser(tokens)
let tree = try parser.r()
let walker = ParseTreeWalker()
try walker.walk(HelloWalker(), tree)
}
catch ANTLRException.cannotInvokeStartRule {
print("Error: cannot invoke start rule.")
}
catch ANTLRException.recognition(let e) {
print("Unrecoverable recognition error: \(e)")
}
catch {
print("Unknown error: \(error)")
}

View File

@ -0,0 +1,5 @@
// Define a grammar called Hello
grammar Hello;
r : 'hello' ID ; // match keyword hello followed by an identifier
ID : [a-z]+ ; // match lower-case identifiers
WS : [ \t\r\n]+ -> skip ; // skip spaces, tabs, newlines

View File

@ -0,0 +1 @@
hello world

View File

@ -0,0 +1,4 @@
T__0=1
ID=2
WS=3
'hello'=1

View File

@ -0,0 +1,50 @@
// Generated from Hello.g4 by ANTLR 4.6
import Antlr4
/**
* This class provides an empty implementation of {@link HelloListener},
* which can be extended to create a listener which only needs to handle a subset
* of the available methods.
*/
open class HelloBaseListener: HelloListener {
public init() { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
open func enterR(_ ctx: HelloParser.RContext) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
open func exitR(_ ctx: HelloParser.RContext) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
open func enterEveryRule(_ ctx: ParserRuleContext) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
open func exitEveryRule(_ ctx: ParserRuleContext) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
open func visitTerminal(_ node: TerminalNode) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
open func visitErrorNode(_ node: ErrorNode) { }
}

View File

@ -0,0 +1,20 @@
// Generated from Hello.g4 by ANTLR 4.6
import Antlr4
/**
* This class provides an empty implementation of {@link HelloVisitor},
* which can be extended to create a visitor which only needs to handle a subset
* of the available methods.
*
* @param <T> The return type of the visit operation. Use {@link Void} for
* operations with no return type.
*/
open class HelloBaseVisitor<T>: AbstractParseTreeVisitor<T> {
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
open func visitR(_ ctx: HelloParser.RContext) -> T? { return visitChildren(ctx) }
}

View File

@ -0,0 +1,84 @@
// Generated from Hello.g4 by ANTLR 4.6
import Antlr4
open class HelloLexer: Lexer {
internal static var _decisionToDFA: [DFA] = {
var decisionToDFA = [DFA]()
let length = HelloLexer._ATN.getNumberOfDecisions()
for i in 0..<length {
decisionToDFA.append(DFA(HelloLexer._ATN.getDecisionState(i)!, i))
}
return decisionToDFA
}()
internal static let _sharedContextCache:PredictionContextCache = PredictionContextCache()
public static let T__0=1, ID=2, WS=3
public static let modeNames: [String] = [
"DEFAULT_MODE"
]
public static let ruleNames: [String] = [
"T__0", "ID", "WS"
]
private static let _LITERAL_NAMES: [String?] = [
nil, "'hello'"
]
private static let _SYMBOLIC_NAMES: [String?] = [
nil, nil, "ID", "WS"
]
public static let VOCABULARY: Vocabulary = Vocabulary(_LITERAL_NAMES, _SYMBOLIC_NAMES)
/**
* @deprecated Use {@link #VOCABULARY} instead.
*/
//@Deprecated
public let tokenNames: [String?]? = {
let length = _SYMBOLIC_NAMES.count
var tokenNames = [String?](repeating: nil, count: length)
for i in 0..<length {
var name = VOCABULARY.getLiteralName(i)
if name == nil {
name = VOCABULARY.getSymbolicName(i)
}
if name == nil {
name = "<INVALID>"
}
tokenNames[i] = name
}
return tokenNames
}()
override
open func getTokenNames() -> [String?]? {
return tokenNames
}
open override func getVocabulary() -> Vocabulary {
return HelloLexer.VOCABULARY
}
public override init(_ input: CharStream) {
RuntimeMetaData.checkVersion("4.6", RuntimeMetaData.VERSION)
super.init(input)
_interp = LexerATNSimulator(self, HelloLexer._ATN, HelloLexer._decisionToDFA, HelloLexer._sharedContextCache)
}
override
open func getGrammarFileName() -> String { return "Hello.g4" }
override
open func getRuleNames() -> [String] { return HelloLexer.ruleNames }
override
open func getSerializedATN() -> String { return HelloLexer._serializedATN }
override
open func getModeNames() -> [String] { return HelloLexer.modeNames }
override
open func getATN() -> ATN { return HelloLexer._ATN }
public static let _serializedATN: String = HelloLexerATN().jsonString
public static let _ATN: ATN = ATNDeserializer().deserializeFromJson(_serializedATN)
}

View File

@ -0,0 +1,4 @@
T__0=1
ID=2
WS=3
'hello'=1

View File

@ -0,0 +1,3 @@
class HelloLexerATN {
let jsonString: String = "{\"version\":3,\"uuid\":\"aadb8d7e-aeef-4415-ad2b-8204d6cf042e\",\"grammarType\":0,\"maxTokenType\":3,\"states\":[{\"stateType\":6,\"ruleIndex\":-1},{\"stateType\":2,\"ruleIndex\":0},{\"stateType\":7,\"ruleIndex\":0},{\"stateType\":2,\"ruleIndex\":1},{\"stateType\":7,\"ruleIndex\":1},{\"stateType\":2,\"ruleIndex\":2},{\"stateType\":7,\"ruleIndex\":2},{\"stateType\":1,\"ruleIndex\":0},{\"stateType\":1,\"ruleIndex\":0},{\"stateType\":1,\"ruleIndex\":0},{\"stateType\":1,\"ruleIndex\":0},{\"stateType\":1,\"ruleIndex\":0},{\"stateType\":1,\"ruleIndex\":0},{\"stateType\":1,\"ruleIndex\":1},{\"stateType\":4,\"ruleIndex\":1,\"detailStateNumber\":15},{\"stateType\":8,\"ruleIndex\":1},{\"stateType\":11,\"ruleIndex\":1},{\"stateType\":12,\"ruleIndex\":1,\"detailStateNumber\":16},{\"stateType\":1,\"ruleIndex\":2},{\"stateType\":4,\"ruleIndex\":2,\"detailStateNumber\":20},{\"stateType\":8,\"ruleIndex\":2},{\"stateType\":11,\"ruleIndex\":2},{\"stateType\":12,\"ruleIndex\":2,\"detailStateNumber\":21},{\"stateType\":1,\"ruleIndex\":2},{\"stateType\":1,\"ruleIndex\":2}],\"nonGreedyStates\":[],\"precedenceStates\":[],\"ruleToStartState\":[{\"stateNumber\":1,\"ruleToTokenType\":1},{\"stateNumber\":3,\"ruleToTokenType\":2},{\"stateNumber\":5,\"ruleToTokenType\":3}],\"modeToStartState\":[0],\"nsets\":2,\"IntervalSet\":[{\"size\":1,\"containsEof\":0,\"Intervals\":[{\"a\":97,\"b\":122}]},{\"size\":3,\"containsEof\":0,\"Intervals\":[{\"a\":9,\"b\":10},{\"a\":13,\"b\":13},{\"a\":32,\"b\":32}]}],\"allTransitionsBuilder\":[[{\"src\":0,\"trg\":1,\"edgeType\":1,\"arg1\":0,\"arg2\":0,\"arg3\":0},{\"src\":0,\"trg\":3,\"edgeType\":1,\"arg1\":0,\"arg2\":0,\"arg3\":0},{\"src\":0,\"trg\":5,\"edgeType\":1,\"arg1\":0,\"arg2\":0,\"arg3\":0}],[{\"src\":1,\"trg\":7,\"edgeType\":1,\"arg1\":0,\"arg2\":0,\"arg3\":0}],[{\"src\":3,\"trg\":14,\"edgeType\":1,\"arg1\":0,\"arg2\":0,\"arg3\":0}],[{\"src\":5,\"trg\":19,\"edgeType\":1,\"arg1\":0,\"arg2\":0,\"arg3\":0}],[{\"src\":7,\"trg\":8,\"edgeType\":5,\"arg1\":104,\"arg2\":0,\"arg3\":0}],[{\"src\":8,\"trg\":9,\"edgeType\":5,\"arg1\":101,\"arg2\":0,\"arg3\":0}],[{\"src\":9,\"trg\":10,\"edgeType\":5,\"arg1\":108,\"arg2\":0,\"arg3\":0}],[{\"src\":10,\"trg\":11,\"edgeType\":5,\"arg1\":108,\"arg2\":0,\"arg3\":0}],[{\"src\":11,\"trg\":12,\"edgeType\":5,\"arg1\":111,\"arg2\":0,\"arg3\":0}],[{\"src\":12,\"trg\":2,\"edgeType\":1,\"arg1\":0,\"arg2\":0,\"arg3\":0}],[{\"src\":13,\"trg\":15,\"edgeType\":7,\"arg1\":0,\"arg2\":0,\"arg3\":0}],[{\"src\":14,\"trg\":13,\"edgeType\":1,\"arg1\":0,\"arg2\":0,\"arg3\":0}],[{\"src\":15,\"trg\":16,\"edgeType\":1,\"arg1\":0,\"arg2\":0,\"arg3\":0}],[{\"src\":16,\"trg\":14,\"edgeType\":1,\"arg1\":0,\"arg2\":0,\"arg3\":0},{\"src\":16,\"trg\":17,\"edgeType\":1,\"arg1\":0,\"arg2\":0,\"arg3\":0}],[{\"src\":17,\"trg\":4,\"edgeType\":1,\"arg1\":0,\"arg2\":0,\"arg3\":0}],[{\"src\":18,\"trg\":20,\"edgeType\":7,\"arg1\":1,\"arg2\":0,\"arg3\":0}],[{\"src\":19,\"trg\":18,\"edgeType\":1,\"arg1\":0,\"arg2\":0,\"arg3\":0}],[{\"src\":20,\"trg\":21,\"edgeType\":1,\"arg1\":0,\"arg2\":0,\"arg3\":0}],[{\"src\":21,\"trg\":19,\"edgeType\":1,\"arg1\":0,\"arg2\":0,\"arg3\":0},{\"src\":21,\"trg\":22,\"edgeType\":1,\"arg1\":0,\"arg2\":0,\"arg3\":0}],[{\"src\":22,\"trg\":23,\"edgeType\":1,\"arg1\":0,\"arg2\":0,\"arg3\":0}],[{\"src\":23,\"trg\":24,\"edgeType\":6,\"arg1\":2,\"arg2\":0,\"arg3\":0}],[{\"src\":24,\"trg\":6,\"edgeType\":1,\"arg1\":0,\"arg2\":0,\"arg3\":0}]],\"decisionToState\":[0,16,21],\"lexerActions\":[{\"actionType\":6,\"a\":0,\"b\":0}]}"
}

View File

@ -0,0 +1,21 @@
// Generated from Hello.g4 by ANTLR 4.6
import Antlr4
/**
* This interface defines a complete listener for a parse tree produced by
* {@link HelloParser}.
*/
public protocol HelloListener: ParseTreeListener {
/**
* Enter a parse tree produced by {@link HelloParser#r}.
- Parameters:
- ctx: the parse tree
*/
func enterR(_ ctx: HelloParser.RContext)
/**
* Exit a parse tree produced by {@link HelloParser#r}.
- Parameters:
- ctx: the parse tree
*/
func exitR(_ ctx: HelloParser.RContext)
}

View File

@ -0,0 +1,130 @@
// Generated from Hello.g4 by ANTLR 4.6
import Antlr4
open class HelloParser: Parser {
internal static var _decisionToDFA: [DFA] = {
var decisionToDFA = [DFA]()
let length = HelloParser._ATN.getNumberOfDecisions()
for i in 0..<length {
decisionToDFA.append(DFA(HelloParser._ATN.getDecisionState(i)!, i))
}
return decisionToDFA
}()
internal static let _sharedContextCache: PredictionContextCache = PredictionContextCache()
public enum Tokens: Int {
case EOF = -1, T__0 = 1, ID = 2, WS = 3
}
public static let RULE_r = 0
public static let ruleNames: [String] = [
"r"
]
private static let _LITERAL_NAMES: [String?] = [
nil, "'hello'"
]
private static let _SYMBOLIC_NAMES: [String?] = [
nil, nil, "ID", "WS"
]
public static let VOCABULARY: Vocabulary = Vocabulary(_LITERAL_NAMES, _SYMBOLIC_NAMES)
/**
* @deprecated Use {@link #VOCABULARY} instead.
*/
//@Deprecated
public let tokenNames: [String?]? = {
let length = _SYMBOLIC_NAMES.count
var tokenNames = [String?](repeating: nil, count: length)
for i in 0..<length {
var name = VOCABULARY.getLiteralName(i)
if name == nil {
name = VOCABULARY.getSymbolicName(i)
}
if name == nil {
name = "<INVALID>"
}
tokenNames[i] = name
}
return tokenNames
}()
override
open func getTokenNames() -> [String?]? {
return tokenNames
}
override
open func getGrammarFileName() -> String { return "Hello.g4" }
override
open func getRuleNames() -> [String] { return HelloParser.ruleNames }
override
open func getSerializedATN() -> String { return HelloParser._serializedATN }
override
open func getATN() -> ATN { return HelloParser._ATN }
open override func getVocabulary() -> Vocabulary {
return HelloParser.VOCABULARY
}
public override init(_ input:TokenStream)throws {
RuntimeMetaData.checkVersion("4.6", RuntimeMetaData.VERSION)
try super.init(input)
_interp = ParserATNSimulator(self,HelloParser._ATN,HelloParser._decisionToDFA, HelloParser._sharedContextCache)
}
open class RContext:ParserRuleContext {
open func ID() -> TerminalNode? { return getToken(HelloParser.Tokens.ID.rawValue, 0) }
open override func getRuleIndex() -> Int { return HelloParser.RULE_r }
override
open func enterRule(_ listener: ParseTreeListener) {
if listener is HelloListener {
(listener as! HelloListener).enterR(self)
}
}
override
open func exitRule(_ listener: ParseTreeListener) {
if listener is HelloListener {
(listener as! HelloListener).exitR(self)
}
}
override
open func accept<T>(_ visitor: ParseTreeVisitor<T>) -> T? {
if visitor is HelloVisitor {
return (visitor as! HelloVisitor<T>).visitR(self)
}else if visitor is HelloBaseVisitor {
return (visitor as! HelloBaseVisitor<T>).visitR(self)
}
else {
return visitor.visitChildren(self)
}
}
}
@discardableResult
open func r() throws -> RContext {
var _localctx: RContext = RContext(_ctx, getState())
try enterRule(_localctx, 0, HelloParser.RULE_r)
defer {
try! exitRule()
}
do {
try enterOuterAlt(_localctx, 1)
setState(2)
try match(HelloParser.Tokens.T__0.rawValue)
setState(3)
try match(HelloParser.Tokens.ID.rawValue)
}
catch ANTLRException.recognition(let re) {
_localctx.exception = re
_errHandler.reportError(self, re)
try _errHandler.recover(self, re)
}
return _localctx
}
public static let _serializedATN : String = HelloParserATN().jsonString
public static let _ATN: ATN = ATNDeserializer().deserializeFromJson(_serializedATN)
}

View File

@ -0,0 +1,3 @@
class HelloParserATN {
let jsonString: String = "{\"version\":3,\"uuid\":\"aadb8d7e-aeef-4415-ad2b-8204d6cf042e\",\"grammarType\":1,\"maxTokenType\":3,\"states\":[{\"stateType\":2,\"ruleIndex\":0},{\"stateType\":7,\"ruleIndex\":0},{\"stateType\":1,\"ruleIndex\":0},{\"stateType\":1,\"ruleIndex\":0},{\"stateType\":1,\"ruleIndex\":0},{\"stateType\":1,\"ruleIndex\":0}],\"nonGreedyStates\":[],\"precedenceStates\":[],\"ruleToStartState\":[{\"stateNumber\":0}],\"modeToStartState\":[],\"nsets\":0,\"IntervalSet\":[],\"allTransitionsBuilder\":[[{\"src\":0,\"trg\":2,\"edgeType\":1,\"arg1\":0,\"arg2\":0,\"arg3\":0}],[{\"src\":2,\"trg\":3,\"edgeType\":5,\"arg1\":1,\"arg2\":0,\"arg3\":0}],[{\"src\":3,\"trg\":4,\"edgeType\":5,\"arg1\":2,\"arg2\":0,\"arg3\":0}],[{\"src\":4,\"trg\":1,\"edgeType\":1,\"arg1\":0,\"arg2\":0,\"arg3\":0}],[]],\"decisionToState\":[],\"lexerActions\":[]}"
}

View File

@ -0,0 +1,22 @@
// Generated from Hello.g4 by ANTLR 4.6
import Antlr4
/**
* This interface defines a complete generic visitor for a parse tree produced
* by {@link HelloParser}.
*
* @param <T> The return type of the visit operation. Use {@link Void} for
* operations with no return type.
*/
open class HelloVisitor<T>: ParseTreeVisitor<T> {
/**
* Visit a parse tree produced by {@link HelloParser#r}.
- Parameters:
- ctx: the parse tree
- returns: the visitor result
*/
open func visitR(_ ctx: HelloParser.RContext) -> T{
fatalError(#function + " must be overridden")
}
}

View File

@ -0,0 +1,18 @@
import Antlr4
public class HelloWalker: HelloBaseListener {
public override func enterR(_ ctx: HelloParser.RContext) {
print("enterR: \(ctx.IDText())")
}
public override func exitR(_ ctx: HelloParser.RContext) {
print("exitR: \(ctx.IDText())")
}
}
fileprivate extension HelloParser.RContext {
fileprivate func IDText() -> String {
return ID()?.getText() ?? ""
}
}

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<playground version='5.0' target-platform='macos'>
<timeline fileName='timeline.xctimeline'/>
</playground>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "container:Antlr4.xcodeproj">
</FileRef>
<FileRef
location = "container:Antlr4 playground.playground">
</FileRef>
</Workspace>