├── .gitignore ├── DeterministicGenerator.py ├── Ideas.gram ├── IdeasNonRecursive.gram ├── JSGFGrammar.py ├── JSGFParser.py ├── LICENSE ├── ProbabilisticGenerator.py ├── README.md ├── docs ├── DeterministicGenerator.rst ├── JSGFGrammar.rst ├── JSGFParser.rst ├── Makefile ├── ProbabilisticGenerator.rst ├── _build │ ├── doctrees │ │ ├── DeterministicGenerator.doctree │ │ ├── JSGFGrammar.doctree │ │ ├── JSGFParser.doctree │ │ ├── ProbabilisticGenerator.doctree │ │ ├── environment.pickle │ │ └── index.doctree │ └── html │ │ ├── .buildinfo │ │ ├── DeterministicGenerator.html │ │ ├── JSGFGrammar.html │ │ ├── JSGFParser.html │ │ ├── ProbabilisticGenerator.html │ │ ├── _sources │ │ ├── DeterministicGenerator.txt │ │ ├── JSGFGrammar.txt │ │ ├── JSGFParser.txt │ │ ├── ProbabilisticGenerator.txt │ │ └── index.txt │ │ ├── _static │ │ ├── ajax-loader.gif │ │ ├── basic.css │ │ ├── comment-bright.png │ │ ├── comment-close.png │ │ ├── comment.png │ │ ├── default.css │ │ ├── doctools.js │ │ ├── down-pressed.png │ │ ├── down.png │ │ ├── file.png │ │ ├── jquery.js │ │ ├── minus.png │ │ ├── plus.png │ │ ├── pygments.css │ │ ├── searchtools.js │ │ ├── sidebar.js │ │ ├── underscore.js │ │ ├── up-pressed.png │ │ ├── up.png │ │ └── websupport.js │ │ ├── genindex.html │ │ ├── index.html │ │ ├── objects.inv │ │ ├── py-modindex.html │ │ ├── search.html │ │ └── searchindex.js ├── conf.py └── index.rst └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | -------------------------------------------------------------------------------- /DeterministicGenerator.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @copyright: MIT License 3 | # Copyright (c) 2018 syntactic (Pastèque Ho) 4 | # Permission is hereby granted, free of charge, to any person obtaining a copy 5 | # of this software and associated documentation files (the "Software"), to deal 6 | # in the Software without restriction, including without limitation the rights 7 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | # copies of the Software, and to permit persons to whom the Software is 9 | # furnished to do so, subject to the following conditions: 10 | # The above copyright notice and this permission notice shall be included in all 11 | # copies or substantial portions of the Software. 12 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 15 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 18 | # SOFTWARE. 19 | # @summary: This file generates all strings described by a non-recursive JSGF grammar. 20 | # Run it by entering into the command line: python DeterministicGenerator.py 21 | # where is the path to the JSGF grammar. 22 | # @since: 2014/06/02 23 | 24 | """ 25 | This file deterministically generates strings from a JSGF Grammar, whether there are \ 26 | weights defined in rules or not. It requires one argument: the path to the JSGF\ 27 | Grammar file. You can run this on the included grammar IdeasNonRecursive.gram:\ 28 | 29 | 30 | ``python DeterministicGenerator.py IdeasNonRecursive.gram`` 31 | 32 | This will generate all strings defined by the public rules of IdeasNonRecursive.gram.\ 33 | It is important that the grammar used by the generator is not recursive (rules \ 34 | should not directly or indirectly reference themselves), so that the generator\ 35 | terminates. Otherwise, you may get a maximum recursion depth exceeded error or \ 36 | a segmentation fault. 37 | """ 38 | 39 | import sys, itertools 40 | import JSGFParser as parser 41 | import JSGFGrammar as gram 42 | 43 | 44 | def combineSets(listOfSets): 45 | """ 46 | Combines sets of strings by taking the cross product of the sets and \ 47 | concatenating the elements in the resulting tuples 48 | 49 | :param listOfSets: 2-D list of strings 50 | :returns: a list of strings 51 | """ 52 | totalCrossProduct = [''] 53 | for i in range(len(listOfSets)): 54 | currentProduct = [] 55 | for crossProduct in itertools.product(totalCrossProduct, listOfSets[i]): 56 | currentProduct.append((crossProduct[0].strip() + ' ' + crossProduct[1].strip()).strip()) 57 | totalCrossProduct = currentProduct 58 | return totalCrossProduct 59 | 60 | def processSequence(seq): 61 | """ 62 | Combines adjacent elements in a sequence 63 | """ 64 | componentSets = [] 65 | for component in seq: 66 | componentSets.append(processRHS(component)) 67 | return combineSets(componentSets) 68 | 69 | 70 | def processNonTerminal(nt): 71 | """ 72 | Finds the rule expansion for a nonterminal and returns its expansion. 73 | """ 74 | return processRHS(grammar.getRHS(nt)) 75 | 76 | def processDisjunction(disj): 77 | """ 78 | Returns the string representations of a set of alternatives 79 | 80 | :returns: list of strings, where each string is each alternative 81 | """ 82 | disjunctExpansions = [] 83 | if type(disj.disjuncts[0]) is tuple: 84 | disjuncts = map(lambda x : x[0], disj.disjuncts) 85 | else: 86 | disjuncts = disj.disjuncts 87 | for disjunct in disjuncts: 88 | disjunctExpansions.extend(processRHS(disjunct)) 89 | return disjunctExpansions 90 | 91 | def processOptional(opt): 92 | """ 93 | Returns the string representations of an optional grouping 94 | 95 | :type opt: JSGFOptional 96 | :returns: list of strings, including an empty string 97 | """ 98 | optional = [''] 99 | optional.extend(processRHS(opt.option)) 100 | return optional 101 | 102 | def processRHS(rhs): 103 | """ 104 | Depending on the type of the argument, calls the corresponding 105 | function to deal with that type. 106 | 107 | :param rhs: portion of JSGF rule 108 | :type rhs: either a JSGF Expression, list, or string 109 | :returns: list of strings 110 | """ 111 | if type(rhs) is list: 112 | return processSequence(rhs) 113 | elif isinstance(rhs, gram.Disjunction): 114 | return processDisjunction(rhs) 115 | elif isinstance(rhs, gram.Optional): 116 | return processOptional(rhs) 117 | elif isinstance(rhs, gram.NonTerminal): 118 | return processNonTerminal(rhs) 119 | elif type(rhs) is str: 120 | return [rhs] 121 | 122 | 123 | if __name__ == '__main__': 124 | fileStream = open(sys.argv[1]) 125 | grammar = parser.getGrammarObject(fileStream) 126 | for rule in grammar.publicRules: 127 | expansions = processRHS(rule.rhs) 128 | for expansion in expansions: 129 | print expansion 130 | 131 | 132 | 133 | -------------------------------------------------------------------------------- /Ideas.gram: -------------------------------------------------------------------------------- 1 | public = ; 2 | 3 | = /5/ the idea | /1/ the idea ; 4 | = will suffice; 5 | 6 | = that ; 7 | -------------------------------------------------------------------------------- /IdeasNonRecursive.gram: -------------------------------------------------------------------------------- 1 | public = | ; 2 | 3 | = /5/ the idea | /1/ the idea ; 4 | = suffice; 5 | 6 | = that ; 7 | 8 | = ; 9 | 10 | = the idea; 11 | 12 | = /10/ can | /15/ should | /5/ might; 13 | 14 | = the idea can suffice; 15 | -------------------------------------------------------------------------------- /JSGFGrammar.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @copyright: MIT License 3 | # Copyright (c) 2018 syntactic (Pastèque Ho) 4 | # Permission is hereby granted, free of charge, to any person obtaining a copy 5 | # of this software and associated documentation files (the "Software"), to deal 6 | # in the Software without restriction, including without limitation the rights 7 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | # copies of the Software, and to permit persons to whom the Software is 9 | # furnished to do so, subject to the following conditions: 10 | # The above copyright notice and this permission notice shall be included in all 11 | # copies or substantial portions of the Software. 12 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 15 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 18 | # SOFTWARE. 19 | # @summary: This file lays out the class structure for a JSGF Grammar 20 | # @since: 2014/06/02 21 | 22 | """ 23 | This file lays out the class structure for a JSGF Grammar. 24 | 25 | .. module:: JSGFGrammar 26 | 27 | .. moduleauthor:: Pastèque Ho 28 | """ 29 | 30 | 31 | class JSGFExpression(): 32 | pass 33 | 34 | class Disjunction(JSGFExpression): 35 | """ 36 | Disjunction class stores disjuncts in a list 37 | """ 38 | 39 | def __init__(self, disjuncts): 40 | self.disjuncts = disjuncts 41 | 42 | def __str__(self): 43 | return '( ' + ' | '.join(map(str,self.disjuncts)) + ' )' 44 | 45 | def __repr__(self): 46 | return str(self) 47 | 48 | def __getitem__(self): 49 | return self.disjuncts 50 | 51 | class Optional(JSGFExpression): 52 | """ 53 | Optional class stores either a JSGFExpression, list, or string 54 | as its optional element 55 | """ 56 | 57 | def __init__(self, option): 58 | self.option = option 59 | 60 | def __str__(self): 61 | return ('[ ' + str(self.option) + ' ]') 62 | 63 | def __repr__(self): 64 | return str(self) 65 | 66 | def __getitem__(self): 67 | return self.option 68 | 69 | class NonTerminal(JSGFExpression): 70 | """ 71 | NonTerminal class simply stores the label of the nonterminal 72 | """ 73 | 74 | def __init__(self, ntName): 75 | self.name = ntName 76 | 77 | def __str__(self): 78 | return self.name 79 | 80 | def __repr__(self): 81 | return str(self) 82 | 83 | def __getitem__(self): 84 | return self.name 85 | 86 | 87 | class Rule(): 88 | """ 89 | Rule class, represents a JSGF rule, with a nonterminal name representing the 90 | left hand side, and a list of possible expansions representing the right 91 | hand side. 92 | """ 93 | 94 | def __init__(self): 95 | """ 96 | constructor with no args 97 | """ 98 | self.lhs = '' 99 | self.rhs = [] 100 | 101 | def __init__(self, lhs): 102 | """ 103 | constructor with nonterminal name 104 | """ 105 | pass 106 | 107 | def __init__(self, lhs, rhs): 108 | """ 109 | constructor with full rule definition 110 | """ 111 | self.lhs = lhs 112 | self.rhs = rhs 113 | 114 | def __str__(self): 115 | return (str(self.lhs) + ' -> ' + str(self.rhs)) 116 | 117 | def __repr__(self): 118 | return str(self) 119 | 120 | 121 | class Grammar(): 122 | """ 123 | Grammar class which contains a list for public rules and a list 124 | for all rules. 125 | """ 126 | 127 | def __init__(self): 128 | self.rules = [] 129 | self.publicRules = [] 130 | 131 | def addRule(self, rule): 132 | """ 133 | adds a rule to the list of rules 134 | """ 135 | self.rules.append(rule) 136 | 137 | def addPublicRule(self, rule): 138 | """ 139 | adds a rule to the list of public rules 140 | """ 141 | self.publicRules.append(rule) 142 | 143 | def getRHS(self, nt): 144 | """ 145 | returns rule definition 146 | 147 | :param nt: Non-Terminal (variable) whose definition to get 148 | """ 149 | for rule in self.rules: 150 | #print 'checking', nt.name, 'and', rule.lhs, type(nt.name), rule.lhs.name 151 | if rule.lhs.name == nt.name: 152 | return rule.rhs 153 | raise ValueError("Rule not defined for " + str(nt)) 154 | 155 | def __getitem__(self, nt): 156 | #rhsides = [] to do for multiple rhsides 157 | for rule in self.rules: 158 | if rule.lhs == nt: 159 | return rule.rhs 160 | else: 161 | raise ValueError('Rule not defined for ' + str(nt)) 162 | 163 | def __str__(self): 164 | return 'All Rules:' + str(self.rules) + '\n' + 'Public Rules:' + str(self.publicRules) 165 | 166 | if __name__ == "__main__": 167 | jgDisj = Disjunction(['hello', 'world']) 168 | jgOpt = Optional(jgDisj) 169 | jgRule = Rule("", jgOpt) 170 | 171 | print jgRule 172 | -------------------------------------------------------------------------------- /JSGFParser.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @copyright: MIT License 3 | # Copyright (c) 2018 syntactic (Pastèque Ho) 4 | # Permission is hereby granted, free of charge, to any person obtaining a copy 5 | # of this software and associated documentation files (the "Software"), to deal 6 | # in the Software without restriction, including without limitation the rights 7 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | # copies of the Software, and to permit persons to whom the Software is 9 | # furnished to do so, subject to the following conditions: 10 | # The above copyright notice and this permission notice shall be included in all 11 | # copies or substantial portions of the Software. 12 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 15 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 18 | # SOFTWARE. 19 | # @summary: This file parses a JSGF Grammar and prints it out. 20 | # @since: 2014/06/02 21 | 22 | """ 23 | This file parses a JSGF grammar file and returns a JSGFGrammar object. \ 24 | It uses the pyparsing module and defines a grammar for JSGF grammars. \ 25 | Upon finding a string or JSGF expression, it builds a grammar object from \ 26 | the bottom up, composing JSGF expressions with strings and lists. When the \ 27 | entire right hand side of a rule has been parsed and a JSGF expression \ 28 | object has been created of it, it gets added to the main JSGFGrammar \ 29 | object as one of its rules. 30 | 31 | To run the parser independently and print the resulting JSGFGrammar object, \ 32 | run it as: 33 | 34 | ``python JSGFParser.py Ideas.gram`` 35 | 36 | Generally, this module should be imported and the getGrammarObject should be called \ 37 | with a ``file`` object as its argument. This function returns a grammar \ 38 | object that can be used by the Generator scripts ``DeterministicGenerator.py`` \ 39 | and ``ProbabilisticGenerator.py``. 40 | 41 | The features of JSGF that this parser can handle include: 42 | - rulenames 43 | - tokens 44 | - comments 45 | - rule definitions 46 | - rule expansions 47 | - sequences 48 | - alternatives 49 | - weights 50 | - grouping 51 | - optional grouping 52 | 53 | Notable features of JSGF that are **not** handled by this parser are: 54 | - grammar names 55 | - import statements 56 | - unary operators 57 | - tags 58 | 59 | """ 60 | 61 | import sys 62 | import JSGFGrammar as gram 63 | from pyparsing import * 64 | 65 | sys.setrecursionlimit(100000) 66 | usePackrat = True 67 | 68 | def foundWeight(s, loc, toks): 69 | """ 70 | PyParsing action to run when a weight is found. 71 | 72 | :returns: Weight as a floating point number 73 | """ 74 | #print 'found weight', toks.dump() 75 | #print 'returning the weight', float(toks.weightAmount) 76 | return float(toks.weightAmount) 77 | 78 | def foundToken(s, loc, toks): 79 | """ 80 | PyParsing action to run when a token is found. 81 | 82 | :returns: Token as a string 83 | """ 84 | #print 'found token', toks.dump() 85 | #print 'returning the token', toks.token 86 | return toks.token 87 | 88 | def foundNonterminal(s, loc, toks): 89 | """ 90 | PyParsing action to run when a nonterminal reference is found. 91 | 92 | :returns: NonTerminal object representing the NT reference found 93 | """ 94 | return gram.NonTerminal(list(toks)[0]) 95 | 96 | def foundWeightedExpression(s, loc, toks): 97 | """ 98 | PyParsing action to run when a weighted expression is found. 99 | 100 | :returns: Ordered pair of the expression and its weight 101 | """ 102 | toks.weightedExpression = (toks.expr, toks.weight) 103 | #print 'found weighted expression', toks.dump() 104 | expr = list(toks.expr) 105 | if len(expr) == 1: 106 | expr = expr[0] 107 | pair = (expr, toks.weight) 108 | #print 'returning', pair 109 | return pair 110 | 111 | def foundPair(s, loc, toks): 112 | """ 113 | PyParsing action to run when a pair of alternatives are found. 114 | 115 | :returns: Disjunction object containing all disjuncts that have been accumulated so far 116 | """ 117 | #print 'found pair', toks.dump() 118 | #print 'disj1 is', list(toks.disj1), 'disj2 is', list(toks.disj2) 119 | firstAlternative = list(toks.disj1) 120 | secondAlternative = list(toks.disj2) 121 | if len(firstAlternative) > 1: 122 | disj = [firstAlternative] 123 | else: 124 | disj = firstAlternative 125 | if len(secondAlternative) == 1: 126 | if isinstance(secondAlternative[0], gram.Disjunction): 127 | #print 'found disjuncts in second alt', secondAlternative[0].disjuncts 128 | disj.extend(secondAlternative[0].disjuncts) 129 | else: 130 | disj.append(secondAlternative[0]) 131 | else: 132 | disj.append(secondAlternative) 133 | disj = gram.Disjunction(disj) 134 | #print 'returing the pair', disj 135 | return disj 136 | 137 | def foundOptionalGroup(s, loc, toks): 138 | """ 139 | PyParsing action to run when an optional group is found. 140 | 141 | :returns: Optional object containing all elements in the group 142 | """ 143 | #print 'optional item is', toks.optionalItem 144 | if len(list(toks[0])) > 1: 145 | return gram.Optional(list(toks[0])) 146 | else: 147 | return gram.Optional(toks.optionalItem[0]) 148 | 149 | def foundSeq(s, loc, toks): 150 | """ 151 | PyParsing action to run when a sequence of concatenated elements is found. 152 | 153 | :returns: List of JSGFGrammar objects, strings, or more lists 154 | """ 155 | #print 'seq is', toks.dump() 156 | #print 'length of seq is', len(list(toks[0])), list(toks[0]) 157 | if len(list(toks[0])) > 1: 158 | #print 'seq retringin', list(toks[0]), type(list(toks[0])) 159 | return list(toks[0]) 160 | else: 161 | #print 'seq returning', list(toks[0])[0], type(list(toks[0])[0]) 162 | return list(toks[0])[0] 163 | 164 | # PyParsing rule for a weight 165 | weight = (Literal('/').suppress() + (Word(nums + '.')).setResultsName('weightAmount') + Literal('/').suppress()).setParseAction(foundWeight).setResultsName("weight") 166 | 167 | # PyParsing rule for a token 168 | token = Word(alphanums+"'_-,.?@").setResultsName('token').setParseAction(foundToken) 169 | 170 | # PyParsing rule for a nonterminal reference 171 | nonterminal = Combine(Literal('<') + Word(alphanums+'$_:;,=|/\\()[]@#%!^&~') + Literal('>')).setParseAction(foundNonterminal).setResultsName('NonTerminal') 172 | 173 | Sequence = Forward() 174 | 175 | weightedExpression = (weight + Group(Sequence).setResultsName("expr")).setResultsName('weightedExpression').setParseAction(foundWeightedExpression) 176 | 177 | weightAlternatives = Forward() 178 | weightedPrime = Literal('|').suppress() + weightAlternatives 179 | weightAlternatives << MatchFirst([(Group(weightedExpression).setResultsName("disj1") + Group(weightedPrime).setResultsName("disj2")).setParseAction(foundPair).setResultsName("pair"), Group(weightedExpression).setParseAction(foundSeq)]) 180 | 181 | disj = Forward() 182 | disjPrime = Literal('|').suppress() + disj 183 | disj << MatchFirst([(Group(Sequence).setResultsName("disj1") + Group(disjPrime).setResultsName("disj2")).setParseAction(foundPair).setResultsName("pair"), Group(Sequence).setParseAction(foundSeq)]) 184 | 185 | topLevel = MatchFirst([disj, weightAlternatives]) 186 | StartSymbol = Optional(Literal('public')).setResultsName('public') + nonterminal.setResultsName('identifier') + Literal('=').suppress() + Group(topLevel).setResultsName('ruleDef') + Literal(';').suppress() + stringEnd 187 | 188 | 189 | Expression = MatchFirst([nonterminal, token]) 190 | 191 | Grouping = Literal('(').suppress() + topLevel + Literal(')').suppress() 192 | OptionalGrouping = (Literal('[').suppress() + Group(topLevel).setResultsName("optionalItem") + Literal(']').suppress()).setParseAction(foundOptionalGroup) 193 | 194 | Sequence << Group(OneOrMore(MatchFirst([Grouping, OptionalGrouping, Expression]))).setResultsName("seq").setParseAction(foundSeq) 195 | 196 | def nocomment(oldline): 197 | """ 198 | Removes a comment from a line 199 | 200 | :param oldline: String representing the original line 201 | :returns: String with the same semantic content, with the comments stripped 202 | """ 203 | if '//' in oldline: 204 | return oldline.replace(oldline, oldline[0:oldline.index('//')]) 205 | elif '*' in oldline: 206 | return oldline.replace(oldline, '') 207 | else: 208 | return oldline 209 | 210 | def getGrammarObject(fileStream): 211 | """ 212 | Produces a JSGFGrammar object from a stream of text, the grammar object has a set of public rules and regular rules 213 | 214 | :param fileStream: file object containing the contents of the grammar file 215 | :type fileStream: file object 216 | :returns: JSGFGrammar object 217 | """ 218 | linegenerator = fileStream 219 | lines = linegenerator.readlines() 220 | for i in range(len(lines)): 221 | lines[i] = nocomment(lines[i]) 222 | # buffer will accumulate lines until a fully parseable piece is found 223 | buffer = "" 224 | 225 | grammar = gram.Grammar() 226 | for line in lines: 227 | buffer += line 228 | 229 | match = next(StartSymbol.scanString(buffer), None) 230 | while match: 231 | tokens, start, end = match 232 | #print 'rule dict is', tokens.asDict() 233 | if 'public' in tokens.keys(): 234 | grammar.addPublicRule(gram.Rule(tokens.identifier, list(tokens.ruleDef))) 235 | grammar.addRule(gram.Rule(tokens.identifier, list(tokens.ruleDef))) 236 | 237 | buffer = buffer[end:] 238 | match = next(StartSymbol.scanString(buffer), None) 239 | return grammar 240 | 241 | if __name__ == '__main__': 242 | fileStream = open(sys.argv[1]) 243 | grammar = getGrammarObject(fileStream) 244 | print grammar 245 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 syntactic 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /ProbabilisticGenerator.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | #/usr/bin/python 3 | 4 | # @copyright: MIT License 5 | # Copyright (c) 2018 syntactic (Pastèque Ho) 6 | # Permission is hereby granted, free of charge, to any person obtaining a copy 7 | # of this software and associated documentation files (the "Software"), to deal 8 | # in the Software without restriction, including without limitation the rights 9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | # copies of the Software, and to permit persons to whom the Software is 11 | # furnished to do so, subject to the following conditions: 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | # SOFTWARE. 21 | # @summary: This file generates sentences from a PCFG in JSGF. Run it by entering 22 | # in the command line: python ProbabilisticGenerator.py 23 | # where is the path of the JSGF file, and is the number 24 | # of strings you want to generate 25 | # @since: 2014/06/02 26 | 27 | """ 28 | This file probabilistically generates strings from a JSGF grammar. It takes advantage \ 29 | of weights assigned to alternatives (separated by pipes) by choosing to \ 30 | expand higher weighted alternatives with greater probability. For sets of \ 31 | alternatives without weights, each alternative is equally likely to be \ 32 | expanded. For optional groups, the elements in the group have a 50% chance \ 33 | of being expanded. 34 | 35 | It requires two arguments: the path to the JSGF\ 36 | Grammar file, and the number of strings to generate. You can run this on the \ 37 | included grammar Ideas.gram:\ 38 | 39 | 40 | ``python ProbabilisticGenerator.py Ideas.gram 20`` 41 | 42 | This will generate 20 sentences based on the public rule(s) in Ideas.gram, using the \ 43 | weights if they are provided. 44 | """ 45 | 46 | import sys, itertools, random, bisect, argparse 47 | import JSGFParser as parser 48 | import JSGFGrammar as gram 49 | 50 | 51 | def weightedChoice(listOfTuples): 52 | """ 53 | Chooses an element of a list based on its weight 54 | 55 | :param listOfTuples: a list of (element, weight) tuples, where the element can be a JSGF expression object, string, or list,\ 56 | and the weight is a float 57 | :returns: the first element of a chosen tuple 58 | """ 59 | def accum(listOfWeights): # support function for creating ranges for weights 60 | for i in range(len(listOfWeights)): 61 | if i > 0: 62 | listOfWeights[i] += listOfWeights[i-1] 63 | return listOfWeights 64 | choices, weights = zip(*listOfTuples) 65 | cumdist = accum(list(weights)) 66 | x = random.random() * cumdist[-1] 67 | return choices[bisect.bisect(cumdist, x)] 68 | 69 | def combineSets(listOfSets): 70 | """ 71 | Combines sets of strings by taking the cross product of the sets and \ 72 | concatenating the elements in the resulting tuples 73 | 74 | :param listOfSets: 2-D list of strings 75 | :returns: a list of strings 76 | """ 77 | totalCrossProduct = [''] 78 | for i in range(len(listOfSets)): 79 | currentProduct = [] 80 | for crossProduct in itertools.product(totalCrossProduct, listOfSets[i]): 81 | #print crossProduct[0], crossProduct[1] 82 | currentProduct.append((crossProduct[0].strip() + ' ' + crossProduct[1].strip()).strip()) 83 | totalCrossProduct = currentProduct 84 | return totalCrossProduct 85 | 86 | def processSequence(seq): 87 | """ 88 | Combines adjacent elements in a sequence. 89 | """ 90 | componentSets = [] 91 | for component in seq: 92 | expandedComponent = processRHS(component).strip() 93 | if len(expandedComponent) > 0: 94 | componentSets.append(expandedComponent) 95 | return ' '.join(componentSets) 96 | 97 | 98 | def processNonTerminal(nt): 99 | """ 100 | Finds the rule expansion for a nonterminal and returns its expansion. 101 | """ 102 | return processRHS(grammar.getRHS(nt)) 103 | 104 | def processDisjunction(disj): 105 | """ 106 | Chooses either a random disjunct (for alternatives without weights) or 107 | a disjunct based on defined weights. 108 | """ 109 | if type(disj.disjuncts[0]) is tuple: 110 | return processRHS(weightedChoice(disj.disjuncts)) 111 | else: 112 | return processRHS(random.choice(disj.disjuncts)) 113 | 114 | def processOptional(opt): 115 | """ 116 | Processes the optional element 50% of the time, skips it the other 50% of the time 117 | """ 118 | rand = random.random() 119 | if rand <= 0.5: 120 | return '' 121 | else: 122 | return processRHS(opt.option) 123 | 124 | def processRHS(rhs): 125 | if type(rhs) is list: 126 | return processSequence(rhs) 127 | elif isinstance(rhs, gram.Disjunction): 128 | return processDisjunction(rhs) 129 | elif isinstance(rhs, gram.Optional): 130 | return processOptional(rhs) 131 | elif isinstance(rhs, gram.NonTerminal): 132 | return processNonTerminal(rhs) 133 | elif type(rhs) is str: 134 | return rhs 135 | 136 | 137 | if __name__ == '__main__': 138 | argParser = argparse.ArgumentParser() 139 | argParser.add_argument('grammarFile') 140 | argParser.add_argument('iterations', type=int, nargs=1, help='number of strings to generate') 141 | args = argParser.parse_args() 142 | fileStream = open(args.grammarFile) 143 | numIterations = args.iterations[0] 144 | grammar = parser.getGrammarObject(fileStream) 145 | if len(grammar.publicRules) != 1: 146 | #x = raw_input('Found more than one public rule. Generate a random string between them?\n') 147 | #if x == 'y': 148 | ### This next chunk has been de-indented 149 | disjuncts = [] 150 | for rule in grammar.publicRules: 151 | rhs = rule.rhs 152 | disjuncts.append(rhs) 153 | newStartSymbol = gram.Disjunction(disjuncts) 154 | for i in range(numIterations): 155 | print processRHS(newStartSymbol) 156 | ### 157 | #else: 158 | #sys.exit('Bye') 159 | else: 160 | startSymbol = grammar.publicRules[0] 161 | for i in range(numIterations): 162 | expansions = processRHS(startSymbol.rhs) 163 | print expansions 164 | 165 | 166 | 167 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JSGF Grammar Tools 2 | 3 | This set of tools can be used primarily to generate strings from a JSGF 4 | grammar, but it also provides an easy to use JSGFParser module which creates 5 | abstract syntax trees for JSGF grammars. Developers can use these ASTs to 6 | help create more tools for their purposes. For more detailed documentation, 7 | refer to the Sphinx documentation located in docs/_build/html/index.html 8 | 9 | ## Dependencies 10 | 11 | - Python 2.7 12 | - PyParsing module (http://pyparsing.wikispaces.com/Download+and+Installation) 13 | 14 | ## Instructions 15 | 16 | The two main Python scripts are DeterministicGenerator.py and 17 | ProbabilisticGenerator.py. Both files require a grammar file as a command 18 | line argument, and the latter also requires a number, which refers to the number 19 | of sentences to generate. Importantly, DeterministicGenerator.py should not take 20 | grammars with recursive rules as an argument. A recursive rule is of the form: 21 | 22 | ``` = this (comes | goes) back to ;``` 23 | 24 | There are two example grammars included with the scripts: Ideas.gram and 25 | IdeasNonRecursive.gram. Ideas.gram is an example of a grammar with recursive 26 | rules, though the recursion is not as direct as the above example. It's a good 27 | idea to run these grammars with the generator scripts to see how the scripts 28 | work: 29 | 30 | ```> python DeterministicGenerator.py IdeasNonRecursive.gram``` 31 | 32 | ```> python ProbabilisticGenerator.py Ideas.gram 20``` 33 | 34 | ### Notes 35 | 36 | - Larger grammars take a longer time to parse, so if nothing seems to be generating, 37 | wait a few seconds and the grammar should be parsed. 38 | 39 | - Most of JSGF as described in http://www.w3.org/TR/2000/NOTE-jsgf-20000605/ is 40 | supported, but there are a few things that have not been implemented by these 41 | tools yet: 42 | - Kleene operators 43 | - Imports and Grammar Names 44 | - Tags 45 | -------------------------------------------------------------------------------- /docs/DeterministicGenerator.rst: -------------------------------------------------------------------------------- 1 | Deterministic Generator module 2 | ============================== 3 | 4 | .. automodule:: DeterministicGenerator 5 | :members: 6 | :undoc-members: 7 | -------------------------------------------------------------------------------- /docs/JSGFGrammar.rst: -------------------------------------------------------------------------------- 1 | JSGFGrammar module 2 | ================== 3 | 4 | .. automodule:: JSGFGrammar 5 | :members: 6 | :undoc-members: 7 | -------------------------------------------------------------------------------- /docs/JSGFParser.rst: -------------------------------------------------------------------------------- 1 | JSGFParser module 2 | ================== 3 | 4 | .. automodule:: JSGFParser 5 | :members: 6 | :undoc-members: 7 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # User-friendly check for sphinx-build 11 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) 12 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) 13 | endif 14 | 15 | # Internal variables. 16 | PAPEROPT_a4 = -D latex_paper_size=a4 17 | PAPEROPT_letter = -D latex_paper_size=letter 18 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 19 | # the i18n builder cannot share the environment and doctrees with the others 20 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 21 | 22 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext 23 | 24 | help: 25 | @echo "Please use \`make ' where is one of" 26 | @echo " html to make standalone HTML files" 27 | @echo " dirhtml to make HTML files named index.html in directories" 28 | @echo " singlehtml to make a single large HTML file" 29 | @echo " pickle to make pickle files" 30 | @echo " json to make JSON files" 31 | @echo " htmlhelp to make HTML files and a HTML help project" 32 | @echo " qthelp to make HTML files and a qthelp project" 33 | @echo " devhelp to make HTML files and a Devhelp project" 34 | @echo " epub to make an epub" 35 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 36 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 37 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" 38 | @echo " text to make text files" 39 | @echo " man to make manual pages" 40 | @echo " texinfo to make Texinfo files" 41 | @echo " info to make Texinfo files and run them through makeinfo" 42 | @echo " gettext to make PO message catalogs" 43 | @echo " changes to make an overview of all changed/added/deprecated items" 44 | @echo " xml to make Docutils-native XML files" 45 | @echo " pseudoxml to make pseudoxml-XML files for display purposes" 46 | @echo " linkcheck to check all external links for integrity" 47 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 48 | 49 | clean: 50 | rm -rf $(BUILDDIR)/* 51 | 52 | html: 53 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 54 | @echo 55 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 56 | 57 | dirhtml: 58 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 59 | @echo 60 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 61 | 62 | singlehtml: 63 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 64 | @echo 65 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 66 | 67 | pickle: 68 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 69 | @echo 70 | @echo "Build finished; now you can process the pickle files." 71 | 72 | json: 73 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 74 | @echo 75 | @echo "Build finished; now you can process the JSON files." 76 | 77 | htmlhelp: 78 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 79 | @echo 80 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 81 | ".hhp project file in $(BUILDDIR)/htmlhelp." 82 | 83 | qthelp: 84 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 85 | @echo 86 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 87 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 88 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/JSGFGrammarTools.qhcp" 89 | @echo "To view the help file:" 90 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/JSGFGrammarTools.qhc" 91 | 92 | devhelp: 93 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 94 | @echo 95 | @echo "Build finished." 96 | @echo "To view the help file:" 97 | @echo "# mkdir -p $$HOME/.local/share/devhelp/JSGFGrammarTools" 98 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/JSGFGrammarTools" 99 | @echo "# devhelp" 100 | 101 | epub: 102 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 103 | @echo 104 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 105 | 106 | latex: 107 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 108 | @echo 109 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 110 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 111 | "(use \`make latexpdf' here to do that automatically)." 112 | 113 | latexpdf: 114 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 115 | @echo "Running LaTeX files through pdflatex..." 116 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 117 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 118 | 119 | latexpdfja: 120 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 121 | @echo "Running LaTeX files through platex and dvipdfmx..." 122 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja 123 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 124 | 125 | text: 126 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 127 | @echo 128 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 129 | 130 | man: 131 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 132 | @echo 133 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 134 | 135 | texinfo: 136 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 137 | @echo 138 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 139 | @echo "Run \`make' in that directory to run these through makeinfo" \ 140 | "(use \`make info' here to do that automatically)." 141 | 142 | info: 143 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 144 | @echo "Running Texinfo files through makeinfo..." 145 | make -C $(BUILDDIR)/texinfo info 146 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 147 | 148 | gettext: 149 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 150 | @echo 151 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 152 | 153 | changes: 154 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 155 | @echo 156 | @echo "The overview file is in $(BUILDDIR)/changes." 157 | 158 | linkcheck: 159 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 160 | @echo 161 | @echo "Link check complete; look for any errors in the above output " \ 162 | "or in $(BUILDDIR)/linkcheck/output.txt." 163 | 164 | doctest: 165 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 166 | @echo "Testing of doctests in the sources finished, look at the " \ 167 | "results in $(BUILDDIR)/doctest/output.txt." 168 | 169 | xml: 170 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml 171 | @echo 172 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml." 173 | 174 | pseudoxml: 175 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml 176 | @echo 177 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." 178 | -------------------------------------------------------------------------------- /docs/ProbabilisticGenerator.rst: -------------------------------------------------------------------------------- 1 | Probabilistic Generator module 2 | ============================== 3 | 4 | 5 | .. automodule:: ProbabilisticGenerator 6 | :members: 7 | :undoc-members: 8 | -------------------------------------------------------------------------------- /docs/_build/doctrees/DeterministicGenerator.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syntactic/JSGFTools/907b91791abe523817b2c2f8e77c66a83d74935e/docs/_build/doctrees/DeterministicGenerator.doctree -------------------------------------------------------------------------------- /docs/_build/doctrees/JSGFGrammar.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syntactic/JSGFTools/907b91791abe523817b2c2f8e77c66a83d74935e/docs/_build/doctrees/JSGFGrammar.doctree -------------------------------------------------------------------------------- /docs/_build/doctrees/JSGFParser.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syntactic/JSGFTools/907b91791abe523817b2c2f8e77c66a83d74935e/docs/_build/doctrees/JSGFParser.doctree -------------------------------------------------------------------------------- /docs/_build/doctrees/ProbabilisticGenerator.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syntactic/JSGFTools/907b91791abe523817b2c2f8e77c66a83d74935e/docs/_build/doctrees/ProbabilisticGenerator.doctree -------------------------------------------------------------------------------- /docs/_build/doctrees/environment.pickle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syntactic/JSGFTools/907b91791abe523817b2c2f8e77c66a83d74935e/docs/_build/doctrees/environment.pickle -------------------------------------------------------------------------------- /docs/_build/doctrees/index.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syntactic/JSGFTools/907b91791abe523817b2c2f8e77c66a83d74935e/docs/_build/doctrees/index.doctree -------------------------------------------------------------------------------- /docs/_build/html/.buildinfo: -------------------------------------------------------------------------------- 1 | # Sphinx build info version 1 2 | # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. 3 | config: 788090ed81524437c57a51ef201002b0 4 | tags: 645f666f9bcd5a90fca523b33c5a78b7 5 | -------------------------------------------------------------------------------- /docs/_build/html/DeterministicGenerator.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Deterministic Generator module — JSGF Grammar Tools 1.0 documentation 10 | 11 | 12 | 13 | 14 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 45 | 46 |
47 |
48 |
49 |
50 | 51 |
52 |

