aboutsummaryrefslogtreecommitdiffstats
path: root/src/jcgp/backend/parsers/FunctionParser.java
blob: 806099ef02a35463336bfdaa0e1c60e943c83677 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
package jcgp.backend.parsers;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.Scanner;

import jcgp.backend.function.FunctionSet;
import jcgp.backend.resources.Resources;

/**
 * Contains a static method for parsing functions from a
 * .par file. 
 * 
 * @author Eduardo Pedroni
 *
 */
public abstract class FunctionParser {

	/**
	 * Reads the specified file and attempts to enable 
	 * and disable the functions in the FunctionSet 
	 * accordingly.
	 * <br><br>
	 * Standard CGP .par files do not contain enough information
	 * to determine if they match the currently selected function set.
	 * For this reason, the parser assumes the function set is correct
	 * and treats functions by their index rather than their name. Any
	 * index outside the bounds of the function set is ignored and a
	 * warning message is printed once parsing is complete.
	 * 
	 * @param file the .par file to parse.
	 * @param functionSet the function set whose functions should be modified. 
	 * @param resources used for printing console messages.
	 */
	public static void parse(File file, FunctionSet functionSet, Resources resources) {
		// create file reader and scanner to parse, return if file does not exist
		FileReader fr;
		try {
			fr = new FileReader(file);
		} catch (FileNotFoundException e) {
			resources.println("[Parser] Error: could not find " + file.getAbsolutePath());
			return;
		}
		
		Scanner in = new Scanner(fr);
		boolean excessFunctions = false;
		resources.println("[Parser] Parsing file: " + file.getAbsolutePath() + "...");
		
		/*
		 * The encoding used in .par files is quite simple, so regex matches are used to extract
		 * the values.
		 * 
		 * A standard .par file contains functions in the following format:
		 * 
		 * 0  1      modulus-0
		 * 0  1      sqrt-1
		 * 0  1      reciprocal-2
		 * 
		 * The first integer signals whether to enable or disable the function. Any non-zero value
		 * is treated as "enable". The second integer is the function arity. The integer following
		 * the function name is the function index. 
		 * 
		 * The scanner is used to return each line separately. Every line that ends in a number
		 * is treated as a function line and split into an array, which holds its composing integers.
		 * This array is then used to enable or disabled the indexed function.
		 * 
		 * A flag is raised if the index exceeds the total number of functions, and a warning is
		 * printed once parsing is complete regarding the index mismatch.
		 * 
		 */
		while (in.hasNextLine()) {
			String line = in.nextLine();
			if (line.substring(line.length() - 1).matches("[0-9]")) {
				String[] splitString = line.split("[^0-9]+");
				int functionIndex = Integer.parseInt(splitString[splitString.length - 1]);
				
				if (functionIndex < functionSet.getTotalFunctionCount()) {
					if (Integer.parseInt(splitString[0]) != 0) {
						functionSet.enableFunction(functionIndex);
						resources.println("[Parser] Enabled function: " + functionSet.getFunction(functionIndex));
					} else if (Integer.parseInt(splitString[0]) == 0) {
						functionSet.disableFunction(functionIndex);
						resources.println("[Parser] Disabled function: " + functionSet.getFunction(functionIndex));
					}
				} else {
					excessFunctions = true;
				}
			}
		}
		
		// warn the user function index went out of bounds
		if (excessFunctions) {
			resources.println("[Parser] Warning: the parameter file contained more functions than the current function set");
		}
		
		in.close();
		resources.println("[Parser] Finished parsing functions");
	}
}