sclass ProbabilisticParser1 { new ProbabilisticMachine pm; bool verbose; abstract class Action { abstract void run(State state); } abstract class Consumer extends Action { // override this or the next method double calcProbabilityForMatchedText(S s) { throw overrideMe(); } // tok is CNC starting & ending with code token double calcProbabilityForMatchedTokens(LS tok) { ret calcProbabilityForMatchedText(join(tok)); } void run(State state) { int maxTokensToConsume = state.remainingTokens(); for (int n = 0; n <= maxTokensToConsume; n++) { State s = state.prepareClone(); s.iNextToken += n*2; LS tok = subList(state.tok, state.iNextToken, s.iNextToken-1); s.probability = multiplyPercentages(s.probability, calcProbabilityForMatchedTokens(tok)); s.matches = revChainPlus(s.matches, pair(state, tok)); pm.addState(s); } } } noeq record ConsumeToken(S token) extends Consumer { double calcProbabilityForMatchedText(S s) { ret empty(s) ? 50 : levenSimilarityIntIC(s, token); } } noeq record Any extends Consumer { double calcProbabilityForMatchedText(S s) { ret 90; } } noeq record Filler extends Consumer { double calcProbabilityForMatchedTokens(LS tok) { ret 100-countCodeTokensInReversedCNC(tok)*10; } } noeq record EndOfInput extends Action { void run(State state) { State s = state.prepareClone(); if (!state.endOfInput()) s.probability /= 2; s.matches = revChainPlus(s.matches, pair(state, subList(s.tok, s.iNextToken))); pm.addState(s); } } class State extends ProbabilisticMachine.State { LS tok; // CNC int iNextToken = 1; ReverseChain> matches; // values: reversed CNC toString { ret super.toString() + " iNextToken=\*iNextToken*/, matches: " + matchesFromAction(); } LPair matchesFromAction() { ret mapPairsA(s -> s.action(), matches); } Action action() { ret remainingRule == null ? null : (Action) remainingRule.lhs; } bool endOfInput() { ret iNextToken >= l(tok); } int remainingTokens() { ret (l(tok)-iNextToken)/2+1; } S nextToken() { ret get(tok, iNextToken); } State emptyClone() { ret new State; } State prepareClone() { ret copyFields(this, (State) super.prepareClone(), 'tok, 'iNextToken, 'matches); } void runAction(O action) { assertSame(machine, pm); if (verbose) print("Running action: " + action + ", machine: " + machine); ((Action) action).run(this); } } BasicLogicRule patternToRule(S pattern) { ret BasicLogicRule( makeAnd(listPlus( mapWithIndex(javaTok(pattern), (i, t) -> even(i) ? new Filler : eq(t, "*") ? new Any : new ConsumeToken(t)), new EndOfInput)), formatFrag("parsed")); } // pattern e.g.: "Das * hat *."; void parse(S pattern, S input) { pm.reset(); addState(javaTok(input), patternToRule(pattern)); pm.think(); } void addState(LS tok, BasicLogicRule rule) { new State state; state.tok = tok; state.remainingRule = curryLHS(rule); pm.addState(state); } Matches stateToMatches(State state) { if (state == null) null; new LS out; for (Pair p : state.matchesFromAction()) if (p.a instanceof Any) out.add(join(p.b)); ret matches(out); } Matches bestMatches() { ret stateToMatches(bestDoneState()); } State bestDoneState() { ret first(pm.doneStates); } }