Deterministic Generator module

53 |

This file deterministically generates strings from a JSGF Grammar, whether there are weights defined in rules or not. It requires one argument: the path to the JSGF Grammar file. You can run this on the included grammar IdeasNonRecursive.gram:

54 |
55 |
python DeterministicGenerator.py IdeasNonRecursive.gram
56 |

This will generate all strings defined by the public rules of IdeasNonRecursive.gram. It is important that the grammar used by the generator is not recursive (rules should not directly or indirectly reference themselves), so that the generator terminates. Otherwise, you may get a maximum recursion depth exceeded error or a segmentation fault.

57 |
58 |
59 | DeterministicGenerator.combineSets(listOfSets)
60 |

Combines sets of strings by taking the cross product of the sets and concatenating the elements in the resulting tuples

61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 |
Parameters:listOfSets – 2-D list of strings
Returns:a list of strings
71 |
72 | 73 |
74 |
75 | DeterministicGenerator.processDisjunction(disj)
76 |

Returns the string representations of a set of alternatives

77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 |
Returns:list of strings, where each string is each alternative
85 |
86 | 87 |
88 |
89 | DeterministicGenerator.processNonTerminal(nt)
90 |

Finds the rule expansion for a nonterminal and returns its expansion.

91 |
92 | 93 |
94 |
95 | DeterministicGenerator.processOptional(opt)
96 |

