aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Denker <jsd@av8n.com>2021-11-10 17:19:23 -0700
committerJohn Denker <jsd@av8n.com>2021-11-11 16:08:05 -0700
commit9b981411b8dc7c0ff4878fa1a98dad6e3d69c653 (patch)
treebf9705832900d567bdbde31e5178de424aadde01
parent00f7ed380b90cc003c3f99a6ce116b885a7469ec (diff)
multi-character variable names, with and without auto-Greek,
with and without subscripts
-rw-r--r--lang/en/qtype_algebra.php1
-rw-r--r--parser.php114
2 files changed, 34 insertions, 81 deletions
diff --git a/lang/en/qtype_algebra.php b/lang/en/qtype_algebra.php
index b29682e..003d0ee 100644
--- a/lang/en/qtype_algebra.php
+++ b/lang/en/qtype_algebra.php
@@ -25,6 +25,7 @@
// Parser lang strings.
$string['deprecatedlog'] = 'log() is deprecated; use ln() or log10() instead';
$string['trivial_1'] = '{$a}';
+$string['debug_1'] = 'Debug:<br>{$a}';
$string['badclosebracket'] = 'Invalid close bracket found';
$string['badequivtype'] = 'Invalid type: can only compare parser terms with other parser terms';
$string['badfuncargs'] = 'Invalid arguments for the function \'{$a}\'';
diff --git a/parser.php b/parser.php
index fd58f4c..ad141f1 100644
--- a/parser.php
+++ b/parser.php
@@ -627,7 +627,7 @@ class qtype_algebra_parser_variable extends qtype_algebra_parser_term {
);
/**
- * Constructor for an algebraic term cass representing a variable.
+ * Constructor for an algebraic term class representing a variable.
*
* Initializes an instance of the variable term subclass. The method is given the text
* in the expression corresponding to the variable name. This is then parsed to get the
@@ -643,37 +643,15 @@ class qtype_algebra_parser_variable extends qtype_algebra_parser_term {
$m = array();
// Set the sign of the variable to be empty.
$this->_sign = '';
- // 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.
- $this->_base = $m[1];
- // 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 (strlen($this->_subscript) != 0 && $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.
- parent::__construct(self::NARGS, self::$formats['greek'],
- $this->_base.$this->_subscript);
+ if (preg_match('/([^_]+)_(.*)/A', $text, $m)) {
+ $this->_base = $m[1];
+ $this->_subscript = $m[2];
} else {
- // Otherwise we have a simple multi-letter variable name. Treat the fist letter as the base
- // name and the rest as the subscript.
-
- // Get the variable's base name.
- $this->_base = substr($text, 0, 1);
- // 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 (strlen($this->_subscript) != 0 && $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.
- parent::__construct(self::NARGS, self::$formats['std'],
- $this->_base.$this->_subscript);
+ $this->_base = $text;
+ $this->_subscript = '';
}
+ $gmode = in_array($this->_base, self::$greek, 1) ? 'greek' : 'std';
+ parent::__construct(self::NARGS, self::$formats[$gmode], $text);
}
/**
@@ -698,7 +676,8 @@ class qtype_algebra_parser_variable 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) {
- return array($this->_sign, $this->_base, $this->_subscript);
+ $under = $this->_subscript == '' ? '' : '_';
+ return array($this->_sign, $this->_base, $under, $this->_subscript);
}
/**
@@ -745,10 +724,10 @@ class qtype_algebra_parser_variable extends qtype_algebra_parser_term {
// Static class properties.
const NARGS = 0;
private static $formats = array(
- 'greek' => array('str' => '%s%s%s',
- 'tex' => '%s\%s_{%s}'),
- 'std' => array('str' => '%s%s%s',
- 'tex' => '%s%s_{%s}')
+ 'greek' => array('str' => '%s%s%s%s',
+ 'tex' => '%s\%s%s{%s}'),
+ 'std' => array('str' => '%s%s%s%s',
+ 'tex' => '%s%s%s{%s}')
);
}
@@ -1479,14 +1458,12 @@ class qtype_algebra_parser {
public function __construct() {
$this->_tokens = array (
array ('/(\^|\*\*)/A', 'qtype_algebra_parser_power' )
- , array ('/('.implode('|', self::$functions).')/A', 'qtype_algebra_parser_function' )
- , array ('/\//A', 'qtype_algebra_parser_divide' )
+ , array ('/\//A', 'qtype_algebra_parser_divide' )
, array ('/\*/A', 'qtype_algebra_parser_multiply' )
, array ('/\+/A', 'qtype_algebra_parser_add' )
, array ('/-/A', 'qtype_algebra_parser_subtract' )
- , array ('/('.implode('|', self::$specials).')/A', 'qtype_algebra_parser_special' )
, array ('/('.self::$expnumber.'|'.self::$plainnumber.')/A', 'qtype_algebra_parser_number' )
- , array ('/[A-Za-z][A-Za-z0-9_]*/A', 'qtype_algebra_parser_variable' )
+ , array ('/[A-Za-z][A-Za-z0-9_]*/A', 'qtype_algebra_parser_identifier' )
);
}
@@ -1508,31 +1485,6 @@ 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.
- if (!empty($variables)) {
- // 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 variable 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.
- if (!empty($tmpvar->_subscript)) {
- $reextra[] = $tmpvar->_base.'_'.$tmpvar->_subscript;
- }
- }
- // 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.
- $revar = '/('.implode('|', $variables).')/A';
- } else {
- $revar = '';
- }
$i = 0;
// Create an array to store the parse tree.
$tree = array();
@@ -1594,28 +1546,28 @@ class qtype_algebra_parser {
$i += strlen($m[0]);
continue;
}
- // 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.
- 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.
- 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) {
if (preg_match($token[0], substr($text, $i), $m)) {
- // Check for a variable and throw an exception if undeclared variables are
- // not allowed and a list of defined variables was passed.
- if (!empty($revar) and !$undecvars and $token[1] == 'qtype_algebra_parser_variable') {
- throw new parser_exception(get_string('undeclaredvar', 'qtype_algebra', $m[0]));
+ if ($token[1] == 'qtype_algebra_parser_identifier') {
+ if (in_array($m[0], self::$functions, 1)) {
+ $token[1] = 'qtype_algebra_parser_function';
+ }
+ else if (in_array($m[0], self::$specials, 1)) {
+ $token[1] = 'qtype_algebra_parser_special';
+ }
+ else if (in_array($m[0], $variables, 1)) {
+ $token[1] = 'qtype_algebra_parser_variable';
+ } else {
+ if (!empty($variables) and !$undecvars) {
+ throw new parser_exception(get_string('undeclaredvar', 'qtype_algebra', $m[0]));
+ }
+ // heretofore unknown identifier, promote to variable:
+ $token[1] = 'qtype_algebra_parser_variable';
+ }
}
+
// Check for a zero argument term preceding a variable, function or special and then
// add the implicit multiplication.
if (count($tree) > 0 and ($token[1] == 'qtype_algebra_parser_variable' or