ometa RegexpParser { symbol = letter:l -> ['sym', l] | digit:d -> ['sym', d], alternation = concatenation:c '|' alternation:a -> ['alt', c, a] | concatenation, concatenation = quantification:q concatenation:c -> ['con', q, c] | quantification, quantification = grouping:q '*' -> ['qua', q] | grouping, grouping = '(' alternation:a ')' -> ['gro', a] | symbol, pattern = alternation:a '.' -> ['pat', a] | anything:x -> (false) } ometa RegexpReducer { rank = ['pat' anything:a] -> 0 | ['alt' rank:x rank:y] -> (Math.min(1, x, y)) | ['con' rank:x rank:y] -> (Math.min(2, x, y)) | ['qua' rank:x] -> (Math.min(3, x)) | ['gro' rank:x] -> 4 | ['sym' anything:x] -> 5, print = ['pat' print:p] -> p | ['alt' print:x print:y] -> (x + '|' + y) | ['con' print:x print:y] -> (x + y) | ['qua' print:x] -> (x + '*') | ['gro' print:x] -> ('(' + x + ')') | ['sym' anything:x] -> x, reduce = ['pat' ['gro' reduce:x]] -> x | ['pat' reduce:x] -> ['pat', x] | ['gro' reduce:x] ?(RegexpReducer.match(x, 'rank') >= 4) -> x | ['gro' reduce:x] -> ['gro', x] | ['qua' ['gro' reduce:x]] ?(RegexpReducer.match(x, 'rank') >= 3) -> ['qua', x] | ['qua' reduce:x] -> ['qua', x] | ['con' ['gro' reduce:x] ['gro' reduce:y]] ?(RegexpReducer.match(x, 'rank') >= 2) ?(RegexpReducer.match(y, 'rank') >= 2) -> ['con', x, y] | ['con' ['gro' reduce:x] reduce:y] ?(RegexpReducer.match(x, 'rank') >= 2) -> ['con', x, y] | ['con' reduce:x ['gro' reduce:y]] ?(RegexpReducer.match(y, 'rank') >= 2) -> ['con', x, y] | ['con' reduce:x reduce:y] -> ['con', x, y] | ['alt' ['gro' reduce:x] ['gro' reduce:y]] ?(RegexpReducer.match(x, 'rank') >= 1) ?(RegexpReducer.match(y, 'rank') >= 1) -> ['alt', x, y] | ['alt' ['gro' reduce:x] reduce:y] ?(RegexpReducer.match(x, 'rank') >= 1) -> ['alt', x, y] | ['alt' reduce:x ['gro' reduce:y]] ?(RegexpReducer.match(y, 'rank') >= 1) -> ['alt', x, y] | ['alt' reduce:x reduce:y] -> ['alt', x, y] | anything:x -> x } reduce = function (pat) { tree = RegexpParser.matchAll(pat + '.', 'pattern') if (tree != false) { reduced_tree = RegexpReducer.match(tree, 'reduce') return RegexpReducer.match(reduced_tree, 'print') } else { return 'Not a reglar expression' } } //reduce('((aa|ab)|(ab|bb))*') //reduce('(ab|(ac**|bc))*') //reduce('(ab|(ac|bc))*') //reduce('a(aa)a') //reduce('a(a(a|a)a)a') //reduce('a(a|b)a') //add input area col_count = 40 row_count = 10 reg_input = document.createElement('textarea') reg_input.setAttribute('cols', col_count) reg_input.setAttribute('rows', row_count) reg_input.setAttribute('name', 'reg_input') reg_input.setAttribute('style', 'font-family:monaco, monospace; font-size: 10pt') $('playArea').appendChild(reg_input) //set some sample expressions reg_input.value = '((aa|ab)|(ab|bb))*\n(ab|(ac**|bc))*\n(ab|(ac|bc))*' //add area for results reg_reduced = document.createElement('textarea') reg_reduced.setAttribute('cols', col_count) reg_reduced.setAttribute('rows', row_count) reg_reduced.setAttribute('name', 'reg_input') reg_reduced.setAttribute('style', 'font-family:monaco, monospace; font-size: 10pt') reg_reduced.setAttribute('readonly', true) $('playArea').appendChild(reg_reduced) //add button to start reduction reduce_button = document.createElement('input') reduce_button.setAttribute('type', 'button') reduce_button.setAttribute('value', 'reduce') reduce_button.setAttribute('onClick', 'reduce_area()') $('playArea').appendChild(reduce_button) reduce_area = function() { reg_reduced.value = reg_input.value.split('\n').map(reduce).join('\n') }