Returns the string representations of an optional grouping

97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 |
Returns:list of strings, including an empty string
105 |
106 | 107 |
108 |
109 | DeterministicGenerator.processRHS(rhs)
110 |

Depending on the type of the argument, calls the corresponding 111 | function to deal with that type.

112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 |
Parameters:rhs (either a JSGF Expression, list, or string) – portion of JSGF rule
Returns:list of strings
122 |
123 | 124 |
125 |
126 | DeterministicGenerator.processSequence(seq)
127 |

Combines adjacent elements in a sequence

128 |
129 | 130 |
131 | 132 | 133 |
134 |
135 |
136 |
137 |
138 |

Previous topic

139 |

Probabilistic Generator module

141 |

This Page

142 | 146 | 158 | 159 |
160 |
161 |
162 |
163 | 178 | 182 | 183 | -------------------------------------------------------------------------------- /docs/_build/html/JSGFGrammar.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | JSGFGrammar module — JSGF Grammar Tools 1.0 documentation 10 | 11 | 12 | 13 | 14 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 49 | 50 |
51 |
52 |
53 |
54 | 55 |
56 |

JSGFGrammar module

57 |

This file lays out the class structure for a JSGF Grammar.

58 |
59 |
60 | class JSGFGrammar.Disjunction(disjuncts)
61 |

