#!/usr/bin/env python3 # -*- coding: utf-8 -*- # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import random import re import sys class Sentence_generator: punctuation_re = re.compile(' ([^ ]+)$') variable_re = re.compile(r'\$([^_\$:]+)') def __init__(self, non_terminals, terminals, unique=False, verbosity=0, err_file=sys.stderr): self.non_terminals = non_terminals self.terminals = terminals self.unique = unique self.verbosity = verbosity self.err_file = err_file if self.unique: self.cache = set() def err(self, *args, **kwargs): if kwargs.pop('verbosity', 0) <= self.verbosity: print(kwargs.pop('align_char', ' ')*kwargs.pop('align_level', 0), end='', file=self.err_file) print(*args, file=sys.stderr, **kwargs) def compile_symbols(self, symbols, variables, level): def sub(match): a = match.group(1) if a not in variables: variables[a] = random.choice(self.non_terminals[a][0]) self.err('choosing', a+'='+variables[a], align_level=level*2, verbosity=2) return variables[a] s = [self.variable_re.sub(sub, symbol) for symbol in symbols] return s def generate_from_symbols(self, symbols, variables=None, r=None, level=0): if variables is None: variables = {} if r is None: r = [] symbols = self.compile_symbols(symbols, variables, level) for symbol in symbols: if ':' in symbol: symbol, attributes = symbol.split(':') attributes = attributes.split(',') if symbol not in self.non_terminals: r.append(symbol) continue v = {} for a in attributes: if a not in variables: variables[a] = random.choice(self.non_terminals[a][0]) self.err('choosing', a+'='+variables[a], 'for', symbol, align_level=level*2, verbosity=2) v[a] = variables[a] c = random.choice(self.non_terminals[symbol]) self.err(symbol, '→', ' '.join(c), align_level=level*2, verbosity=1) self.generate_from_symbols(c, v, r, level+1) elif symbol in self.non_terminals: c = random.choice(self.non_terminals[symbol]) self.err(symbol, '→', ' '.join(c), align_level=level*2, verbosity=1) self.generate_from_symbols(c, None, r, level+1) elif symbol in self.terminals: r.append(random.choice(self.terminals[symbol])) self.err(symbol, '→', r[-1], align_level=level*2, verbosity=1) else: r.append(symbol) return r def generate_sentence(self): r = self.generate_from_symbols(['_Sentence']) r[0] = r[0][0].upper() + r[0][1:] r = ' '.join(r) r = self.punctuation_re.sub(r'\1', r) for a, b in self.terminals['_Replacements']: r = r.replace(a, b) return r