/*
* 2016 Maciej Wiecierzewski
*/
/**
* @constructor
* @classdesc Rule data
* @param {type} symbol
* @param {type} string
* @param {type} probability
* @returns {Rule}
*/
function Rule(symbol, string, probability)
{
this.symbol = symbol;
this.string = string;
this.probability = probability;
this.operator = null;
}
/**
* @contructor
* @classdesc Symbol data
* @param {type} str Symbol's character
* @param {type} terminal Is symbol terminal
* @returns {Symbol}
*/
function Symbol(str, terminal)
{
this.str = str;
this.terminal = terminal;
}
/**
* Generates the grammar given the operators
* @constructor
* @param {type} operators
* @param {type} rulesProb
* @returns {Grammar}
*/
function Grammar(operators, rulesProb)
{
if(rulesProb === undefined)
{
rulesProb = [];
rulesProb['endRule'] = 1;
rulesProb['nextSymbol'] = 1;
rulesProb['0-aryOperator'] = 1;
rulesProb['1-aryOperator'] = 1;
rulesProb['2-aryOperator'] = 1;
rulesProb['otherwise'] = 1;
}
function compare(a, b)
{
if(a.precedence > b.precedence)
return 1;
else if(a.precedence < b.precedence)
return -1;
else
return 0;
}
function ruleProb(type, i)
{
if(type === "endRule")
//return 0.01*((1-i*i/(operators.length*operators.length))+10);
return rulesProb['endRule'];
else if(type === "nextSymbol")
//return 1*((1-i*i/(operators.length*operators.length))+0.1);
return rulesProb['nextSymbol'];
else if(type === "0-aryOperator")
return rulesProb['0-aryOperator'];
else if(type === "1-aryOperator")
return rulesProb['1-aryOperator'];
else if(type === "2-aryOperator")
return rulesProb['2-aryOperator'];
else
return rulesProb['otherwise'];
}
operators.sort(compare);
var symbols = [];
symbols.push(new Symbol("S", false));
var terminalSymbol = 0;
var charCode = "A".charCodeAt(0);
for(var i = 0; i < operators.length; i++)
{
var isTerminal = (operators[i].arity == 0) ? true : false;
symbols.push(new Symbol(String.fromCharCode(charCode+i), isTerminal));
if(isTerminal)
terminalSymbol = (symbols.length-1);
}
var rules = [];
var endRules = [];
var lastSymbol = 0;
for(var i = 0; i < operators.length; i++)
{
var symbol = lastSymbol+1;
if(symbol === terminalSymbol)
{var rule = new Rule(symbols[0].str, symbols[symbol].str, 0);
endRules.push(rules.length-1);
rules.push(rule);
}
else
{
var rule = new Rule(symbols[0].str, symbols[symbol].str, ruleProb("nextSymbol", i));
rules.push(rule);
}
lastSymbol = symbol;
}
lastSymbol = 0;
for(var i = 0; i < operators.length; i++)
{
var symbol = lastSymbol+1;
if(symbol != terminalSymbol && lastSymbol > 0)
{
var rule = new Rule(symbols[lastSymbol].str, symbols[symbol].str, ruleProb("nextSymbol", i));
rules.push(rule);
}
if(!symbols[lastSymbol].terminal && lastSymbol > 0)
{
var rule = new Rule(symbols[lastSymbol].str, symbols[terminalSymbol].str, ruleProb("endRule", i));
rules.push(rule);
endRules.push(rules.length-1);
}
if(operators[i].arity == 0)
{
var rule = new Rule(symbols[symbol].str, operators[i].symbol,
operators[i].probability);
rule.operator = operators[i].symbol;
rules.push(rule);
}
else if(operators[i].arity == 1)
{
if(operators[i].placement == "prefix")
{
var rule = new Rule(symbols[symbol].str,
operators[i].symbol+symbols[symbol].str,
operators[i].probability);
rule.operator = operators[i].symbol;
rules.push(rule);
}
else if(operators[i].placement == "postfix")
{
var rule = new Rule(symbols[symbol].str,
symbols[symbol].str+operators[i].symbol,
operators[i].probability);
rule.operator = operators[i].symbol;
rules.push(rule);
}
}
else if(operators[i].arity == 2)
{
if(operators[i].placement == "prefix")
{
var rule = new Rule(symbols[symbol].str,
operators[i].symbol+symbols[0].str+symbols[symbol].str,
operators[i].probability);
rule.operator = operators[i].symbol;
rules.push(rule);
}
else if(operators[i].placement == "infix")
{
var rule = new Rule(symbols[symbol].str, "", operators[i].probability);
if(operators[i].associativity == "right")
rule.string = symbols[symbol+1].str+operators[i].symbol+symbols[symbol].str;
else
rule.string = symbols[symbol].str+operators[i].symbol+symbols[symbol+1].str;
rule.operator = operators[i].symbol;
rules.push(rule);
}
else if(operators[i].placement == "postfix")
{
var rule = new Rule(symbols[symbol].str,
symbols[symbol].str+symbols[0].str+operators[i].symbol,
operators[i].probability);
rule.operator = operators[i].symbol;
rules.push(rule);
}
}
lastSymbol = symbol;
}
this.symbols = symbols;
this.rules = rules;
this.startSymbol = 0;
this.endRules = endRules;
this.operators = operators;
var str = "";
for(var i = 0; i < rules.length; i++)
{
str += i + ". " + rules[i].symbol + " -> " + rules[i].string
+ " (" + rules[i].probability + ")\n";
}
console.log(str);
}
/**
* Returns rules applicable for given symbol
* @param {type} symbol
* @returns {Array|Grammar.prototype.getRules.rules}
*/
Grammar.prototype.getRules = function(symbol)
{
var rules = [];
for(var i = 0; i < this.rules.length; i++)
{
if(this.rules[i].symbol == symbol)
rules.push(this.rules[i]);
}
return rules;
}
/**
* Returns indexes of rules applicable for given symbol
* @param {type} symbol
* @returns {Array|Grammar.prototype.getRules.rules}
*/
Grammar.prototype.getRulesN = function(symbol)
{
var rulesN = [];
for(var i = 0; i < this.rules.length; i++)
{
if(this.rules[i].symbol == symbol)
rulesN.push(i);
// ^ here's the difference
}
return rulesN;
}