Disjunction class stores disjuncts in a list

62 |
63 | 64 |
65 |
66 | class JSGFGrammar.Grammar
67 |

Grammar class which contains a list for public rules and a list 68 | for all rules.

69 |
70 |
71 | addPublicRule(rule)
72 |

adds a rule to the list of public rules

73 |
74 | 75 |
76 |
77 | addRule(rule)
78 |

adds a rule to the list of rules

79 |
80 | 81 |
82 |
83 | getRHS(nt)
84 |

returns rule definition

85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 |
Parameters:nt – Non-Terminal (variable) whose definition to get
93 |
94 | 95 |
96 | 97 |
98 |
99 | class JSGFGrammar.JSGFExpression
100 |
101 | 102 |
103 |
104 | class JSGFGrammar.NonTerminal(ntName)
105 |

NonTerminal class simply stores the label of the nonterminal

106 |
107 | 108 |
109 |
110 | class JSGFGrammar.Optional(option)
111 |

Optional class stores either a JSGFExpression, list, or string 112 | as its optional element

113 |
114 | 115 |
116 |
117 | class JSGFGrammar.Rule(lhs, rhs)
118 |

Rule class, represents a JSGF rule, with a nonterminal name representing the 119 | left hand side, and a list of possible expansions representing the right 120 | hand side.

121 |
122 | 123 |
124 | 125 | 126 |
127 |
128 |
129 |
130 |
131 |

Previous topic

132 |

Welcome to JSGF Grammar Tools’s documentation!

134 |

Next topic

135 |

JSGFParser module

137 |

This Page

138 | 142 | 154 | 155 |
156 |
157 |
158 |
159 | 177 | 181 | 182 | -------------------------------------------------------------------------------- /docs/_build/html/JSGFParser.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | JSGFParser module — JSGF Grammar Tools 1.0 documentation 10 | 11 | 12 | 13 | 14 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 49 | 50 |
51 |
52 |
53 |
54 | 55 |
56 |

JSGFParser module

57 |

This file parses a JSGF grammar file and returns a JSGFGrammar object. It uses the pyparsing module and defines a grammar for JSGF grammars. Upon finding a string or JSGF expression, it builds a grammar object from the bottom up, composing JSGF expressions with strings and lists. When the entire right hand side of a rule has been parsed and a JSGF expression object has been created of it, it gets added to the main JSGFGrammar object as one of its rules.

58 |

To run the parser independently and print the resulting JSGFGrammar object, run it as:

59 |
60 |
python JSGFParser.py Ideas.gram
61 |

Generally, this module should be imported and the getGrammarObject should be called with a file object as its argument. This function returns a grammar object that can be used by the Generator scripts DeterministicGenerator.py and ProbabilisticGenerator.py.

62 |
63 |
The features of JSGF that this parser can handle include:
64 |
    65 |
  • rulenames
  • 66 |
  • tokens
  • 67 |
  • comments
  • 68 |
  • rule definitions
  • 69 |
  • rule expansions
  • 70 |
  • sequences
  • 71 |
  • alternatives
  • 72 |
  • weights
  • 73 |
  • grouping
  • 74 |
  • optional grouping
  • 75 |
76 |
77 |
Notable features of JSGF that are not handled by this parser are:
78 |
    79 |
  • grammar names
  • 80 |
  • import statements
  • 81 |
  • unary operators
  • 82 |
  • tags
  • 83 |
84 |
85 |
86 |
87 |
88 | JSGFParser.foundNonterminal(s, loc, toks)
89 |

PyParsing action to run when a nonterminal reference is found.

90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 |
Returns:NonTerminal object representing the NT reference found
98 |
99 | 100 |
101 |
102 | JSGFParser.foundOptionalGroup(s, loc, toks)
103 |

PyParsing action to run when an optional group is found.

104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 |
Returns:Optional object containing all elements in the group
112 |
113 | 114 |
115 |
116 | JSGFParser.foundPair(s, loc, toks)
117 |

PyParsing action to run when a pair of alternatives are found.

118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 |
Returns:Disjunction object containing all disjuncts that have been accumulated so far
126 |
127 | 128 |
129 |
130 | JSGFParser.foundSeq(s, loc, toks)
131 |

PyParsing action to run when a sequence of concatenated elements is found.

132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 |
Returns:List of JSGFGrammar objects, strings, or more lists
140 |
141 | 142 |
143 |
144 | JSGFParser.foundToken(s, loc, toks)
145 |

PyParsing action to run when a token is found.

146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 |
Returns:Token as a string
154 |
155 | 156 |
157 |
158 | JSGFParser.foundWeight(s, loc, toks)
159 |

PyParsing action to run when a weight is found.

160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 |
Returns:Weight as a floating point number
168 |
169 | 170 |
171 |
172 | JSGFParser.foundWeightedExpression(s, loc, toks)
173 |

PyParsing action to run when a weighted expression is found.

174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 |
Returns:Ordered pair of the expression and its weight
182 |
183 | 184 |
185 |
186 | JSGFParser.getGrammarObject(fileStream)
187 |

Produces a JSGFGrammar object from a stream of text, the grammar object has a set of public rules and regular rules

188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 |
Parameters:fileStream (file object) – file object containing the contents of the grammar file
Returns:JSGFGrammar object
198 |
199 | 200 |
201 |
202 | JSGFParser.nocomment(oldline)
203 |

Removes a comment from a line

204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 |
Parameters:oldline – String representing the original line
Returns:String with the same semantic content, with the comments stripped
214 |
215 | 216 |
217 | 218 | 219 |
220 |
221 |
222 |
223 |
224 |

Previous topic

225 |

JSGFGrammar module

227 |

Next topic

228 |

Probabilistic Generator module

230 |

This Page

