aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--parser.php341
1 files changed, 178 insertions, 163 deletions
diff --git a/parser.php b/parser.php
index 1c1761a..ba6a054 100644
--- a/parser.php
+++ b/parser.php
@@ -1,8 +1,23 @@
<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle 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.
+//
+// Moodle 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 Moodle. If not, see <http://www.gnu.org/licenses/>.
+
// Parser code for the Moodle Algebra question type
// Moodle algebra question type class
// Author: Roger Moore <rwmoore 'at' ualberta.ca>
-// License: GNU Public License version 3
+// License: GNU Public License version 3.
defined('MOODLE_INTERNAL') || die();
@@ -33,13 +48,13 @@ if (!function_exists('lcfirst')) {
* @return -1 if $a is longer than $b, 0 if they are the same length and +1 if $a is shorter
*/
function qtype_algebra_parser_strlen_sort($a, $b) {
- // Get the two string lengths once so we don't have to repeat the function call
+ // Get the two string lengths once so we don't have to repeat the function call.
$alen = strlen($a);
$blen = strlen($b);
- // If the two lengths are equal return zero
+ // If the two lengths are equal return zero.
if ($alen == $blen) return 0;
- // Otherwise return +1 if a>b or -1 if a<b
- return ($alen>$blen) ? -1 : +1;
+ // Otherwise return +1 if a > b or -1 if a < b.
+ return ($alen > $blen) ? -1 : +1;
}
@@ -87,15 +102,15 @@ class qtype_algebra_parser_term {
// Create an empty array to store the arguments in
$args = array();
// Handle zero argument terms differently by making the
- // first 'argument' the value of the term itself
+ // first 'argument' the value of the term itself.
if ($this->_nargs == 0) {
$args[] = $this->_value;
} else {
- foreach($this->_arguments as $arg) {
+ foreach ($this->_arguments as $arg) {
$args[] = $arg->$method();
}
}
- // Return the array of arguments
+ // Return the array of arguments.
return $args;
}
@@ -108,13 +123,13 @@ class qtype_algebra_parser_term {
* @return string input syntax format string of the expression
*/
public function str() {
- // First check to see if the class has been given all the arguments
+ // First check to see if the class has been given all the arguments.
$this->check_arguments();
- // Get an array of all the arguments except for the format string
+ // Get an array of all the arguments except for the format string.
$args = $this->print_args('str');
- // Insert the format string at the front of the argument array
+ // Insert the format string at the front of the argument array.
array_unshift($args, $this->_formats['str']);
- // Call sprintf using the argument array as the arguments
+ // Call sprintf using the argument array as the arguments.
return call_user_func_array('sprintf', $args);
}
@@ -129,13 +144,13 @@ class qtype_algebra_parser_term {
* @return LaTeX format string of the expression
*/
public function tex() {
- // First check to see if the class has been given all the arguments
+ // First check to see if the class has been given all the arguments.
$this->check_arguments();
- // Get an array of all the arguments except for the format string
+ // Get an array of all the arguments except for the format string.
$args = $this->print_args('tex');
- // Insert the format string at the front of the argument array
+ // Insert the format string at the front of the argument array.
array_unshift($args, $this->_formats['tex']);
- // Call sprintf using the argument array as the arguments
+ // Call sprintf using the argument array as the arguments.
return call_user_func_array('sprintf', $args);
}
@@ -150,21 +165,21 @@ class qtype_algebra_parser_term {
* @return SAGE format string of the expression
*/
public function sage() {
- // First check to see if the class has been given all the arguments
+ // First check to see if the class has been given all the arguments.
$this->check_arguments();
- // Get an array of all the arguments except for the format string
+ // Get an array of all the arguments except for the format string.
$args = $this->print_args('sage');
// Insert the format string at the front of the argument array. First we
// check to see if there is a format element called 'sage' if not then we
- // default to the standard string format
+ // default to the standard string format.
if (array_key_exists('sage', $this->_formats)) {
- // Insert the sage format string at the front of the argument array
+ // Insert the sage format string at the front of the argument array.
array_unshift($args, $this->_formats['sage']);
} else {
- // Insert the normal format string at the front of the argument array
+ // Insert the normal format string at the front of the argument array.
array_unshift($args, $this->_formats['str']);
}
- // Call sprintf using the argument array as the arguments
+ // Call sprintf using the argument array as the arguments.
return call_user_func_array('sprintf', $args);
}
@@ -263,16 +278,16 @@ class qtype_algebra_parser_term {
* @return an array containing all the terms of the selected type keyed by their value
*/
public function collect(&$list, $type) {
- // Add this class to the list if of the correct type
+ // Add this class to the list if of the correct type.
if (is_a($this, $type)) {
// Add a key to the array with the value of the term, this means
// that multiple terms with the same value will overwrite each
// other so only one will remain.
$list[$this->_value] = 0;
}
- // Now loop over all the argument for this term (if any) and check them
- foreach($this->_arguments as $arg) {
- // Collect terms from the arguments as well
+ // Now loop over all the argument for this term (if any) and check them.
+ foreach ($this->_arguments as $arg) {
+ // Collect terms from the arguments as well.
$arg->collect($list, $type);
}
}
@@ -288,7 +303,7 @@ class qtype_algebra_parser_term {
* @return true if the terms match, false otherwise
*/
public function equals($term) {
- // Default method just checks to ensure that the Terms are both of the same type
+ // Default method just checks to ensure that the Terms are both of the same type.
return is_a($term, get_class($this));
}
@@ -305,13 +320,13 @@ class qtype_algebra_parser_term {
* @return true if the expressions match, false otherwise
*/
public function equivalent($expr) {
- // Check that the argument is also a term
+ // Check that the argument is also a term.
if (!is_a($expr, 'qtype_algebra_parser_term')) {
throw new Exception(get_string('badequivtype', 'qtype_algebra'));
}
- // Now check that this term is the same as the given term
+ // Now check that this term is the same as the given term.
if (!$this->equals($expr)) {
- // Terms are not equal immediately return false since the two do not match
+ // Terms are not equal immediately return false since the two do not match.
return false;
}
// Now compare the arguments recursively...
@@ -321,18 +336,18 @@ class qtype_algebra_parser_term {
// because there are no arguments to check we are equivalent!
return true;
case 1:
- // For one argument we also need to compare the argument of each term
+ // For one argument we also need to compare the argument of each term.
return $this->_arguments[0]->equivalent($expr->_arguments[0]);
case 2:
// Now it gets interesting. First we compare the two arguments in the same
// order and see what we get...
if ($this->_arguments[0]->equivalent($expr->_arguments[0]) and
$this->_arguments[1]->equivalent($expr->_arguments[1])) {
- // Both arguments are equivalent so we have a match
+ // Both arguments are equivalent so we have a match.
return true;
}
// Otherwise if the operator commutes we can see if the first argument matches
- // the second argument and vice versa
+ // the second argument and vice versa.
else if ($this->_commutes and $this->_arguments[0]->equivalent($expr->_arguments[1]) and
$this->_arguments[1]->equivalent($expr->_arguments[0])) {
return true;
@@ -386,7 +401,7 @@ class qtype_algebra_parser_term {
} else {
echo "'>\n";
}
- foreach($this->_arguments as $arg) {
+ foreach ($this->_arguments as $arg) {
$arg->dump($params, $indent.' ');
}
}
@@ -404,11 +419,11 @@ class qtype_algebra_parser_term {
return '<Algebraic parser term of type \''.get_class($this).'\'>';
}
- // Member variables
- var $_value; // String of the actual term itself
- var $_arguments = array(); // Array of arguments in class form
- var $_formats; // Array of format strings
- var $_nargs; // Number of arguments for this term
+ // Member variables.
+ var $_value; // String of the actual term itself.
+ var $_arguments = array(); // Array of arguments in class form.
+ var $_formats; // Array of format strings.
+ var $_nargs; // Number of arguments for this term.
}
/**
@@ -452,11 +467,11 @@ class qtype_algebra_parser_nullterm extends qtype_algebra_parser_term {
* @param $params array of the variable values to use
*/
public function evaluate($params) {
- // Return something which is not a number
+ // Return something which is not a number.
return acos(2.0);
}
- // Static class properties
+ // Static class properties.
const NARGS = 0;
private static $formats = array('str' => '',
'tex' => '');
@@ -483,10 +498,10 @@ class qtype_algebra_parser_number extends qtype_algebra_parser_term {
public function __construct($text = '') {
// Unfortunately PHP maths will only support a '.' as a decimal point and will not support
// ',' as used in Danish, French etc. To allow for this we always convert any commas into
- // decimal points before we parse the string
+ // decimal points before we parse the string.
$text = str_replace(',', '.', $text);
$this->_sign = '';
- // Now determine whether this is in exponent form or just a plain number
+ // Now determine whether this is in exponent form or just a plain number.
if (preg_match('/([\.0-9]+)E([-+]?\d+)/', $text, $m)) {
$this->_base = $m[1];
$this->_exp = $m[2];
@@ -508,7 +523,7 @@ class qtype_algebra_parser_number extends qtype_algebra_parser_term {
* not have a variable or another number preceding it.
*/
public function set_negative() {
- // Prepend a minus sign to both the base and total value strings
+ // Prepend a minus sign to both the base and total value strings.
$this->_base = '-'.$this->_base;
$this->_value = '-'.$this->_value;
$this->_sign = '-';
@@ -524,7 +539,7 @@ class qtype_algebra_parser_number extends qtype_algebra_parser_term {
* @return true if the terms match, false otherwise
*/
public function equals($expr) {
- // Call the default method first to check type
+ // Call the default method first to check type.
if (parent::equals($expr)) {
return (float)$this->_value == (float)$expr->_value;
} else {
@@ -548,14 +563,14 @@ class qtype_algebra_parser_number extends qtype_algebra_parser_term {
// decimal point (which we have to use internally because of the PHP math standard)
// with the correct string from the language pack
$base = str_replace('.', get_string('decimal', 'qtype_algebra'), $this->_base);
- // Put the base part of the number into the argument array
+ // Put the base part of the number into the argument array.
$args = array($base);
// Check to see if we have an exponent...
if ($this->_exp) {
- // ...we do so add it to the argument array as well
+ // We do so add it to the argument array as well.
$args[] = $this->_exp;
}
- // Return the list of arguments
+ // Return the list of arguments.
return $args;
}
@@ -571,7 +586,7 @@ class qtype_algebra_parser_number extends qtype_algebra_parser_term {
return doubleval($this->_value);
}
- // Static class properties
+ // Static class properties.
const NARGS = 0;
private static $formats = array('str' => '%s',
'tex' => '%s ');
@@ -629,38 +644,38 @@ class qtype_algebra_parser_variable extends qtype_algebra_parser_term {
* @param $text text matching the variable name
*/
public function __construct($text) {
- // Create the array to store the regular expression matches in
+ // Create the array to store the regular expression matches in.
$m = array();
- // Set the sign of the variable to be empty
+ // Set the sign of the variable to be empty.
$this->_sign = '';
- // Try to match the text to a greek letter
+ // Try to match the text to a greek letter.
if (preg_match('/('.implode('|', self::$greek).')/A', $text, $m)) {
- // Take the base name of the variable to be the greek letter
+ // Take the base name of the variable to be the greek letter.
$this->_base = $m[1];
- // Extract the remaining characters for use as the subscript
+ // Extract the remaining characters for use as the subscript.
$this->_subscript = substr($text, strlen($m[1]));
- // If the first letter of the subscript is an underscore then remove it
+ // If the first letter of the subscript is an underscore then remove it.
if ($this->_subscript[0] == '_') {
$this->_subscript = substr($this->_subscript, 1);
}
// Call the base class constructor with the variable text set to the combination of the
- // base name and the subscript without an underscore between them
+ // base name and the subscript without an underscore between them.
parent::__construct(self::NARGS, self::$formats['greek'],
$this->_base.$this->_subscript);
}
// Otherwise we have a simple multi-letter variable name. Treat the fist letter as the base
- // name and the rest as the subscript
+ // name and the rest as the subscript.
else {
- // Get the variable's base name
+ // Get the variable's base name.
$this->_base = substr($text, 0, 1);
- // Now set the subscript to the remaining letters
+ // Now set the subscript to the remaining letters.
$this->_subscript = substr($text, 1);
- // If the first letter of the subscript is an underscore then remove it
+ // If the first letter of the subscript is an underscore then remove it.
if ($this->_subscript[0] == '_') {
$this->_subscript = substr($this->_subscript, 1);
}
// Call the base class constructor with the variable text set to the combination of the
- // base name and the subscript without an underscore between them
+ // base name and the subscript without an underscore between them.
parent::__construct(self::NARGS, self::$formats['std'],
$this->_base.$this->_subscript);
}
@@ -709,7 +724,7 @@ class qtype_algebra_parser_variable extends qtype_algebra_parser_term {
if (array_key_exists($this->_value, $params)) {
return $mult*doubleval($params[$this->_value]);
} else {
- // Found an indefined variable. Cannot evaluate numerically so throw exception
+ // Found an indefined variable. Cannot evaluate numerically so throw exception.
throw new Exception(get_string('undefinedvariable', 'qtype_algebra', $this->_value));
}
}
@@ -724,7 +739,7 @@ class qtype_algebra_parser_variable extends qtype_algebra_parser_term {
* @return true if the terms match, false otherwise
*/
public function equals($expr) {
- // Call the default method first to check type
+ // Call the default method first to check type.
if (parent::equals($expr)) {
return $this->_value == $expr->_value and $this->_sign == $expr->_sign;
} else {
@@ -732,7 +747,7 @@ class qtype_algebra_parser_variable extends qtype_algebra_parser_term {
}
}
- // Static class properties
+ // Static class properties.
const NARGS = 0;
private static $formats = array(
'greek' => array('str' => '%s%s%s',
@@ -781,7 +796,7 @@ class qtype_algebra_parser_power extends qtype_algebra_parser_term {
doubleval($this->_arguments[1]->evaluate($params)));
}
- // Static class properties
+ // Static class properties.
const NARGS = 2;
private static $formats = array(
'str' => '%s^%s',
@@ -824,19 +839,19 @@ class qtype_algebra_parser_divide extends qtype_algebra_parser_term {
*/
public function evaluate($params) {
$this->check_arguments();
- // Get the value we are trying to divide by
+ // Get the value we are trying to divide by.
$divby = $this->_arguments[1]->evaluate($params);
- // Check to see if this is zero
+ // Check to see if this is zero.
if ($divby == 0) {
// Check the sign of the other argument and use to determine whether we return
- // plus or minus infinity
+ // plus or minus infinity.
return INF*$this->_arguments[0]->evaluate($params);
} else {
return $this->_arguments[0]->evaluate($params)/$divby;
}
}
- // Static class properties
+ // Static class properties.
const NARGS = 2;
private static $formats = array(
'str' => '%s/%s',
@@ -882,13 +897,13 @@ class qtype_algebra_parser_multiply extends qtype_algebra_parser_term {
*/
public function set_arguments($args) {
// First perform default argument setting method. This will generate
- // an error if there is a problem with the number of arguments
+ // an error if there is a problem with the number of arguments.
parent::set_arguments($args);
- // Set the default explicit format
+ // Set the default explicit format.
$this->_formats = $this->mformats['*'];
// Only allow the implicit multipication if the second argument is either a
// special, variable, function or bracket and not negative. In all other cases the operator must be
- // explicitly written
+ // explicitly written.
if (is_a($args[1], 'qtype_algebra_parser_bracket') or
is_a($args[1], 'qtype_algebra_parser_variable') or
is_a($args[1], 'qtype_algebra_parser_special') or
@@ -898,7 +913,7 @@ class qtype_algebra_parser_multiply extends qtype_algebra_parser_term {
}
}
// Check for one more special exemption: if the second argument is a power expression
- // then we use the same criteria on the first argument of it
+ // then we use the same criteria on the first argument of it.
if (is_a($args[1], 'qtype_algebra_parser_power')) {
// Get the arguments from the power term. Note we do not check these since
// power terms are parsed before multiplication ones and are required to
@@ -933,7 +948,7 @@ class qtype_algebra_parser_multiply extends qtype_algebra_parser_term {
$this->_arguments[1]->evaluate($params);
}
- // Static class properties
+ // Static class properties.
const NARGS = 2;
}
@@ -976,7 +991,7 @@ class qtype_algebra_parser_add extends qtype_algebra_parser_term {
$this->_arguments[1]->evaluate($params);
}
- // Static class properties
+ // Static class properties.
const NARGS = 2;
private static $formats = array(
'str' => '%s+%s',
@@ -1023,7 +1038,7 @@ class qtype_algebra_parser_subtract extends qtype_algebra_parser_term {
$this->_arguments[1]->evaluate($params);
}
- // Static class properties
+ // Static class properties.
const NARGS = 2;
private static $formats = array(
'str' => '%s-%s',
@@ -1061,7 +1076,7 @@ class qtype_algebra_parser_special extends qtype_algebra_parser_term {
* not have a variable or another number preceding it.
*/
public function set_negative() {
- // Set the sign to be a '-'
+ // Set the sign to be a '-'.
$this->_sign = '-';
}
@@ -1114,7 +1129,7 @@ class qtype_algebra_parser_special extends qtype_algebra_parser_term {
* @return true if the terms match, false otherwise
*/
public function equals($expr) {
- // Call the default method first to check type
+ // Call the default method first to check type.
if (parent::equals($expr)) {
return $this->_value == $expr->_value and $this->_sign == $this->_sign;
} else {
@@ -1122,7 +1137,7 @@ class qtype_algebra_parser_special extends qtype_algebra_parser_term {
}
}
- // Static class properties
+ // Static class properties.
const NARGS = 0;
private static $formats = array(
'pi' => array( 'str' => '%spi',
@@ -1172,7 +1187,7 @@ class qtype_algebra_parser_function extends qtype_algebra_parser_term {
* not have a variable or another number preceding it e.g. 3*-sin(x)
*/
public function set_negative() {
- // Set the sign to be a '-'
+ // Set the sign to be a '-'.
$this->_sign = '-';
}
@@ -1190,25 +1205,25 @@ class qtype_algebra_parser_function extends qtype_algebra_parser_term {
throw new Exception(get_string('badfuncargs', 'qtype_algebra', $this->_value));
}
if (!is_a($args[0], 'qtype_algebra_parser_bracket')) {
- // Check to see if this function requires a special bracket
+ // Check to see if this function requires a special bracket.
if (in_array($this->_value, self::$bracketmap)) {
$b = new qtype_algebra_parser_bracket('<');
}
- // Does not require special brackets so create normal ones
+ // Does not require special brackets so create normal ones.
else {
$b = new qtype_algebra_parser_bracket('(');
}
$b->set_arguments($args);
$this->_arguments = array($b);
}
- // First term already a bracket
+ // First term already a bracket.
else {
- // Check to see if we need a special bracket
+ // Check to see if we need a special bracket.
if (in_array($this->_value, self::$bracketmap)) {
// Make the bracket special
$args[0]->make_special();
}
- // Set the arguments to the given type
+ // Set the arguments to the given type.
$this->_arguments = $args;
}
}
@@ -1223,7 +1238,7 @@ class qtype_algebra_parser_function extends qtype_algebra_parser_term {
* @return array of the arguments that, with a format string, can be passed to sprintf
*/
public function print_args($method) {
- // First ensure that there are the correct number of arguments
+ // First ensure that there are the correct number of arguments.
$this->check_arguments();
return array($this->_sign, $this->_arguments[0]->$method());
}
@@ -1240,15 +1255,15 @@ class qtype_algebra_parser_function extends qtype_algebra_parser_term {
* @return the numerical value of the term given the provided values for the variables
*/
public function evaluate($params) {
- // First ensure that there are the correct number of arguments
+ // First ensure that there are the correct number of arguments.
$this->check_arguments();
- // Get the correct sign to multiply the value by
+ // Get the correct sign to multiply the value by.
if ($this->_sign == '-') {
$mult = -1;
} else {
$mult = 1;
}
- // Check to see if there is an entry to map the function name to a PHP function
+ // Check to see if there is an entry to map the function name to a PHP function.
if (array_key_exists($this->_value, self::$fnmap)) {
$func = self::$fnmap[$this->_value];
return $mult*$func($this->_arguments[0]->evaluate($params));
@@ -1270,7 +1285,7 @@ class qtype_algebra_parser_function extends qtype_algebra_parser_term {
* @return true if the terms match, false otherwise
*/
public function equals($expr) {
- // Call the default method first to check type
+ // Call the default method first to check type.
if (parent::equals($expr)) {
return $this->_value == $expr->_value and $this->_sign == $this->_sign;
} else {
@@ -1278,7 +1293,7 @@ class qtype_algebra_parser_function extends qtype_algebra_parser_term {
}
}
- // Static class properties
+ // Static class properties.
const NARGS = 1;
public static $fnmap = array ('ln' => 'log',
'log' => 'log10'
@@ -1349,7 +1364,7 @@ class qtype_algebra_parser_bracket extends qtype_algebra_parser_term {
}
public function set_negative() {
- // Set the sign to be a '-'
+ // Set the sign to be a '-'.
$this->_sign = '-';
}
@@ -1362,15 +1377,15 @@ class qtype_algebra_parser_bracket extends qtype_algebra_parser_term {
public function make_special() {
$this->_open = '<';
$this->_close = '>';
- // Call the base class constructor as if this were a new instance of the bracket
+ // Call the base class constructor as if this were a new instance of the bracket.
parent::__construct(self::NARGS, self::$formats['<'], '<');
}
- // Member variables
+ // Member variables.
var $_open = '(';
var $_close = ')';
- // Static class properties
+ // Static class properties.
const NARGS = 1;
private static $formats = array(
'(' => array('str' => '(%s)',
@@ -1394,7 +1409,7 @@ class qtype_algebra_parser_bracket extends qtype_algebra_parser_term {
* instances of the correct subclass to handle them.
*/
class qtype_algebra_parser {
- // Special constants which the parser will understand
+ // Special constants which the parser will understand.
public static $specials = array (
'pi',
'e'
@@ -1415,7 +1430,7 @@ class qtype_algebra_parser {
);
// Array to define the priority of the different operations. The parser implements the standard BODMAS priority:
- // brackets, order (power), division, mulitplication, addition, subtraction
+ // brackets, order (power), division, mulitplication, addition, subtraction.
private static $priority = array (
array('qtype_algebra_parser_power'),
array('qtype_algebra_parser_function'),
@@ -1423,15 +1438,15 @@ class qtype_algebra_parser {
array('qtype_algebra_parser_add', 'qtype_algebra_parser_subtract')
);
- // Regular experssion to match an open bracket
+ // Regular experssion to match an open bracket.
private static $OPENB = '/[\{\(\[]/A';
- // Regular experssion to match a close bracket
+ // Regular experssion to match a close bracket.
private static $CLOSEB = '/[\}\)\]]/A';
- // Regular expression to match a plain float or integer number without exponent
+ // Regular expression to match a plain float or integer number without exponent.
private static $PLAIN_NUMBER = '(([0-9]+(\.|,)[0-9]*)|([0-9]+)|((\.|,)[0-9]+))';
- // Regular expression to match a float or integer number with an exponent
+ // Regular expression to match a float or integer number with an exponent.
private static $EXP_NUMBER = '(([0-9]+(\.|,)[0-9]*)|([0-9]+)|((\.|,)[0-9]+))E([-+]?\d+)';
- // Array to associate close brackets with the correct open bracket type
+ // Array to associate close brackets with the correct open bracket type.
private static $BRACKET_MAP = array(')' => '(', ']' => '[', '}' => '{');
/**
@@ -1474,119 +1489,119 @@ class qtype_algebra_parser {
* @return top term of the parsed expression
*/
public function parse($text, $variables = array(), $undecvars = false) {
- // Create a regular expression to match the known variables if an array is specified
+ // Create a regular expression to match the known variables if an array is specified.
if (!empty($variables)) {
- // Create an empty array to store the list of extra regular expressions to match
+ // Create an empty array to store the list of extra regular expressions to match.
$reextra = array();
- // Loop over all the variable names we are given
- foreach($variables as $var) {
- // Create a temporary varible term using the current name
+ // Loop over all the variable names we are given.
+ foreach ($variables as $var) {
+ // Create a temporary varible term using the current name.
$tmpvar = new qtype_algebra_parser_variable($var);
// If the variable name has a subscript then create a new regular expression to
- // search for which includes an underscore
+ // search for which includes an underscore.
if (!empty($tmpvar->_subscript)) {
$reextra[] = $tmpvar->_base.'_'.$tmpvar->_subscript;
}
}
- // Merge the variable name array with the array of extra regular expressions to match
+ // Merge the variable name array with the array of extra regular expressions to match.
$variables = array_merge($variables, $reextra);
// Sort the array in order of increasing variable length in order to prevent 'x1' matching
// a variable 'x' before 'x1'. Do this using a helper function, which will compare two
// strings using their length only, and use this with the usort function.
usort($variables, 'qtype_algebra_parser_strlen_sort');
- // Generate a single regular expression which will match both all known variables
+ // Generate a single regular expression which will match both all known variables.
$revar = '/('.implode('|', $variables).')/A';
} else {
$revar = '';
}
$i = 0;
- // Create an array to store the parse tree
+ // Create an array to store the parse tree.
$tree = array();
// Create an array to act as a temporary storage stack. This stack is used to
- // push higher levels of the parse tree as it is assembled from the expression
+ // push higher levels of the parse tree as it is assembled from the expression.
$stack = array();
- // Array used to store the match results from regular expression searches
+ // Array used to store the match results from regular expression searches.
$m = array();
// Loop over the expression string moving along it using the offset variable $i while
- // there are still characters left to parse
- while($i<strlen($text)) {
+ // there are still characters left to parse.
+ while($i < strlen($text)) {
// Match any white space at the start of the string and 'remove' it by advancing
// the pointer by the length of the string matching the regular expression white
- // space pattern
+ // space pattern.
if (preg_match('/\s+/A', substr($text, $i), $m)) {
- $i+ = strlen($m[0]);
+ $i += strlen($m[0]);
// Return to the start of the loop in case this was white space characters at
- // the end of the string
+ // the end of the string.
continue;
}
// Since we don't have any white space the first thing we look for (top priority)
- // are open brackets
+ // are open brackets.
if (preg_match(self::$OPENB, substr($text, $i), $m)) {
- // Check for a non-operator and if one is found assume implicit multiplication
+ // Check for a non-operator and if one is found assume implicit multiplication.
if (count($tree)>0 and (is_array($tree[count($tree)-1]) or
(is_object($tree[count($tree)-1])
and $tree[count($tree)-1]->n_args() == 0))) {
// Make the implicit assumption explicit by adding an appropriate
- // multiplication operator
+ // multiplication operator.
array_push($tree, new qtype_algebra_parser_multiply('*'));
}
- // Push the current parse tree onto the stack
+ // Push the current parse tree onto the stack.
array_push($stack, $tree);
- // Create a new parse tree starting with a bracket term
+ // Create a new parse tree starting with a bracket term.
$tree = array(new qtype_algebra_parser_bracket($m[0]));
- // Increment the string pointer by the length of the string that was matched
- $i+ = strlen($m[0]);
- // Return to the start of the loop
+ // Increment the string pointer by the length of the string that was matched.
+ $i += strlen($m[0]);
+ // Return to the start of the loop.
continue;
}
- // Now see if we have a close bracket here
+ // Now see if we have a close bracket here.
if (preg_match(self::$CLOSEB, substr($text, $i), $m)) {
- // First check that the current parse tree has at least one term
+ // First check that the current parse tree has at least one term.
if (count($tree) == 0) {
throw new Exception(get_string('badclosebracket', 'qtype_algebra'));
}
- // Now check that the current tree started with a bracket
+ // Now check that the current tree started with a bracket.
if (!is_a($tree[0], 'qtype_algebra_parser_bracket')) {
throw new Exception(get_string('mismatchedcloseb', 'qtype_algebra'));
}
- // Check that the open and close bracket are of the same type
+ // Check that the open and close bracket are of the same type.
else if ($tree[0]->_value != self::$BRACKET_MAP[$m[0]]) {
throw new Exception(get_string('mismatchedbracket', 'qtype_algebra', $tree[0]->_value.$m[0]));
}
- // Append the current tree to the tree one level up on the stack
+ // Append the current tree to the tree one level up on the stack.
array_push($stack[count($stack)-1], $tree);
// The new tree is the lowest level tree on the stack so we
- // pop the new tree off the stack
+ // pop the new tree off the stack.
$tree = array_pop($stack);
- $i+ = strlen($m[0]);
+ $i += strlen($m[0]);
continue;
}
- // If a list of predefined variables was given to the method then check for them here
+ // If a list of predefined variables was given to the method then check for them here.
if (!empty($revar) and preg_match($revar, substr($text, $i), $m)) {
// Check for a zero argument term or brackets preceding the variable and if there is one then
- // add the implicit multiplication operation
+ // add the implicit multiplication operation.
if (count($tree)>0 and (is_array($tree[count($tree)-1]) or $tree[count($tree)-1]->n_args() == 0)) {
array_push($tree, new qtype_algebra_parser_multiply('*'));
}
- // Increment the string index by the length of the variable's name
- $i+ = strlen($m[0]);
- // Push a new variable term onto the parse tree
+ // Increment the string index by the length of the variable's name.
+ $i += strlen($m[0]);
+ // Push a new variable term onto the parse tree.
array_push($tree, new qtype_algebra_parser_variable($m[0]));
continue;
}
// Here we have not found any open or close brackets or known variables so we can
- // parse the string for a normal token
- foreach($this->_tokens as $token) {
+ // parse the string for a normal token.
+ foreach ($this->_tokens as $token) {
//echo 'Looking for token ', $token[1], "\n";
if (preg_match($token[0], substr($text, $i), $m)) {
//echo 'Found a ', $token[1], "!\n";
// Check for a variable and throw an exception if undeclared variables are
- // not allowed and a list of defined variables was passed
+ // not allowed and a list of defined variables was passed.
if (!empty($revar) and !$undecvars and $token[1] == 'qtype_algebra_parser_variable') {
throw new Exception(get_string('undeclaredvar', 'qtype_algebra', $m[0]));
}
// Check for a zero argument term preceding a variable, function or special and then
- // add the implicit multiplication
+ // add the implicit multiplication.
if (count($tree)>0 and ($token[1] == 'qtype_algebra_parser_variable' or
$token[1] == 'qtype_algebra_parser_function' or
$token[1] == 'qtype_algebra_parser_special')
@@ -1594,15 +1609,15 @@ class qtype_algebra_parser {
$tree[count($tree)-1]->n_args() == 0)) {
array_push($tree, new qtype_algebra_parser_multiply('*'));
}
- $i+ = strlen($m[0]);
+ $i += strlen($m[0]);
array_push($tree, new $token[1]($m[0]));
continue 2;
}
}
throw new Exception(get_string('unknownterm', 'qtype_algebra', substr($text, $i)));
- } // end while loop over tokens
+ } // End while loop over tokens.
// If all the open brackets have been closed then the stack will be empty and the
- // tree will contain the entire parsed expression
+ // tree will contain the entire parsed expression.
if (count($stack)>0) {
throw new Exception(get_string('mismatchedopenb', 'qtype_algebra'));
}
@@ -1623,7 +1638,7 @@ class qtype_algebra_parser {
*/
public function interpret($tree) {
// First check to see if we are passed anything at all. If not then simply
- // return a qtype_algebra_parser_nullterm
+ // return a qtype_algebra_parser_nullterm.
if (count($tree) == 0) {
return new qtype_algebra_parser_nullterm;
}
@@ -1639,21 +1654,21 @@ class qtype_algebra_parser {
}
// Next we loop over the tree and look for arrays. These represent
// brackets inside our tree and so we need to process them first.
- for($i = 0;$i<count($tree);$i++) {
+ for ($i = 0;$i < count($tree);$i++) {
// Check for a list type if we find one then replace
- // it with the interpreted term
+ // it with the interpreted term.
if (is_array($tree[$i])) {
$tree[$i] = $this->interpret($tree[$i]);
}
}
// The next job is to check the subtraction operations to determine whether they are
- // really subtraction operations or whether they are minus signs for negative numbers
+ // really subtraction operations or whether they are minus signs for negative numbers.
$toremove = array();
- for($i = 0;$i<count($tree);$i++) {
- // Check that this element is an addition or subtraction operator
+ for ($i = 0;$i < count($tree);$i++) {
+ // Check that this element is an addition or subtraction operator.
if (is_a($tree[$i], 'qtype_algebra_parser_subtract') or is_a($tree[$i], 'qtype_algebra_parser_add')) {
// Check whether the precedding argument (if there is one) is a number or
- // a variable. In either case this is a addition/subtraction operation so we continue
+ // a variable. In either case this is a addition/subtraction operation so we continue.
if ($i>0 and (is_a($tree[$i-1], 'qtype_algebra_parser_variable') or
is_a($tree[$i-1], 'qtype_algebra_parser_number') or
is_a($tree[$i-1], 'qtype_algebra_parser_bracket'))) {
@@ -1665,28 +1680,28 @@ class qtype_algebra_parser {
if ($i == (count($tree)-1) or !method_exists($tree[$i+1], 'set_negative')) {
throw new Exception(get_string('illegalplusminus', 'qtype_algebra'));
}
- // If we have a subtract operation then we need to make the following number negative
+ // If we have a subtract operation then we need to make the following number negative.
if (is_a($tree[$i], 'qtype_algebra_parser_subtract')) {
- // Set the number to be negative
+ // Set the number to be negative.
$tree[$i+1]->set_negative();
}
- // Add the term to the removal list
+ // Add the term to the removal list.
$toremove[$i] = 1;
}
}
}
- // Remove the elements from the tree who's keys are found in the removal list
+ // Remove the elements from the tree who's keys are found in the removal list.
$tree = array_diff_key($tree, $toremove);
- // Re-key the tree array so that the keys are sequential
+ // Re-key the tree array so that the keys are sequential.
$tree = array_values($tree);
- foreach(self::$priority as $ops) {
+ foreach (self::$priority as $ops) {
$i = 0;
//echo 'Looking for ', $ops, "\n";
- while($i<count($tree)) {
+ while($i < count($tree)) {
if (in_array(get_class($tree[$i]), $ops)) {
//echo 'Found a ', get_class($tree[$i]), "\n";
if ($tree[$i]->n_args() == 1) {
- if (($i+1)<count($tree)) {
+ if (($i+1) < count($tree)) {
$tree[$i]->set_arguments(array_splice($tree, $i+1, 1));
$i++;
continue;
@@ -1694,7 +1709,7 @@ class qtype_algebra_parser {
throw new Exception(get_string('missingonearg', 'qtype_algebra', $op));
}
} elseif ($tree[$i]->n_args() == 2) {
- if ($i>0 and $i<(count($tree)-1)) {
+ if ($i > 0 and $i < (count($tree)-1)) {
$tree[$i]->set_arguments(array($tree[$i-1],
$tree[$i+1]));
array_splice($tree, $i+1, 1);
@@ -1710,7 +1725,7 @@ class qtype_algebra_parser {
}
}
// If there are no terms in the parse tree then we were passed an empty string
- // in which case we create a null term and return it
+ // in which case we create a null term and return it.
if (count($tree) == 0) {
return new qtype_algebra_parser_nullterm;
} else if (count($tree)!= 1) {
@@ -1726,7 +1741,7 @@ class qtype_algebra_parser {
}
}
-// Sort static arrays once here by inverse string length
+// Sort static arrays once here by inverse string length.
usort(qtype_algebra_parser_variable::$greek, 'qtype_algebra_parser_strlen_sort');
usort(qtype_algebra_parser::$functions, 'qtype_algebra_parser_strlen_sort');