001/* 002 * Java Genetic Algorithm Library (jenetics-9.0.0). 003 * Copyright (c) 2007-2026 Franz Wilhelmstötter 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 * 017 * Author: 018 * Franz Wilhelmstötter (franz.wilhelmstoetter@gmail.com) 019 */ 020package io.jenetics.ext.grammar; 021 022import static java.util.Objects.requireNonNull; 023 024import java.util.Optional; 025 026import io.jenetics.ext.grammar.Cfg.NonTerminal; 027import io.jenetics.ext.grammar.Cfg.Symbol; 028import io.jenetics.ext.grammar.Cfg.Terminal; 029import io.jenetics.ext.util.Tree; 030import io.jenetics.ext.util.TreeNode; 031 032/** 033 * Standard implementation of a derivation-tree generator. The following code 034 * snippet lets you generate a derivation tree from a given grammar. 035 * {@snippet lang="java": 036 * final Cfg<String> cfg = Bnf.parse(""" 037 * <expr> ::= ( <expr> <op> <expr> ) | <num> | <var> | <fun> ( <arg>, <arg> ) 038 * <fun> ::= FUN1 | FUN2 039 * <arg> ::= <expr> | <var> | <num> 040 * <op> ::= + | - | * | / 041 * <var> ::= x | y 042 * <num> ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 043 * """ 044 * ); 045 * 046 * final var random = RandomGenerator.of("L64X256MixRandom"); 047 * final var generator = new DerivationTreeGenerator<String>( 048 * SymbolIndex.of(random), 049 * 1_000 050 * ); 051 * final Tree<Symbol<String>, ?> tree = generator.generate(cfg); 052 * } 053 * 054 * @see SentenceGenerator 055 * 056 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a> 057 * @since 7.1 058 * @version 7.1 059 */ 060public final class DerivationTreeGenerator<T> 061 implements Generator<T, Tree<Symbol<T>, ?>> 062{ 063 064 private final SymbolIndex _index; 065 private final int _limit; 066 067 /** 068 * Create a new derivation tree generator from the given parameters. 069 * 070 * @param index the symbol index function used for generating the derivation 071 * tree 072 * @param limit the maximal allowed nodes of the tree. If the generated 073 * tree exceeds this length, the generation is interrupted and 074 * an empty tree is returned. If a tree is empty can be checked with 075 * {@link Tree#isEmpty()}. 076 */ 077 public DerivationTreeGenerator( 078 final SymbolIndex index, 079 final int limit 080 ) { 081 _index = requireNonNull(index); 082 _limit = limit; 083 } 084 085 /** 086 * Generates a new derivation tree from the given grammar, <em>cfg</em>. 087 * 088 * @see Tree#isEmpty() 089 * 090 * @param cfg the generating grammar 091 * @return a newly created derivation tree, or an empty tree if 092 * the number of nodes exceeds the defined node limit 093 */ 094 @Override 095 public Tree<Symbol<T>, ?> generate(final Cfg<? extends T> cfg) { 096 final Cfg<T> grammar = Cfg.upcast(cfg); 097 final NonTerminal<T> start = grammar.start(); 098 final TreeNode<Symbol<T>> symbols = TreeNode.of(start); 099 100 int count = 1; 101 boolean expanded = true; 102 while (expanded) { 103 final Optional<TreeNode<Symbol<T>>> tree = symbols.leaves() 104 .filter(leave -> 105 leave.value() instanceof NonTerminal<T> nt && 106 cfg.rule(nt).isPresent() 107 ) 108 .findFirst(); 109 110 if (tree.isPresent()) { 111 final var t = tree.orElseThrow(); 112 final var selection = Generator.select( 113 (NonTerminal<T>)t.value(), 114 grammar, 115 _index 116 ); 117 count += selection.size(); 118 119 if (count > _limit) { 120 return TreeNode.of(); 121 } 122 123 selection.forEach(t::attach); 124 } 125 126 expanded = tree.isPresent(); 127 } 128 129 return symbols; 130 } 131 132 public static <T> Tree<Terminal<T>, ?> 133 toAst(final Tree<Symbol<T>, ?> derivationTree) { 134 final TreeNode<Terminal<T>> abstractSyntaxTree = TreeNode.of(); 135 prune(derivationTree, abstractSyntaxTree); 136 return abstractSyntaxTree; 137 } 138 139 private static <T> void prune( 140 final Tree<Symbol<T>, ?> derivationTree, 141 final TreeNode<Terminal<T>> abstractSyntaxTree 142 ) { 143 if (derivationTree.value() instanceof Terminal<T> terminal) { 144 abstractSyntaxTree.value(terminal); 145 } 146 147 for (int i = 0; i < derivationTree.childCount(); ++i) { 148 TreeNode<Terminal<T>> targetChild = abstractSyntaxTree; 149 if (abstractSyntaxTree.value() != null) { 150 targetChild = TreeNode.of(); 151 abstractSyntaxTree.attach(targetChild); 152 } 153 154 prune(derivationTree.childAt(i), targetChild); 155 } 156 } 157 158 /* 159 public static <T> void prune( 160 final Tree<? extends T, ?> source, 161 final TreeNode<T> target, 162 final Predicate<? super T> filter 163 ) { 164 if (filter.test(source.value())) { 165 target.value(source.value()); 166 } 167 168 for (int i = 0; i < source.childCount(); ++i) { 169 TreeNode<T> targetChild = target; 170 if (target.value() != null) { 171 targetChild = TreeNode.of(); 172 target.attach(targetChild); 173 } 174 175 prune(source.childAt(i), targetChild, filter); 176 } 177 } 178 */ 179 180}