231 | 235 | 247 | 248 |
249 |
250 |
251 |
252 | 270 | 274 | 275 | -------------------------------------------------------------------------------- /docs/_build/html/ProbabilisticGenerator.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Probabilistic Generator module — JSGF Grammar Tools 1.0 documentation 10 | 11 | 12 | 13 | 14 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 49 | 50 |
51 |
52 |
53 |
54 | 55 |
56 |

Probabilistic Generator module

57 |

This file probabilistically generates strings from a JSGF grammar. It takes advantage of weights assigned to alternatives (separated by pipes) by choosing to expand higher weighted alternatives with greater probability. For sets of alternatives without weights, each alternative is equally likely to be expanded. For optional groups, the elements in the group have a 50% chance of being expanded.

58 |

It requires two arguments: the path to the JSGF Grammar file, and the number of strings to generate. You can run this on the included grammar Ideas.gram:

59 |
60 |
python ProbabilisticGenerator.py Ideas.gram 20
61 |

This will generate 20 sentences based on the public rule(s) in Ideas.gram, using the weights if they are provided.

62 |
63 |
64 | ProbabilisticGenerator.combineSets(listOfSets)
65 |

Combines sets of strings by taking the cross product of the sets and concatenating the elements in the resulting tuples

66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 |
Parameters:listOfSets – 2-D list of strings
Returns:a list of strings
76 |
77 | 78 |
79 |
80 | ProbabilisticGenerator.processDisjunction(disj)
81 |

Chooses either a random disjunct (for alternatives without weights) or 82 | a disjunct based on defined weights.

83 |
84 | 85 |
86 |
87 | ProbabilisticGenerator.processNonTerminal(nt)
88 |

Finds the rule expansion for a nonterminal and returns its expansion.

89 |
90 | 91 |
92 |
93 | ProbabilisticGenerator.processOptional(opt)
94 |

Processes the optional element 50% of the time, skips it the other 50% of the time

95 |
96 | 97 |
98 |
99 | ProbabilisticGenerator.processRHS(rhs)
100 |
101 | 102 |
103 |
104 | ProbabilisticGenerator.processSequence(seq)
105 |

Combines adjacent elements in a sequence.

106 |
107 | 108 |
109 |
110 | ProbabilisticGenerator.weightedChoice(listOfTuples)
111 |

Chooses an element of a list based on its weight

112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 |
Parameters:listOfTuples – a list of (element, weight) tuples, where the element can be a JSGF expression object, string, or list, and the weight is a float
Returns:the first element of a chosen tuple
122 |
123 | 124 |
125 | 126 | 127 |
128 |
129 |
130 |
131 |
132 |

Previous topic

133 |

JSGFParser module

135 |

Next topic

136 |

Deterministic Generator module

138 |

This Page

139 | 143 | 155 | 156 |
157 |
158 |
159 |
160 | 178 | 182 | 183 | -------------------------------------------------------------------------------- /docs/_build/html/_sources/DeterministicGenerator.txt: -------------------------------------------------------------------------------- 1 | Deterministic Generator module 2 | ============================== 3 | 4 | .. automodule:: DeterministicGenerator 5 | :members: 6 | :undoc-members: 7 | -------------------------------------------------------------------------------- /docs/_build/html/_sources/JSGFGrammar.txt: -------------------------------------------------------------------------------- 1 | JSGFGrammar module 2 | ================== 3 | 4 | .. automodule:: JSGFGrammar 5 | :members: 6 | :undoc-members: 7 | -------------------------------------------------------------------------------- /docs/_build/html/_sources/JSGFParser.txt: -------------------------------------------------------------------------------- 1 | JSGFParser module 2 | ================== 3 | 4 | .. automodule:: JSGFParser 5 | :members: 6 | :undoc-members: 7 | -------------------------------------------------------------------------------- /docs/_build/html/_sources/ProbabilisticGenerator.txt: -------------------------------------------------------------------------------- 1 | Probabilistic Generator module 2 | ============================== 3 | 4 | 5 | .. automodule:: ProbabilisticGenerator 6 | :members: 7 | :undoc-members: 8 | -------------------------------------------------------------------------------- /docs/_build/html/_sources/index.txt: -------------------------------------------------------------------------------- 1 | .. JSGF Grammar Tools documentation master file, created by 2 | sphinx-quickstart on Thu May 29 15:47:59 2014. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to JSGF Grammar Tools's documentation! 7 | ============================================== 8 | 9 | This set of tools is intended to aid the manipulation of 10 | JSGF Grammars. It includes a parser, and two string generators which 11 | can be used to create artificial corpora. Some additional tools that will 12 | be added in the near future include a tool to check grammars for recursion 13 | and a tool to calculate the total number of strings a grammar generates. 14 | 15 | Contents: 16 | 17 | .. toctree:: 18 | :maxdepth: 2 19 | 20 | JSGFGrammar 21 | JSGFParser 22 | ProbabilisticGenerator 23 | DeterministicGenerator 24 | 25 | 26 | 27 | Indices and tables 28 | ================== 29 | 30 | * :ref:`genindex` 31 | * :ref:`modindex` 32 | * :ref:`search` 33 | 34 | -------------------------------------------------------------------------------- /docs/_build/html/_static/ajax-loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syntactic/JSGFTools/907b91791abe523817b2c2f8e77c66a83d74935e/docs/_build/html/_static/ajax-loader.gif -------------------------------------------------------------------------------- /docs/_build/html/_static/basic.css: -------------------------------------------------------------------------------- 1 | /* 2 | * basic.css 3 | * ~~~~~~~~~ 4 | * 5 | * Sphinx stylesheet -- basic theme. 6 | * 7 | * :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS. 8 | * :license: BSD, see LICENSE for details. 9 | * 10 | */ 11 | 12 | /* -- main layout ----------------------------------------------------------- */ 13 | 14 | div.clearer { 15 | clear: both; 16 | } 17 | 18 | /* -- relbar ---------------------------------------------------------------- */ 19 | 20 | div.related { 21 | width: 100%; 22 | font-size: 90%; 23 | } 24 | 25 | div.related h3 { 26 | display: none; 27 | } 28 | 29 | div.related ul { 30 | margin: 0; 31 | padding: 0 0 0 10px; 32 | list-style: none; 33 | } 34 | 35 | div.related li { 36 | display: inline; 37 | } 38 | 39 | div.related li.right { 40 | float: right; 41 | margin-right: 5px; 42 | } 43 | 44 | /* -- sidebar --------------------------------------------------------------- */ 45 | 46 | div.sphinxsidebarwrapper { 47 | padding: 10px 5px 0 10px; 48 | } 49 | 50 | div.sphinxsidebar { 51 | float: left; 52 | width: 230px; 53 | margin-left: -100%; 54 | font-size: 90%; 55 | } 56 | 57 | div.sphinxsidebar ul { 58 | list-style: none; 59 | } 60 | 61 | div.sphinxsidebar ul ul, 62 | div.sphinxsidebar ul.want-points { 63 | margin-left: 20px; 64 | list-style: square; 65 | } 66 | 67 | div.sphinxsidebar ul ul { 68 | margin-top: 0; 69 | margin-bottom: 0; 70 | } 71 | 72 | div.sphinxsidebar form { 73 | margin-top: 10px; 74 | } 75 | 76 | div.sphinxsidebar input { 77 | border: 1px solid #98dbcc; 78 | font-family: sans-serif; 79 | font-size: 1em; 80 | } 81 | 82 | div.sphinxsidebar #searchbox input[type="text"] { 83 | width: 170px; 84 | } 85 | 86 | div.sphinxsidebar #searchbox input[type="submit"] { 87 | width: 30px; 88 | } 89 | 90 | img { 91 | border: 0; 92 | max-width: 100%; 93 | } 94 | 95 | /* -- search page ----------------------------------------------------------- */ 96 | 97 | ul.search { 98 | margin: 10px 0 0 20px; 99 | padding: 0; 100 | } 101 | 102 | ul.search li { 103 | padding: 5px 0 5px 20px; 104 | background-image: url(file.png); 105 | background-repeat: no-repeat; 106 | background-position: 0 7px; 107 | } 108 | 109 | ul.search li a { 110 | font-weight: bold; 111 | } 112 | 113 | ul.search li div.context { 114 | color: #888; 115 | margin: 2px 0 0 30px; 116 | text-align: left; 117 | } 118 | 119 | ul.keywordmatches li.goodmatch a { 120 | font-weight: bold; 121 | } 122 | 123 | /* -- index page ------------------------------------------------------------ */ 124 | 125 | table.contentstable { 126 | width: 90%; 127 | } 128 | 129 | table.contentstable p.biglink { 130 | line-height: 150%; 131 | } 132 | 133 | a.biglink { 134 | font-size: 1.3em; 135 | } 136 | 137 | span.linkdescr { 138 | font-style: italic; 139 | padding-top: 5px; 140 | font-size: 90%; 141 | } 142 | 143 | /* -- general index --------------------------------------------------------- */ 144 | 145 | table.indextable { 146 | width: 100%; 147 | } 148 | 149 | table.indextable td { 150 | text-align: left; 151 | vertical-align: top; 152 | } 153 | 154 | table.indextable dl, table.indextable dd { 155 | margin-top: 0; 156 | margin-bottom: 0; 157 | } 158 | 159 | table.indextable tr.pcap { 160 | height: 10px; 161 | } 162 | 163 | table.indextable tr.cap { 164 | margin-top: 10px; 165 | background-color: #f2f2f2; 166 | } 167 | 168 | img.toggler { 169 | margin-right: 3px; 170 | margin-top: 3px; 171 | cursor: pointer; 172 | } 173 | 174 | div.modindex-jumpbox { 175 | border-top: 1px solid #ddd; 176 | border-bottom: 1px solid #ddd; 177 | margin: 1em 0 1em 0; 178 | padding: 0.4em; 179 | } 180 | 181 | div.genindex-jumpbox { 182 | border-top: 1px solid #ddd; 183 | border-bottom: 1px solid #ddd; 184 | margin: 1em 0 1em 0; 185 | padding: 0.4em; 186 | } 187 | 188 | /* -- general body styles --------------------------------------------------- */ 189 | 190 | a.headerlink { 191 | visibility: hidden; 192 | } 193 | 194 | h1:hover > a.headerlink, 195 | h2:hover > a.headerlink, 196 | h3:hover > a.headerlink, 197 | h4:hover > a.headerlink, 198 | h5:hover > a.headerlink, 199 | h6:hover > a.headerlink, 200 | dt:hover > a.headerlink { 201 | visibility: visible; 202 | } 203 | 204 | div.body p.caption { 205 | text-align: inherit; 206 | } 207 | 208 | div.body td { 209 | text-align: left; 210 | } 211 | 212 | .field-list ul { 213 | padding-left: 1em; 214 | } 215 | 216 | .first { 217 | margin-top: 0 !important; 218 | } 219 | 220 | p.rubric { 221 | margin-top: 30px; 222 | font-weight: bold; 223 | } 224 | 225 | img.align-left, .figure.align-left, object.align-left { 226 | clear: left; 227 | float: left; 228 | margin-right: 1em; 229 | } 230 | 231 | img.align-right, .figure.align-right, object.align-right { 232 | clear: right; 233 | float: right; 234 | margin-left: 1em; 235 | } 236 | 237 | img.align-center, .figure.align-center, object.align-center { 238 | display: block; 239 | margin-left: auto; 240 | margin-right: auto; 241 | } 242 | 243 | .align-left { 244 | text-align: left; 245 | } 246 | 247 | .align-center { 248 | text-align: center; 249 | } 250 | 251 | .align-right { 252 | text-align: right; 253 | } 254 | 255 | /* -- sidebars -------------------------------------------------------------- */ 256 | 257 | div.sidebar { 258 | margin: 0 0 0.5em 1em; 259 | border: 1px solid #ddb; 260 | padding: 7px 7px 0 7px; 261 | background-color: #ffe; 262 | width: 40%; 263 | float: right; 264 | } 265 | 266 | p.sidebar-title { 267 | font-weight: bold; 268 | } 269 | 270 | /* -- topics ---------------------------------------------------------------- */ 271 | 272 | div.topic { 273 | border: 1px solid #ccc; 274 | padding: 7px 7px 0 7px; 275 | margin: 10px 0 10px 0; 276 | } 277 | 278 | p.topic-title { 279 | font-size: 1.1em; 280 | font-weight: bold; 281 | margin-top: 10px; 282 | } 283 | 284 | /* -- admonitions ----------------------------------------------------------- */ 285 | 286 | div.admonition { 287 | margin-top: 10px; 288 | margin-bottom: 10px; 289 | padding: 7px; 290 | } 291 | 292 | div.admonition dt { 293 | font-weight: bold; 294 | } 295 | 296 | div.admonition dl { 297 | margin-bottom: 0; 298 | } 299 | 300 | p.admonition-title { 301 | margin: 0px 10px 5px 0px; 302 | font-weight: bold; 303 | } 304 | 305 | div.body p.centered { 306 | text-align: center; 307 | margin-top: 25px; 308 | } 309 | 310 | /* -- tables ---------------------------------------------------------------- */ 311 | 312 | table.docutils { 313 | border: 0; 314 | border-collapse: collapse; 315 | } 316 | 317 | table.docutils td, table.docutils th { 318 | padding: 1px 8px 1px 5px; 319 | border-top: 0; 320 | border-left: 0; 321 | border-right: 0; 322 | border-bottom: 1px solid #aaa; 323 | } 324 | 325 | table.field-list td, table.field-list th { 326 | border: 0 !important; 327 | } 328 | 329 | table.footnote td, table.footnote th { 330 | border: 0 !important; 331 | } 332 | 333 | th { 334 | text-align: left; 335 | padding-right: 5px; 336 | } 337 | 338 | table.citation { 339 | border-left: solid 1px gray; 340 | margin-left: 1px; 341 | } 342 | 343 | table.citation td { 344 | border-bottom: none; 345 | } 346 | 347 | /* -- other body styles ----------------------------------------------------- */ 348 | 349 | ol.arabic { 350 | list-style: decimal; 351 | } 352 | 353 | ol.loweralpha { 354 | list-style: lower-alpha; 355 | } 356 | 357 | ol.upperalpha { 358 | list-style: upper-alpha; 359 | } 360 | 361 | ol.lowerroman { 362 | list-style: lower-roman; 363 | } 364 | 365 | ol.upperroman { 366 | list-style: upper-roman; 367 | } 368 | 369 | dl { 370 | margin-bottom: 15px; 371 | } 372 | 373 | dd p { 374 | margin-top: 0px; 375 | } 376 | 377 | dd ul, dd table { 378 | margin-bottom: 10px; 379 | } 380 | 381 | dd { 382 | margin-top: 3px; 383 | margin-bottom: 10px; 384 | margin-left: 30px; 385 | } 386 | 387 | dt:target, .highlighted { 388 | background-color: #fbe54e; 389 | } 390 | 391 | dl.glossary dt { 392 | font-weight: bold; 393 | font-size: 1.1em; 394 | } 395 | 396 | .field-list ul { 397 | margin: 0; 398 | padding-left: 1em; 399 | } 400 | 401 | .field-list p { 402 | margin: 0; 403 | } 404 | 405 | .optional { 406 | font-size: 1.3em; 407 | } 408 | 409 | .versionmodified { 410 | font-style: italic; 411 | } 412 | 413 | .system-message { 414 | background-color: #fda; 415 | padding: 5px; 416 | border: 3px solid red; 417 | } 418 | 419 | .footnote:target { 420 | background-color: #ffa; 421 | } 422 | 423 | .line-block { 424 | display: block; 425 | margin-top: 1em; 426 | margin-bottom: 1em; 427 | } 428 | 429 | .line-block .line-block { 430 | margin-top: 0; 431 | margin-bottom: 0; 432 | margin-left: 1.5em; 433 | } 434 | 435 | .guilabel, .menuselection { 436 | font-family: sans-serif; 437 | } 438 | 439 | .accelerator { 440 | text-decoration: underline; 441 | } 442 | 443 | .classifier { 444 | font-style: oblique; 445 | } 446 | 447 | abbr, acronym { 448 | border-bottom: dotted 1px; 449 | cursor: help; 450 | } 451 | 452 | /* -- code displays --------------------------------------------------------- */ 453 | 454 | pre { 455 | overflow: auto; 456 | overflow-y: hidden; /* fixes display issues on Chrome browsers */ 457 | } 458 | 459 | td.linenos pre { 460 | padding: 5px 0px; 461 | border: 0; 462 | background-color: transparent; 463 | color: #aaa; 464 | } 465 | 466 | table.highlighttable { 467 | margin-left: 0.5em; 468 | } 469 | 470 | table.highlighttable td { 471 | padding: 0 0.5em 0 0.5em; 472 | } 473 | 474 | tt.descname { 475 | background-color: transparent; 476 | font-weight: bold; 477 | font-size: 1.2em; 478 | } 479 | 480 | tt.descclassname { 481 | background-color: transparent; 482 | } 483 | 484 | tt.xref, a tt { 485 | background-color: transparent; 486 | font-weight: bold; 487 | } 488 | 489 | h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt { 490 | background-color: transparent; 491 | } 492 | 493 | .viewcode-link { 494 | float: right; 495 | } 496 | 497 | .viewcode-back { 498 | float: right; 499 | font-family: sans-serif; 500 | } 501 | 502 | div.viewcode-block:target { 503 | margin: -1px -10px; 504 | padding: 0 10px; 505 | } 506 | 507 | /* -- math display ---------------------------------------------------------- */ 508 | 509 | img.math { 510 | vertical-align: middle; 511 | } 512 | 513 | div.body div.math p { 514 | text-align: center; 515 | } 516 | 517 | span.eqno { 518 | float: right; 519 | } 520 | 521 | /* -- printout stylesheet --------------------------------------------------- */ 522 | 523 | @media print { 524 | div.document, 525 | div.documentwrapper, 526 | div.bodywrapper { 527 | margin: 0 !important; 528 | width: 100%; 529 | } 530 | 531 | div.sphinxsidebar, 532 | div.related, 533 | div.footer, 534 | #top-link { 535 | display: none; 536 | } 537 | } -------------------------------------------------------------------------------- /docs/_build/html/_static/comment-bright.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syntactic/JSGFTools/907b91791abe523817b2c2f8e77c66a83d74935e/docs/_build/html/_static/comment-bright.png -------------------------------------------------------------------------------- /docs/_build/html/_static/comment-close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syntactic/JSGFTools/907b91791abe523817b2c2f8e77c66a83d74935e/docs/_build/html/_static/comment-close.png -------------------------------------------------------------------------------- /docs/_build/html/_static/comment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syntactic/JSGFTools/907b91791abe523817b2c2f8e77c66a83d74935e/docs/_build/html/_static/comment.png -------------------------------------------------------------------------------- /docs/_build/html/_static/default.css: -------------------------------------------------------------------------------- 1 | /* 2 | * default.css_t 3 | * ~~~~~~~~~~~~~ 4 | * 5 | * Sphinx stylesheet -- default theme. 6 | * 7 | * :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS. 8 | * :license: BSD, see LICENSE for details. 9 | * 10 | */ 11 | 12 | @import url("basic.css"); 13 | 14 | /* -- page layout ----------------------------------------------------------- */ 15 | 16 | body { 17 | font-family: sans-serif; 18 | font-size: 100%; 19 | background-color: #11303d; 20 | color: #000; 21 | margin: 0; 22 | padding: 0; 23 | } 24 | 25 | div.document { 26 | background-color: #1c4e63; 27 | } 28 | 29 | div.documentwrapper { 30 | float: left; 31 | width: 100%; 32 | } 33 | 34 | div.bodywrapper { 35 | margin: 0 0 0 230px; 36 | } 37 | 38 | div.body { 39 | background-color: #ffffff; 40 | color: #000000; 41 | padding: 0 20px 30px 20px; 42 | } 43 | 44 | div.footer { 45 | color: #ffffff; 46 | width: 100%; 47 | padding: 9px 0 9px 0; 48 | text-align: center; 49 | font-size: 75%; 50 | } 51 | 52 | div.footer a { 53 | color: #ffffff; 54 | text-decoration: underline; 55 | } 56 | 57 | div.related { 58 | background-color: #133f52; 59 | line-height: 30px; 60 | color: #ffffff; 61 | } 62 | 63 | div.related a { 64 | color: #ffffff; 65 | } 66 | 67 | div.sphinxsidebar { 68 | } 69 | 70 | div.sphinxsidebar h3 { 71 | font-family: 'Trebuchet MS', sans-serif; 72 | color: #ffffff; 73 | font-size: 1.4em; 74 | font-weight: normal; 75 | margin: 0; 76 | padding: 0; 77 | } 78 | 79 | div.sphinxsidebar h3 a { 80 | color: #ffffff; 81 | } 82 | 83 | div.sphinxsidebar h4 { 84 | font-family: 'Trebuchet MS', sans-serif; 85 | color: #ffffff; 86 | font-size: 1.3em; 87 | font-weight: normal; 88 | margin: 5px 0 0 0; 89 | padding: 0; 90 | } 91 | 92 | div.sphinxsidebar p { 93 | color: #ffffff; 94 | } 95 | 96 | div.sphinxsidebar p.topless { 97 | margin: 5px 10px 10px 10px; 98 | } 99 | 100 | div.sphinxsidebar ul { 101 | margin: 10px; 102 | padding: 0; 103 | color: #ffffff; 104 | } 105 | 106 | div.sphinxsidebar a { 107 | color: #98dbcc; 108 | } 109 | 110 | div.sphinxsidebar input { 111 | border: 1px solid #98dbcc; 112 | font-family: sans-serif; 113 | font-size: 1em; 114 | } 115 | 116 | 117 | 118 | /* -- hyperlink styles ------------------------------------------------------ */ 119 | 120 | a { 121 | color: #355f7c; 122 | text-decoration: none; 123 | } 124 | 125 | a:visited { 126 | color: #355f7c; 127 | text-decoration: none; 128 | } 129 | 130 | a:hover { 131 | text-decoration: underline; 132 | } 133 | 134 | 135 | 136 | /* -- body styles ----------------------------------------------------------- */ 137 | 138 | div.body h1, 139 | div.body h2, 140 | div.body h3, 141 | div.body h4, 142 | div.body h5, 143 | div.body h6 { 144 | font-family: 'Trebuchet MS', sans-serif; 145 | background-color: #f2f2f2; 146 | font-weight: normal; 147 | color: #20435c; 148 | border-bottom: 1px solid #ccc; 149 | margin: 20px -20px 10px -20px; 150 | padding: 3px 0 3px 10px; 151 | } 152 | 153 | div.body h1 { margin-top: 0; font-size: 200%; } 154 | div.body h2 { font-size: 160%; } 155 | div.body h3 { font-size: 140%; } 156 | div.body h4 { font-size: 120%; } 157 | div.body h5 { font-size: 110%; } 158 | div.body h6 { font-size: 100%; } 159 | 160 | a.headerlink { 161 | color: #c60f0f; 162 | font-size: 0.8em; 163 | padding: 0 4px 0 4px; 164 | text-decoration: none; 165 | } 166 | 167 | a.headerlink:hover { 168 | background-color: #c60f0f; 169 | color: white; 170 | } 171 | 172 | div.body p, div.body dd, div.body li { 173 | text-align: justify; 174 | line-height: 130%; 175 | } 176 | 177 | div.admonition p.admonition-title + p { 178 | display: inline; 179 | } 180 | 181 | div.admonition p { 182 | margin-bottom: 5px; 183 | } 184 | 185 | div.admonition pre { 186 | margin-bottom: 5px; 187 | } 188 | 189 | div.admonition ul, div.admonition ol { 190 | margin-bottom: 5px; 191 | } 192 | 193 | div.note { 194 | background-color: #eee; 195 | border: 1px solid #ccc; 196 | } 197 | 198 | div.seealso { 199 | background-color: #ffc; 200 | border: 1px solid #ff6; 201 | } 202 | 203 | div.topic { 204 | background-color: #eee; 205 | } 206 | 207 | div.warning { 208 | background-color: #ffe4e4; 209 | border: 1px solid #f66; 210 | } 211 | 212 | p.admonition-title { 213 | display: inline; 214 | } 215 | 216 | p.admonition-title:after { 217 | content: ":"; 218 | } 219 | 220 | pre { 221 | padding: 5px; 222 | background-color: #eeffcc; 223 | color: #333333; 224 | line-height: 120%; 225 | border: 1px solid #ac9; 226 | border-left: none; 227 | border-right: none; 228 | } 229 | 230 | tt { 231 | background-color: #ecf0f3; 232 | padding: 0 1px 0 1px; 233 | font-size: 0.95em; 234 | } 235 | 236 | th { 237 | background-color: #ede; 238 | } 239 | 240 | .warning tt { 241 | background: #efc2c2; 242 | } 243 | 244 | .note tt { 245 | background: #d6d6d6; 246 | } 247 | 248 | .viewcode-back { 249 | font-family: sans-serif; 250 | } 251 | 252 | div.viewcode-block:target { 253 | background-color: #f4debf; 254 | border-top: 1px solid #ac9; 255 | border-bottom: 1px solid #ac9; 256 | } -------------------------------------------------------------------------------- /docs/_build/html/_static/doctools.js: -------------------------------------------------------------------------------- 1 | /* 2 | * doctools.js 3 | * ~~~~~~~~~~~ 4 | * 5 | * Sphinx JavaScript utilities for all documentation. 6 | * 7 | * :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS. 8 | * :license: BSD, see LICENSE for details. 9 | * 10 | */ 11 | 12 | /** 13 | * select a different prefix for underscore 14 | */ 15 | $u = _.noConflict(); 16 | 17 | /** 18 | * make the code below compatible with browsers without 19 | * an installed firebug like debugger 20 | if (!window.console || !console.firebug) { 21 | var names = ["log", "debug", "info", "warn", "error", "assert", "dir", 22 | "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", 23 | "profile", "profileEnd"]; 24 | window.console = {}; 25 | for (var i = 0; i < names.length; ++i) 26 | window.console[names[i]] = function() {}; 27 | } 28 | */ 29 | 30 | /** 31 | * small helper function to urldecode strings 32 | */ 33 | jQuery.urldecode = function(x) { 34 | return decodeURIComponent(x).replace(/\+/g, ' '); 35 | }; 36 | 37 | /** 38 | * small helper function to urlencode strings 39 | */ 40 | jQuery.urlencode = encodeURIComponent; 41 | 42 | /** 43 | * This function returns the parsed url parameters of the 44 | * current request. Multiple values per key are supported, 45 | * it will always return arrays of strings for the value parts. 46 | */ 47 | jQuery.getQueryParameters = function(s) { 48 | if (typeof s == 'undefined') 49 | s = document.location.search; 50 | var parts = s.substr(s.indexOf('?') + 1).split('&'); 51 | var result = {}; 52 | for (var i = 0; i < parts.length; i++) { 53 | var tmp = parts[i].split('=', 2); 54 | var key = jQuery.urldecode(tmp[0]); 55 | var value = jQuery.urldecode(tmp[1]); 56 | if (key in result) 57 | result[key].push(value); 58 | else 59 | result[key] = [value]; 60 | } 61 | return result; 62 | }; 63 | 64 | /** 65 | * highlight a given string on a jquery object by wrapping it in 66 | * span elements with the given class name. 67 | */ 68 | jQuery.fn.highlightText = function(text, className) { 69 | function highlight(node) { 70 | if (node.nodeType == 3) { 71 | var val = node.nodeValue; 72 | var pos = val.toLowerCase().indexOf(text); 73 | if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) { 74 | var span = document.createElement("span"); 75 | span.className = className; 76 | span.appendChild(document.createTextNode(val.substr(pos, text.length))); 77 | node.parentNode.insertBefore(span, node.parentNode.insertBefore( 78 | document.createTextNode(val.substr(pos + text.length)), 79 | node.nextSibling)); 80 | node.nodeValue = val.substr(0, pos); 81 | } 82 | } 83 | else if (!jQuery(node).is("button, select, textarea")) { 84 | jQuery.each(node.childNodes, function() { 85 | highlight(this); 86 | }); 87 | } 88 | } 89 | return this.each(function() { 90 | highlight(this); 91 | }); 92 | }; 93 | 94 | /** 95 | * Small JavaScript module for the documentation. 96 | */ 97 | var Documentation = { 98 | 99 | init : function() { 100 | this.fixFirefoxAnchorBug(); 101 | this.highlightSearchWords(); 102 | this.initIndexTable(); 103 | }, 104 | 105 | /** 106 | * i18n support 107 | */ 108 | TRANSLATIONS : {}, 109 | PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; }, 110 | LOCALE : 'unknown', 111 | 112 | // gettext and ngettext don't access this so that the functions 113 | // can safely bound to a different name (_ = Documentation.gettext) 114 | gettext : function(string) { 115 | var translated = Documentation.TRANSLATIONS[string]; 116 | if (typeof translated == 'undefined') 117 | return string; 118 | return (typeof translated == 'string') ? translated : translated[0]; 119 | }, 120 | 121 | ngettext : function(singular, plural, n) { 122 | var translated = Documentation.TRANSLATIONS[singular]; 123 | if (typeof translated == 'undefined') 124 | return (n == 1) ? singular : plural; 125 | return translated[Documentation.PLURALEXPR(n)]; 126 | }, 127 | 128 | addTranslations : function(catalog) { 129 | for (var key in catalog.messages) 130 | this.TRANSLATIONS[key] = catalog.messages[key]; 131 | this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); 132 | this.LOCALE = catalog.locale; 133 | }, 134 | 135 | /** 136 | * add context elements like header anchor links 137 | */ 138 | addContextElements : function() { 139 | $('div[id] > :header:first').each(function() { 140 | $('\u00B6'). 141 | attr('href', '#' + this.id). 142 | attr('title', _('Permalink to this headline')). 143 | appendTo(this); 144 | }); 145 | $('dt[id]').each(function() { 146 | $('\u00B6'). 147 | attr('href', '#' + this.id). 148 | attr('title', _('Permalink to this definition')). 149 | appendTo(this); 150 | }); 151 | }, 152 | 153 | /** 154 | * workaround a firefox stupidity 155 | */ 156 | fixFirefoxAnchorBug : function() { 157 | if (document.location.hash && $.browser.mozilla) 158 | window.setTimeout(function() { 159 | document.location.href += ''; 160 | }, 10); 161 | }, 162 | 163 | /** 164 | * highlight the search words provided in the url in the text 165 | */ 166 | highlightSearchWords : function() { 167 | var params = $.getQueryParameters(); 168 | var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; 169 | if (terms.length) { 170 | var body = $('div.body'); 171 | if (!body.length) { 172 | body = $('body'); 173 | } 174 | window.setTimeout(function() { 175 | $.each(terms, function() { 176 | body.highlightText(this.toLowerCase(), 'highlighted'); 177 | }); 178 | }, 10); 179 | $('') 181 | .appendTo($('#searchbox')); 182 | } 183 | }, 184 | 185 | /** 186 | * init the domain index toggle buttons 187 | */ 188 | initIndexTable : function() { 189 | var togglers = $('img.toggler').click(function() { 190 | var src = $(this).attr('src'); 191 | var idnum = $(this).attr('id').substr(7); 192 | $('tr.cg-' + idnum).toggle(); 193 | if (src.substr(-9) == 'minus.png') 194 | $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); 195 | else 196 | $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); 197 | }).css('display', ''); 198 | if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { 199 | togglers.click(); 200 | } 201 | }, 202 | 203 | /** 204 | * helper function to hide the search marks again 205 | */ 206 | hideSearchWords : function() { 207 | $('#searchbox .highlight-link').fadeOut(300); 208 | $('span.highlighted').removeClass('highlighted'); 209 | }, 210 | 211 | /** 212 | * make the url absolute 213 | */ 214 | makeURL : function(relativeURL) { 215 | return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; 216 | }, 217 | 218 | /** 219 | * get the current relative url 220 | */ 221 | getCurrentURL : function() { 222 | var path = document.location.pathname; 223 | var parts = path.split(/\//); 224 | $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { 225 | if (this == '..') 226 | parts.pop(); 227 | }); 228 | var url = parts.join('/'); 229 | return path.substring(url.lastIndexOf('/') + 1, path.length - 1); 230 | } 231 | }; 232 | 233 | // quick alias for translations 234 | _ = Documentation.gettext; 235 | 236 | $(document).ready(function() { 237 | Documentation.init(); 238 | }); 239 | -------------------------------------------------------------------------------- /docs/_build/html/_static/down-pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syntactic/JSGFTools/907b91791abe523817b2c2f8e77c66a83d74935e/docs/_build/html/_static/down-pressed.png -------------------------------------------------------------------------------- /docs/_build/html/_static/down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syntactic/JSGFTools/907b91791abe523817b2c2f8e77c66a83d74935e/docs/_build/html/_static/down.png -------------------------------------------------------------------------------- /docs/_build/html/_static/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syntactic/JSGFTools/907b91791abe523817b2c2f8e77c66a83d74935e/docs/_build/html/_static/file.png -------------------------------------------------------------------------------- /docs/_build/html/_static/minus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syntactic/JSGFTools/907b91791abe523817b2c2f8e77c66a83d74935e/docs/_build/html/_static/minus.png -------------------------------------------------------------------------------- /docs/_build/html/_static/plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syntactic/JSGFTools/907b91791abe523817b2c2f8e77c66a83d74935e/docs/_build/html/_static/plus.png -------------------------------------------------------------------------------- /docs/_build/html/_static/pygments.css: -------------------------------------------------------------------------------- 1 | .highlight .hll { background-color: #ffffcc } 2 | .highlight { background: #eeffcc; } 3 | .highlight .c { color: #408090; font-style: italic } /* Comment */ 4 | .highlight .err { border: 1px solid #FF0000 } /* Error */ 5 | .highlight .k { color: #007020; font-weight: bold } /* Keyword */ 6 | .highlight .o { color: #666666 } /* Operator */ 7 | .highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */ 8 | .highlight .cp { color: #007020 } /* Comment.Preproc */ 9 | .highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */ 10 | .highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */ 11 | .highlight .gd { color: #A00000 } /* Generic.Deleted */ 12 | .highlight .ge { font-style: italic } /* Generic.Emph */ 13 | .highlight .gr { color: #FF0000 } /* Generic.Error */ 14 | .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ 15 | .highlight .gi { color: #00A000 } /* Generic.Inserted */ 16 | .highlight .go { color: #333333 } /* Generic.Output */ 17 | .highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ 18 | .highlight .gs { font-weight: bold } /* Generic.Strong */ 19 | .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ 20 | .highlight .gt { color: #0044DD } /* Generic.Traceback */ 21 | .highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ 22 | .highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ 23 | .highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ 24 | .highlight .kp { color: #007020 } /* Keyword.Pseudo */ 25 | .highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ 26 | .highlight .kt { color: #902000 } /* Keyword.Type */ 27 | .highlight .m { color: #208050 } /* Literal.Number */ 28 | .highlight .s { color: #4070a0 } /* Literal.String */ 29 | .highlight .na { color: #4070a0 } /* Name.Attribute */ 30 | .highlight .nb { color: #007020 } /* Name.Builtin */ 31 | .highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */ 32 | .highlight .no { color: #60add5 } /* Name.Constant */ 33 | .highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */ 34 | .highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */ 35 | .highlight .ne { color: #007020 } /* Name.Exception */ 36 | .highlight .nf { color: #06287e } /* Name.Function */ 37 | .highlight .nl { color: #002070; font-weight: bold } /* Name.Label */ 38 | .highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ 39 | .highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */ 40 | .highlight .nv { color: #bb60d5 } /* Name.Variable */ 41 | .highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */ 42 | .highlight .w { color: #bbbbbb } /* Text.Whitespace */ 43 | .highlight .mf { color: #208050 } /* Literal.Number.Float */ 44 | .highlight .mh { color: #208050 } /* Literal.Number.Hex */ 45 | .highlight .mi { color: #208050 } /* Literal.Number.Integer */ 46 | .highlight .mo { color: #208050 } /* Literal.Number.Oct */ 47 | .highlight .sb { color: #4070a0 } /* Literal.String.Backtick */ 48 | .highlight .sc { color: #4070a0 } /* Literal.String.Char */ 49 | .highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ 50 | .highlight .s2 { color: #4070a0 } /* Literal.String.Double */ 51 | .highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ 52 | .highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */ 53 | .highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ 54 | .highlight .sx { color: #c65d09 } /* Literal.String.Other */ 55 | .highlight .sr { color: #235388 } /* Literal.String.Regex */ 56 | .highlight .s1 { color: #4070a0 } /* Literal.String.Single */ 57 | .highlight .ss { color: #517918 } /* Literal.String.Symbol */ 58 | .highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */ 59 | .highlight .vc { color: #bb60d5 } /* Name.Variable.Class */ 60 | .highlight .vg { color: #bb60d5 } /* Name.Variable.Global */ 61 | .highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */ 62 | .highlight .il { color: #208050 } /* Literal.Number.Integer.Long */ -------------------------------------------------------------------------------- /docs/_build/html/_static/searchtools.js: -------------------------------------------------------------------------------- 1 | /* 2 | * searchtools.js_t 3 | * ~~~~~~~~~~~~~~~~ 4 | * 5 | * Sphinx JavaScript utilties for the full-text search. 6 | * 7 | * :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS. 8 | * :license: BSD, see LICENSE for details. 9 | * 10 | */ 11 | 12 | 13 | /** 14 | * Porter Stemmer 15 | */ 16 | var Stemmer = function() { 17 | 18 | var step2list = { 19 | ational: 'ate', 20 | tional: 'tion', 21 | enci: 'ence', 22 | anci: 'ance', 23 | izer: 'ize', 24 | bli: 'ble', 25 | alli: 'al', 26 | entli: 'ent', 27 | eli: 'e', 28 | ousli: 'ous', 29 | ization: 'ize', 30 | ation: 'ate', 31 | ator: 'ate', 32 | alism: 'al', 33 | iveness: 'ive', 34 | fulness: 'ful', 35 | ousness: 'ous', 36 | aliti: 'al', 37 | iviti: 'ive', 38 | biliti: 'ble', 39 | logi: 'log' 40 | }; 41 | 42 | var step3list = { 43 | icate: 'ic', 44 | ative: '', 45 | alize: 'al', 46 | iciti: 'ic', 47 | ical: 'ic', 48 | ful: '', 49 | ness: '' 50 | }; 51 | 52 | var c = "[^aeiou]"; // consonant 53 | var v = "[aeiouy]"; // vowel 54 | var C = c + "[^aeiouy]*"; // consonant sequence 55 | var V = v + "[aeiou]*"; // vowel sequence 56 | 57 | var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0 58 | var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 59 | var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 60 | var s_v = "^(" + C + ")?" + v; // vowel in stem 61 | 62 | this.stemWord = function (w) { 63 | var stem; 64 | var suffix; 65 | var firstch; 66 | var origword = w; 67 | 68 | if (w.length < 3) 69 | return w; 70 | 71 | var re; 72 | var re2; 73 | var re3; 74 | var re4; 75 | 76 | firstch = w.substr(0,1); 77 | if (firstch == "y") 78 | w = firstch.toUpperCase() + w.substr(1); 79 | 80 | // Step 1a 81 | re = /^(.+?)(ss|i)es$/; 82 | re2 = /^(.+?)([^s])s$/; 83 | 84 | if (re.test(w)) 85 | w = w.replace(re,"$1$2"); 86 | else if (re2.test(w)) 87 | w = w.replace(re2,"$1$2"); 88 | 89 | // Step 1b 90 | re = /^(.+?)eed$/; 91 | re2 = /^(.+?)(ed|ing)$/; 92 | if (re.test(w)) { 93 | var fp = re.exec(w); 94 | re = new RegExp(mgr0); 95 | if (re.test(fp[1])) { 96 | re = /.$/; 97 | w = w.replace(re,""); 98 | } 99 | } 100 | else if (re2.test(w)) { 101 | var fp = re2.exec(w); 102 | stem = fp[1]; 103 | re2 = new RegExp(s_v); 104 | if (re2.test(stem)) { 105 | w = stem; 106 | re2 = /(at|bl|iz)$/; 107 | re3 = new RegExp("([^aeiouylsz])\\1$"); 108 | re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); 109 | if (re2.test(w)) 110 | w = w + "e"; 111 | else if (re3.test(w)) { 112 | re = /.$/; 113 | w = w.replace(re,""); 114 | } 115 | else if (re4.test(w)) 116 | w = w + "e"; 117 | } 118 | } 119 | 120 | // Step 1c 121 | re = /^(.+?)y$/; 122 | if (re.test(w)) { 123 | var fp = re.exec(w); 124 | stem = fp[1]; 125 | re = new RegExp(s_v); 126 | if (re.test(stem)) 127 | w = stem + "i"; 128 | } 129 | 130 | // Step 2 131 | re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; 132 | if (re.test(w)) { 133 | var fp = re.exec(w); 134 | stem = fp[1]; 135 | suffix = fp[2]; 136 | re = new RegExp(mgr0); 137 | if (re.test(stem)) 138 | w = stem + step2list[suffix]; 139 | } 140 | 141 | // Step 3 142 | re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; 143 | if (re.test(w)) { 144 | var fp = re.exec(w); 145 | stem = fp[1]; 146 | suffix = fp[2]; 147 | re = new RegExp(mgr0); 148 | if (re.test(stem)) 149 | w = stem + step3list[suffix]; 150 | } 151 | 152 | // Step 4 153 | re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; 154 | re2 = /^(.+?)(s|t)(ion)$/; 155 | if (re.test(w)) { 156 | var fp = re.exec(w); 157 | stem = fp[1]; 158 | re = new RegExp(mgr1); 159 | if (re.test(stem)) 160 | w = stem; 161 | } 162 | else if (re2.test(w)) { 163 | var fp = re2.exec(w); 164 | stem = fp[1] + fp[2]; 165 | re2 = new RegExp(mgr1); 166 | if (re2.test(stem)) 167 | w = stem; 168 | } 169 | 170 | // Step 5 171 | re = /^(.+?)e$/; 172 | if (re.test(w)) { 173 | var fp = re.exec(w); 174 | stem = fp[1]; 175 | re = new RegExp(mgr1); 176 | re2 = new RegExp(meq1); 177 | re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); 178 | if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) 179 | w = stem; 180 | } 181 | re = /ll$/; 182 | re2 = new RegExp(mgr1); 183 | if (re.test(w) && re2.test(w)) { 184 | re = /.$/; 185 | w = w.replace(re,""); 186 | } 187 | 188 | // and turn initial Y back to y 189 | if (firstch == "y") 190 | w = firstch.toLowerCase() + w.substr(1); 191 | return w; 192 | } 193 | } 194 | 195 | 196 | 197 | /** 198 | * Simple result scoring code. 199 | */ 200 | var Scorer = { 201 | // Implement the following function to further tweak the score for each result 202 | // The function takes a result array [filename, title, anchor, descr, score] 203 | // and returns the new score. 204 | /* 205 | score: function(result) { 206 | return result[4]; 207 | }, 208 | */ 209 | 210 | // query matches the full name of an object 211 | objNameMatch: 11, 212 | // or matches in the last dotted part of the object name 213 | objPartialMatch: 6, 214 | // Additive scores depending on the priority of the object 215 | objPrio: {0: 15, // used to be importantResults 216 | 1: 5, // used to be objectResults 217 | 2: -5}, // used to be unimportantResults 218 | // Used when the priority is not in the mapping. 219 | objPrioDefault: 0, 220 | 221 | // query found in title 222 | title: 15, 223 | // query found in terms 224 | term: 5 225 | }; 226 | 227 | 228 | /** 229 | * Search Module 230 | */ 231 | var Search = { 232 | 233 | _index : null, 234 | _queued_query : null, 235 | _pulse_status : -1, 236 | 237 | init : function() { 238 | var params = $.getQueryParameters(); 239 | if (params.q) { 240 | var query = params.q[0]; 241 | $('input[name="q"]')[0].value = query; 242 | this.performSearch(query); 243 | } 244 | }, 245 | 246 | loadIndex : function(url) { 247 | $.ajax({type: "GET", url: url, data: null, 248 | dataType: "script", cache: true, 249 | complete: function(jqxhr, textstatus) { 250 | if (textstatus != "success") { 251 | document.getElementById("searchindexloader").src = url; 252 | } 253 | }}); 254 | }, 255 | 256 | setIndex : function(index) { 257 | var q; 258 | this._index = index; 259 | if ((q = this._queued_query) !== null) { 260 | this._queued_query = null; 261 | Search.query(q); 262 | } 263 | }, 264 | 265 | hasIndex : function() { 266 | return this._index !== null; 267 | }, 268 | 269 | deferQuery : function(query) { 270 | this._queued_query = query; 271 | }, 272 | 273 | stopPulse : function() { 274 | this._pulse_status = 0; 275 | }, 276 | 277 | startPulse : function() { 278 | if (this._pulse_status >= 0) 279 | return; 280 | function pulse() { 281 | var i; 282 | Search._pulse_status = (Search._pulse_status + 1) % 4; 283 | var dotString = ''; 284 | for (i = 0; i < Search._pulse_status; i++) 285 | dotString += '.'; 286 | Search.dots.text(dotString); 287 | if (Search._pulse_status > -1) 288 | window.setTimeout(pulse, 500); 289 | } 290 | pulse(); 291 | }, 292 | 293 | /** 294 | * perform a search for something (or wait until index is loaded) 295 | */ 296 | performSearch : function(query) { 297 | // create the required interface elements 298 | this.out = $('#search-results'); 299 | this.title = $('

' + _('Searching') + '

').appendTo(this.out); 300 | this.dots = $('').appendTo(this.title); 301 | this.status = $('

').appendTo(this.out); 302 | this.output = $('