xxeell

TFLAT-2-sint-analizer

Nov 7th, 2021 (edited)
327
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. <!DOCTYPE html>
  2. <html>
  3.  
  4. <head>
  5.     <title>Sint analizator</title>
  6. </head>
  7.  
  8. <body>
  9.     <textarea id="input" cols="60" rows="10"></textarea>
  10.     <button id="parseButton">parse</button>
  11.     <br>
  12.     <details>
  13.         <summary>Лексемы</summary>
  14.         <div id="lexOutputContainer"></div>
  15.     </details>
  16.     <br>
  17.     <details open>
  18.         <summary>Синтаксическое дерево</summary>
  19.         <div id="sintOutputContainer"></div>
  20.         <br>
  21.         <br>
  22.         <div id="sintOutputCanvas" width="100%" height="1000px"
  23.             style="vertical-align:top;text-anchor:middle;font-family:monospace;font-size:16px;"></div>
  24.     </details>
  25.  
  26. </body>
  27. <!-- IO -->
  28. <script>
  29.     const lexOutputContainer = document.getElementById('lexOutputContainer');
  30.     const sintOutputContainer = document.getElementById('sintOutputContainer');
  31.     const inputElement = document.getElementById('input');
  32.     inputElement.value =
  33.         `a = 1
  34. b = 2
  35. c = 3
  36. do while (((a < b) and (a <= c)) or (a > c))
  37.     b=b+c
  38.     b=b+a-20
  39. loop`;
  40. </script>
  41. <!-- Automate engine -->
  42. <script>
  43.     function distinct(array) {
  44.         return array.filter((value, index) => array.indexOf(value) == index);
  45.     }
  46.  
  47.     (function () {
  48.         let automateExample = {
  49.             states: {
  50.                 list: ['a', 'b', 'c'],
  51.                 start: 'a',
  52.                 end: ['c']
  53.             },
  54.             alphabet: [1, 2, 3],
  55.             translations: [
  56.                 { from: 'a', to: 'b', when: 1 },
  57.                 { from: 'b', to: 'c', when: 2 },
  58.                 { from: 'b', to: 'a', when: 2 },
  59.                 { from: 'a', to: 'c', when: 3 },
  60.             ],
  61.             epsilon: {
  62.                 useEpsilon: true,
  63.                 translations: [
  64.                     { from: 'b', to: 'a' },
  65.                     { from: 'b', to: 'b' },
  66.                 ],
  67.             },
  68.             config: {
  69.                 drowWhenNoTranslation: false,
  70.                 logEpsilonSeparately: true
  71.             }
  72.         };
  73.     })();
  74.  
  75.     function validateAutomateTemplate(automateTemplate) {
  76.         if (!automateTemplate) {
  77.             throw new Error(`Template error! Input is undefined.`);
  78.         }
  79.  
  80.         // --- --- States --- ---
  81.         if (!automateTemplate.states) {
  82.             throw new Error(`States error! States object is empty.`);
  83.         }
  84.         // --- list ---
  85.         if (!automateTemplate.states.list) {
  86.             throw new Error(`States error! States list is undefined.`);
  87.         }
  88.  
  89.         if (automateTemplate.states.list.length < 1) {
  90.             throw new Error(`States error! States list is empty.`);
  91.         }
  92.         // --- end list ---
  93.         // --- start ---
  94.         if (!automateTemplate.states.start) {
  95.             throw new Error(`Start state error! Start state is undefined.`);
  96.         }
  97.  
  98.         if (!automateTemplate.states.list.includes(automateTemplate.states.start)) {
  99.             throw new Error(`Start state error! States not include '${automateTemplate.states.start}'.`);
  100.         }
  101.         // --- end start ---
  102.         // --- end ---
  103.         if (!automateTemplate.states.end) {
  104.             throw new Error(`End states error! End states is undefined.`);
  105.         }
  106.  
  107.         if (automateTemplate.states.end.length < 1) {
  108.             throw new Error(`End states error! End states list is empty.`);
  109.         }
  110.  
  111.         for (const state of automateTemplate.states.end) {
  112.             if (!automateTemplate.states.list.includes(state)) {
  113.                 throw new Error(`End states error! States not include '${state}'.`);
  114.             }
  115.         }
  116.         // --- end end ---
  117.         // --- --- end States --- ---
  118.  
  119.         // --- --- Alphabet --- ---
  120.         if (!automateTemplate.alphabet) {
  121.             throw new Error(`Alphabet error! Alphabet is undefined.`);
  122.         }
  123.  
  124.         if (automateTemplate.alphabet.length < 1) {
  125.             throw new Error(`Alphabet error! Alphabet list is empty.`);
  126.         }
  127.         // --- --- end Alphabet --- ---
  128.  
  129.         // --- --- Translation --- ---
  130.         if (!automateTemplate.translations) {
  131.             throw new Error(`Translation error! Translations is undefined.`);
  132.         }
  133.  
  134.         if (automateTemplate.translations.length < 1) {
  135.             throw new Error(`Translation error! Translations list is empty.`);
  136.         }
  137.  
  138.         for (const translation of automateTemplate.translations) {
  139.             if (!automateTemplate.states.list.includes(translation.from)) {
  140.                 throw new Error(`Translation error! States not include 'from' value '${translation.from}' on transtalion ${JSON.stringify(translation)}.`);
  141.             }
  142.             if (!automateTemplate.states.list.includes(translation.to)) {
  143.                 throw new Error(`Translation error! States not include 'to' value '${translation.to}' on transtalion ${JSON.stringify(translation)}.`);
  144.             }
  145.             if (!automateTemplate.alphabet.includes(translation.when)) {
  146.                 throw new Error(`Translation error! Alphabet not include 'when' value '${translation.when}' on transtalion ${JSON.stringify(translation)}.`);
  147.             }
  148.         }
  149.         // --- --- end Translation --- ---
  150.  
  151.         // --- --- Epsilon --- ---
  152.         if (!automateTemplate.epsilon) {
  153.             throw new Error(`Epsilon error! Epsilon is undefined.`);
  154.         }
  155.  
  156.         if (automateTemplate.epsilon.useEpsilon) {
  157.             if (!automateTemplate.epsilon.translations) {
  158.                 throw new Error(`Epsilon error! Epsilon translations is undefined.`);
  159.             }
  160.  
  161.             if (automateTemplate.epsilon.translations.length < 1) {
  162.                 throw new Error(`Epsilon error! Epsilon translations list is empty.`);
  163.             }
  164.  
  165.             for (const translation of automateTemplate.epsilon.translations) {
  166.                 if (!automateTemplate.states.list.includes(translation.from)) {
  167.                     throw new Error(`Epsilon error! States not include 'from' value '${translation.from}' on epsilon transtalion ${JSON.stringify(translation)}.`);
  168.                 }
  169.                 if (!automateTemplate.states.list.includes(translation.to)) {
  170.                     throw new Error(`Epsilon error! States not include 'to' value '${translation.to}' on epsilon transtalion ${JSON.stringify(translation)}.`);
  171.                 }
  172.             }
  173.         }
  174.         // --- --- end Epsilon --- ---
  175.  
  176.         // --- --- Config --- ---
  177.         if (!automateTemplate.config) {
  178.             throw new Error(`Config error! Config is undefined.`);
  179.         }
  180.         // --- --- end Config --- ---
  181.     }
  182.  
  183.     function Automate(automateTemplate) {
  184.         validateAutomateTemplate(automateTemplate);
  185.  
  186.         this.automate = {
  187.             states: {
  188.                 list: Array.from(automateTemplate.states.list),
  189.                 start: automateTemplate.states.start,
  190.                 end: Array.from(automateTemplate.states.end)
  191.             },
  192.             alphabet: Array.from(automateTemplate.alphabet),
  193.             translations: {},
  194.             epsilon: {
  195.                 useEpsilon: false,
  196.                 translations: {}
  197.             },
  198.             config: {
  199.                 drowWhenNoTranslation: automateTemplate.config.drowWhenNoTranslation,
  200.                 logEpsilonSeparately: automateTemplate.config.logEpsilonSeparately
  201.             }
  202.         };
  203.  
  204.         for (const state of this.automate.states.list) {
  205.             this.automate.translations[state] = {};
  206.             for (const letter of this.automate.alphabet) {
  207.                 this.automate.translations[state][letter] = [];
  208.             }
  209.         }
  210.         for (const translation of automateTemplate.translations) {
  211.             if (this.automate.translations[translation.from][translation.when].includes(translation.to)) {
  212.                 throw new Error(`Translation error! Transtalion ${JSON.stringify(translation)} already exists.`);
  213.             }
  214.             this.automate.translations[translation.from][translation.when].push(translation.to);
  215.         }
  216.  
  217.         if (automateTemplate.epsilon.useEpsilon) {
  218.             this.automate.epsilon.useEpsilon = true;
  219.             for (const state of this.automate.states.list) {
  220.                 this.automate.epsilon.translations[state] = [];
  221.             }
  222.             for (const translation of automateTemplate.epsilon.translations) {
  223.                 if (this.automate.epsilon.translations[translation.from].includes(translation.to)) {
  224.                     throw new Error(`Epsilon translation error! Epsilon transtalion ${JSON.stringify(translation)} already exists.`);
  225.                 }
  226.                 this.automate.epsilon.translations[translation.from].push(translation.to);
  227.             }
  228.         }
  229.  
  230.         this.execution = {
  231.             current: [this.automate.states.start],
  232.             log: [],
  233.             errors: []
  234.         };
  235.     }
  236.  
  237.     Automate.prototype = {
  238.         clearExecution() {
  239.             this.execution = {
  240.                 current: [this.automate.states.start],
  241.                 log: [],
  242.                 errors: []
  243.             };
  244.             this.logStep(null);
  245.         },
  246.         logStep(letter) {
  247.             this.execution.log.push({
  248.                 getLetter: letter,
  249.                 resultStates: Array.from(this.execution.current)
  250.             });
  251.         },
  252.         processEpsilon() {
  253.             if (!this.automate.epsilon.useEpsilon) {
  254.                 return;
  255.             }
  256.  
  257.             let next = [...this.execution.current];
  258.             let currentChars = this.execution.current;
  259.             let nextChars = [];
  260.  
  261.             while (currentChars.length > 0) {
  262.                 for (let curChar of currentChars) {
  263.                     nextChars.push(...this.automate.epsilon.translations[curChar]);
  264.                 }
  265.                 next.push(...nextChars);
  266.                 currentChars = distinct(nextChars).filter(value => !next.includes(value));
  267.                 nextChars = [];
  268.             }
  269.  
  270.             this.execution.current = distinct(next);
  271.             if (this.automate.config.logEpsilonSeparately) {
  272.                 this.logStep('epsilon');
  273.             }
  274.         },
  275.         processLetter(letter) {
  276.             if (!this.automate.alphabet.includes(letter)) {
  277.                 alert(`Input error! Alphabet not include ${letter}`);
  278.                 return;
  279.             }
  280.  
  281.             let next = [];
  282.  
  283.             for (let currentState of this.execution.current) {
  284.                 let nextStates = this.automate.translations[currentState][letter];
  285.                 if (nextStates.length < 1) {
  286.                     let error = `No translation for ${JSON.stringify({ from: currentState, when: letter })}`;
  287.                     this.execution.errors.push(error);
  288.                     if (this.automate.config.drowWhenNoTranslation) {
  289.                         throw error;
  290.                     } else {
  291.                         nextStates = [currentState];
  292.                     }
  293.                 }
  294.                 next.push(...nextStates);
  295.             }
  296.  
  297.             this.execution.current = distinct(next);
  298.  
  299.             if (this.automate.config.logEpsilonSeparately) {
  300.                 this.logStep(letter);
  301.                 this.processEpsilon();
  302.             } else {
  303.                 this.processEpsilon();
  304.                 this.logStep(letter);
  305.             }
  306.         },
  307.         isComplete() {
  308.             return this.execution.current.some(value => this.automate.states.end.includes(value));
  309.         }
  310.     };
  311. </script>
  312. <!-- Lex classes -->
  313. <script>
  314.     const LexClasses = {
  315.         keywords: {
  316.             loop: {
  317.                 while: {
  318.                     start: { value: 'lex.keyword.loop.while.start', priority: 1 },
  319.                     end: { value: 'lex.keyword.loop.while.end', priority: 1 },
  320.                 }
  321.             },
  322.             codeSegment: {
  323.                 start: { value: 'lex.keyword.codeSegment.start', priority: 2 },
  324.                 end: { value: 'lex.keyword.codeSegment.end', priority: 2 },
  325.             },
  326.         },
  327.         separators: {
  328.             bracket: {
  329.                 start: { value: 'lex.separators.bracket.start', priority: 3 },
  330.                 end: { value: 'lex.separators.bracket.end', priority: 3 },
  331.             }
  332.         },
  333.         operations: {
  334.             as: { value: 'lex.operations.as', priority: 3 },
  335.             logical: { value: 'lex.operations.logical', priority: 4 },
  336.             compare: { value: 'lex.operations.compare', priority: 4 },
  337.             math: { value: 'lex.operations.math', priority: 4 },
  338.         },
  339.         values: {
  340.             variable: { value: 'lex.values.variable', priority: 5 },
  341.             numConst: { value: 'lex.values.numConst', priority: 5 },
  342.         },
  343.     };
  344. </script>
  345. <!-- Automate builder -->
  346. <script>
  347.     const AutomateBuilder = {
  348.         alphabet: '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ<>=+-*/ ()'.split(''),
  349.         createAutomateTemplate(keyword) {
  350.             let template = {
  351.                 states: {
  352.                     list: ['start'],
  353.                     start: 'start',
  354.                     end: [keyword]
  355.                 },
  356.                 alphabet: AutomateBuilder.alphabet,
  357.                 translations: [],
  358.                 epsilon: {
  359.                     useEpsilon: false,
  360.                     translations: [],
  361.                 },
  362.                 config: {
  363.                     drowWhenNoTranslation: true,
  364.                     logEpsilonSeparately: false
  365.                 }
  366.             };
  367.  
  368.             let wordPart = '';
  369.             for (const letter of keyword) {
  370.                 wordPart += letter;
  371.                 const prewState = template.states.list[template.states.list.length - 1];
  372.                 const curState = wordPart;
  373.                 template.states.list.push(curState);
  374.                 template.translations.push({ from: prewState, to: curState, when: letter });
  375.             }
  376.  
  377.             return template;
  378.         },
  379.         createAutomate(keyword) {
  380.             let template = AutomateBuilder.createAutomateTemplate(keyword);
  381.             let automate = new Automate(template);
  382.             return automate;
  383.         },
  384.         createNumConstAtomate() {
  385.             let template = {
  386.                 states: {
  387.                     list: ['start', 'num'],
  388.                     start: 'start',
  389.                     end: ['num']
  390.                 },
  391.                 alphabet: AutomateBuilder.alphabet,
  392.                 translations: [],
  393.                 epsilon: {
  394.                     useEpsilon: false,
  395.                     translations: [],
  396.                 },
  397.                 config: {
  398.                     drowWhenNoTranslation: true,
  399.                     logEpsilonSeparately: false
  400.                 }
  401.             };
  402.  
  403.             for (let letter of '123456789') {
  404.                 template.translations.push({ from: 'start', to: 'num', when: letter });
  405.                 template.translations.push({ from: 'num', to: 'num', when: letter });
  406.             }
  407.             template.translations.push({ from: 'num', to: 'num', when: '0' });
  408.  
  409.             let automate = new Automate(template);
  410.             return automate;
  411.         },
  412.         createVariableAtomate() {
  413.             let template = {
  414.                 states: {
  415.                     list: ['start', 'var'],
  416.                     start: 'start',
  417.                     end: ['var']
  418.                 },
  419.                 alphabet: AutomateBuilder.alphabet,
  420.                 translations: [],
  421.                 epsilon: {
  422.                     useEpsilon: false,
  423.                     translations: [],
  424.                 },
  425.                 config: {
  426.                     drowWhenNoTranslation: true,
  427.                     logEpsilonSeparately: false
  428.                 }
  429.             };
  430.  
  431.             for (let letter of 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') {
  432.                 template.translations.push({ from: 'start', to: 'var', when: letter });
  433.                 template.translations.push({ from: 'var', to: 'var', when: letter });
  434.             }
  435.  
  436.             for (let letter of '0123456789') {
  437.                 template.translations.push({ from: 'var', to: 'var', when: letter });
  438.             }
  439.  
  440.             let automate = new Automate(template);
  441.             return automate;
  442.         }
  443.     }
  444. </script>
  445. <!-- Automates -->
  446. <script>
  447.     const FullAutomatesList = {
  448.         // keywords,
  449.         while: {
  450.             automate: AutomateBuilder.createAutomate('while'),
  451.             class: LexClasses.keywords.loop.while.start
  452.         },
  453.         loop: {
  454.             automate: AutomateBuilder.createAutomate('loop'),
  455.             class: LexClasses.keywords.loop.while.end
  456.         },
  457.         do: {
  458.             automate: AutomateBuilder.createAutomate('do'),
  459.             class: LexClasses.keywords.codeSegment.start
  460.         },
  461.         end: {
  462.             automate: AutomateBuilder.createAutomate('end'),
  463.             class: LexClasses.keywords.codeSegment.end
  464.         },
  465.         // end keywords
  466.         // separators
  467.         '(': {
  468.             automate: AutomateBuilder.createAutomate('('),
  469.             class: LexClasses.separators.bracket.start
  470.         },
  471.         ')': {
  472.             automate: AutomateBuilder.createAutomate(')'),
  473.             class: LexClasses.separators.bracket.end
  474.         },
  475.         // end separators
  476.         // operations
  477.         and: {
  478.             automate: AutomateBuilder.createAutomate('and'),
  479.             class: LexClasses.operations.logical
  480.         },
  481.         or: {
  482.             automate: AutomateBuilder.createAutomate('or'),
  483.             class: LexClasses.operations.logical
  484.         },
  485.         '<': {
  486.             automate: AutomateBuilder.createAutomate('<'),
  487.             class: LexClasses.operations.compare
  488.         },
  489.         '>': {
  490.             automate: AutomateBuilder.createAutomate('>'),
  491.             class: LexClasses.operations.compare
  492.         },
  493.         '<=': {
  494.             automate: AutomateBuilder.createAutomate('<='),
  495.             class: LexClasses.operations.compare
  496.         },
  497.         '==': {
  498.             automate: AutomateBuilder.createAutomate('=='),
  499.             class: LexClasses.operations.compare
  500.         },
  501.         '<>': {
  502.             automate: AutomateBuilder.createAutomate('<>'),
  503.             class: LexClasses.operations.compare
  504.         },
  505.         '+': {
  506.             automate: AutomateBuilder.createAutomate('+'),
  507.             class: LexClasses.operations.math
  508.         },
  509.         '-': {
  510.             automate: AutomateBuilder.createAutomate('-'),
  511.             class: LexClasses.operations.math
  512.         },
  513.         '*': {
  514.             automate: AutomateBuilder.createAutomate('*'),
  515.             class: LexClasses.operations.math
  516.         },
  517.         '/': {
  518.             automate: AutomateBuilder.createAutomate('/'),
  519.             class: LexClasses.operations.math
  520.         },
  521.         '=': {
  522.             automate: AutomateBuilder.createAutomate('='),
  523.             class: LexClasses.operations.as
  524.         },
  525.         // end operations
  526.         // values
  527.         variable: {
  528.             automate: AutomateBuilder.createVariableAtomate(),
  529.             class: LexClasses.values.variable
  530.         },
  531.         numConst: {
  532.             automate: AutomateBuilder.createNumConstAtomate(),
  533.             class: LexClasses.values.numConst
  534.         },
  535.         // end values
  536.     }
  537. </script>
  538. <!-- Render -->
  539. <script>
  540.     const HTMLTags = {
  541.         Table: 'table',
  542.         TableRow: 'tr',
  543.         TableData: 'td'
  544.     }
  545.  
  546.     const ItemTypes = {
  547.         Value: 'VALUE',
  548.         Container: 'CONTAINER'
  549.     }
  550.  
  551.     function render(item) {
  552.         if (item.element) {
  553.             return item.element;
  554.         }
  555.  
  556.         let element = document.createElement(item.tag);
  557.         item.element = element;
  558.  
  559.         if (item.attributes) {
  560.             for (let name in item.attributes) {
  561.                 let value = item.attributes[name];
  562.                 element.setAttribute(name, value);
  563.             }
  564.         }
  565.  
  566.         switch (item.type) {
  567.             case ItemTypes.Value:
  568.                 if (item.value) {
  569.                     element.innerHTML = item.value;
  570.                 }
  571.                 break;
  572.             case ItemTypes.Container:
  573.                 if (item.childs) {
  574.                     for (let i in item.childs) {
  575.                         let child = item.childs[i];
  576.                         if (!child.element) {
  577.                             render(child);
  578.                         }
  579.                         element.append(child.element);
  580.                     }
  581.                 }
  582.                 break;
  583.         }
  584.  
  585.         return element;
  586.     }
  587. </script>
  588. <!-- Lex analizer -->
  589. <script>
  590.     function LexAnalizer(automatesList) {
  591.         this.automates = automatesList;
  592.         this.output = [];
  593.         this.execution = {
  594.             prevAutomates: [],
  595.             prevCompleteAutomates: [],
  596.             curAutomates: [],
  597.             accumulator: '',
  598.         };
  599.     }
  600.  
  601.     LexAnalizer.prototype = {
  602.         getAllAutomates() {
  603.             let list = Object.values(this.automates);
  604.             list.sort((a, b) => a.class.priority - b.class.priority);
  605.             list.forEach(element => element.automate.clearExecution());
  606.             return list;
  607.         },
  608.         getCompleteAutomates(automates) {
  609.             return automates.filter(value => value.automate.isComplete());
  610.         },
  611.         resetExecution() {
  612.             this.execution = {
  613.                 prevAutomates: this.getAllAutomates(),
  614.                 prevCompleteAutomates: null,
  615.                 curAutomates: [],
  616.                 accumulator: '',
  617.             };
  618.             this.execution.prevCompleteAutomates = this.getCompleteAutomates(this.execution.prevAutomates);
  619.         },
  620.         tryAddToOutput(index) {
  621.             if (this.execution.curAutomates.length < 1) {
  622.                 if (this.execution.prevAutomates.length > 0) {
  623.                     const lastAutomate = this.execution.prevCompleteAutomates[0];
  624.                     if (lastAutomate) {
  625.                         this.output.push({
  626.                             word: this.execution.accumulator,
  627.                             position: {
  628.                                 start: index - this.execution.accumulator.length,
  629.                                 end: index - 1
  630.                             },
  631.                             class: lastAutomate.class.value
  632.                         });
  633.                         return 3;
  634.                     }
  635.                     return 2;
  636.                 }
  637.                 return 1;
  638.             }
  639.             return 0;
  640.         },
  641.         prepareNextStep(letter) {
  642.             this.execution.prevAutomates = this.execution.curAutomates;
  643.             this.execution.prevCompleteAutomates = this.getCompleteAutomates(this.execution.prevAutomates);
  644.             this.execution.curAutomates = [];
  645.             this.execution.accumulator += letter;
  646.         },
  647.         analize(input) {
  648.             const space = ' ';
  649.             this.output = [];
  650.             this.resetExecution();
  651.             input = input.replaceAll(/\s+/g, space);
  652.  
  653.             for (let i = 0; i < input.length; i++) {
  654.                 const letter = input[i];
  655.  
  656.                 for (const automate of this.execution.prevAutomates) {
  657.                     try {
  658.                         automate.automate.processLetter(letter);
  659.                         this.execution.curAutomates.push(automate);
  660.                     } catch {
  661.                         automate.automate.clearExecution();
  662.                     }
  663.                 }
  664.  
  665.                 let stepFinished = this.tryAddToOutput(i);
  666.                 if (stepFinished) {
  667.                     this.resetExecution();
  668.                     if (letter != space) {
  669.                         i--;
  670.                     }
  671.                 } else {
  672.                     this.prepareNextStep(letter);
  673.                 }
  674.             }
  675.  
  676.             this.tryAddToOutput(input.length);
  677.         }
  678.     };
  679. </script>
  680. <!-- Sint classes -->
  681. <script>
  682.     const SintClasses = {
  683.         Value: 'sint.value',
  684.         // lex.values.variable
  685.         //  | lex.values.numConst
  686.         //  | lex.separators.bracket.start sint.math lex.separators.bracket.end
  687.         MathOperation: 'sint.math',
  688.         // sint.value lex.operations.math sint.math
  689.         //  | sint.value
  690.         LogicOperation: 'sint.logic.operation',
  691.         // lex.separators.bracket.start sint.math lex.operations.compare sint.math lex.separators.bracket.end
  692.         LogicExpression: 'sint.logic.expression',
  693.         // lex.separators.bracket.start sint.logic.expression lex.operations.logical sint.logic.expression lex.separators.bracket.end
  694.         //  | sint.logic.operation
  695.         Assignment: 'sint.assignment',
  696.         // lex.values.variable lex.operations.as sint.math
  697.         WhileLoop: 'sint.loop.while',
  698.         // lex.keyword.codeSegment.start lex.keyword.loop.while.start sint.logic.expression [sint.operation] lex.keyword.loop.while.end
  699.         Operation: 'sint.operation',
  700.         // sint.assignment
  701.         //  | sint.loop.while
  702.         Code: 'sint.code',
  703.         // [sint.operation]
  704.     };
  705. </script>
  706. <!-- SintAnalizer -->
  707. <script>
  708.     function SintAnalizer() {
  709.         this.lexList = [];
  710.         this.currentLexIndex = 0;
  711.         this.currentLex = {};
  712.         this.output = {};
  713.     }
  714.  
  715.     SintAnalizer.prototype = {
  716.         SetLexIndex(i) {
  717.             this.currentLexIndex = i;
  718.             this.currentLex = this.lexList[this.currentLexIndex];
  719.             //console.log(`${this.currentLexIndex}) ${JSON.stringify(this.currentLex)}`);
  720.         },
  721.         FirstLex() {
  722.             this.SetLexIndex(0);
  723.         },
  724.         NextLex() {
  725.             this.SetLexIndex(this.currentLexIndex + 1);
  726.         },
  727.         PrevLex() {
  728.             this.SetLexIndex(this.currentLexIndex - 1);
  729.         },
  730.         Error(expected) {
  731.             let text = `Incorrect char on position ${this.currentLex.position.start}. Expected (${JSON.stringify(expected)}) but has "${this.currentLex.class}"`;
  732.             throw new Error(text);
  733.         },
  734.         GenerateNode(value, type, pos) {
  735.             let node = {
  736.                 value: value,
  737.                 type: type,
  738.                 position: pos.start,
  739.                 nodes: [],
  740.                 UpdateValueByNodes() {
  741.                     if (this.nodes.length < 1) {
  742.                         return this.value;
  743.                     }
  744.  
  745.                     let nodesValues = this.nodes.map(n => n.UpdateValueByNodes());
  746.                     let newValue = nodesValues.join(' ');
  747.                     this.value = newValue;
  748.                     return newValue;
  749.                 }
  750.             };
  751.             return node;
  752.         },
  753.         GeneratePosNode(value, type) {
  754.             let node = this.GenerateNode(value, type, this.currentLex.position);
  755.             return node;
  756.         },
  757.         GenerateTypeNode(type) {
  758.             let node = this.GenerateNode('none', type, this.currentLex.position);
  759.             return node;
  760.         },
  761.         GenerateLexNode() {
  762.             let node = this.GeneratePosNode(this.currentLex.word, this.currentLex.class);
  763.             return node;
  764.         },
  765.         Value(parrentNode) {
  766.             // lex.values.variable
  767.             //  | lex.values.numConst
  768.             //  | lex.separators.bracket.start sint.math lex.separators.bracket.end
  769.             let node = this.GenerateTypeNode(SintClasses.Value);
  770.             let tempIndex = this.currentLexIndex;
  771.  
  772.             if (this.currentLex.class == LexClasses.separators.bracket.start.value) {
  773.                 let temp = this.GenerateLexNode();
  774.                 node.nodes.push(temp);
  775.                 this.NextLex();
  776.  
  777.                 this.MathOperation(node);
  778.  
  779.                 if (this.currentLex.class !== LexClasses.separators.bracket.end.value) {
  780.                     this.Error([LexClasses.separators.bracket.end.value]);
  781.                 }
  782.                 temp = this.GenerateLexNode();
  783.                 node.nodes.push(temp);
  784.                 this.NextLex();
  785.             } else {
  786.                 switch (this.currentLex.class) {
  787.                     case LexClasses.values.variable.value:
  788.                     case LexClasses.values.numConst.value:
  789.                         let inner = this.GenerateLexNode();
  790.                         node.nodes.push(inner);
  791.                         this.NextLex();
  792.                         break;
  793.                     default:
  794.                         this.Error([LexClasses.values.variable.value, LexClasses.values.numConst.value]);
  795.                 }
  796.             }
  797.  
  798.             parrentNode.nodes.push(node);
  799.         },
  800.         MathOperation(parrentNode) {
  801.             // sint.value lex.operations.math sint.math
  802.             //  | sint.value
  803.             let node = this.GenerateTypeNode(SintClasses.MathOperation);
  804.  
  805.             this.Value(node);
  806.  
  807.             if (this.currentLex.class === LexClasses.operations.math.value) {
  808.                 let temp = this.GenerateLexNode();
  809.                 node.nodes.push(temp);
  810.                 this.NextLex();
  811.  
  812.                 this.MathOperation(node);
  813.             }
  814.  
  815.             parrentNode.nodes.push(node);
  816.         },
  817.         LogicOperation(parrentNode) {
  818.             // lex.separators.bracket.start sint.math lex.operations.compare sint.math lex.separators.bracket.end
  819.             let node = this.GenerateTypeNode(SintClasses.LogicOperation);
  820.  
  821.             if (this.currentLex.class !== LexClasses.separators.bracket.start.value) {
  822.                 this.Error([LexClasses.separators.bracket.start.value]);
  823.             }
  824.             let temp = this.GenerateLexNode();
  825.             node.nodes.push(temp);
  826.             this.NextLex();
  827.  
  828.             this.MathOperation(node);
  829.  
  830.             if (this.currentLex.class !== LexClasses.operations.compare.value) {
  831.                 this.Error([LexClasses.operations.compare.value]);
  832.             }
  833.             temp = this.GenerateLexNode();
  834.             node.nodes.push(temp);
  835.             this.NextLex();
  836.  
  837.             this.MathOperation(node);
  838.  
  839.             if (this.currentLex.class !== LexClasses.separators.bracket.end.value) {
  840.                 this.Error([LexClasses.separators.bracket.end.value]);
  841.             }
  842.             temp = this.GenerateLexNode();
  843.             node.nodes.push(temp);
  844.             this.NextLex();
  845.  
  846.             parrentNode.nodes.push(node);
  847.         },
  848.         LogicExpression(parrentNode) {
  849.             // lex.separators.bracket.start sint.logic.expression lex.operations.logical sint.logic.expression lex.separators.bracket.end
  850.             //  | sint.logic.operation
  851.             let node = this.GenerateTypeNode(SintClasses.LogicExpression);
  852.  
  853.             let tempIndex = this.currentLexIndex;
  854.             try {
  855.                 this.LogicOperation(node);
  856.             } catch (error) {
  857.                 this.SetLexIndex(tempIndex);
  858.                 if (this.currentLex.class !== LexClasses.separators.bracket.start.value) {
  859.                     this.Error([LexClasses.separators.bracket.start.value]);
  860.                 }
  861.                 let temp = this.GenerateLexNode();
  862.                 node.nodes.push(temp);
  863.                 this.NextLex();
  864.  
  865.                 tempIndex = this.currentLexIndex;
  866.                 try {
  867.                     this.LogicExpression(node);
  868.                 } catch (error) {
  869.                     this.SetLexIndex(tempIndex);
  870.                     this.LogicOperation(node);
  871.                 }
  872.  
  873.                 if (this.currentLex.class !== LexClasses.operations.logical.value) {
  874.                     this.Error([LexClasses.operations.logical.value]);
  875.                 }
  876.                 temp = this.GenerateLexNode();
  877.                 node.nodes.push(temp);
  878.                 this.NextLex();
  879.  
  880.                 tempIndex = this.currentLexIndex;
  881.                 try {
  882.                     this.LogicExpression(node);
  883.                 } catch (error) {
  884.                     this.SetLexIndex(tempIndex);
  885.                     this.LogicOperation(node);
  886.                 }
  887.  
  888.                 if (this.currentLex.class !== LexClasses.separators.bracket.end.value) {
  889.                     this.Error([LexClasses.separators.bracket.end.value]);
  890.                 }
  891.                 temp = this.GenerateLexNode();
  892.                 node.nodes.push(temp);
  893.                 this.NextLex();
  894.             }
  895.  
  896.             parrentNode.nodes.push(node);
  897.         },
  898.         Assignment(parrentNode) {
  899.             // lex.values.variable lex.operations.as sint.math
  900.             let node = this.GenerateTypeNode(SintClasses.Assignment);
  901.  
  902.             if (this.currentLex.class !== LexClasses.values.variable.value) {
  903.                 this.Error([LexClasses.values.variable.value]);
  904.             }
  905.             let temp = this.GenerateLexNode();
  906.             node.nodes.push(temp);
  907.             this.NextLex();
  908.  
  909.             if (this.currentLex.class !== LexClasses.operations.as.value) {
  910.                 this.Error([LexClasses.operations.as.value]);
  911.             }
  912.             temp = this.GenerateLexNode();
  913.             node.nodes.push(temp);
  914.             this.NextLex();
  915.  
  916.             this.MathOperation(node);
  917.  
  918.             parrentNode.nodes.push(node);
  919.         },
  920.         WhileLoop(parrentNode) {
  921.             // lex.keyword.codeSegment.start lex.keyword.loop.while.start sint.logic.expression [sint.operation] lex.keyword.loop.while.end
  922.             let node = this.GenerateTypeNode(SintClasses.WhileLoop);
  923.  
  924.             if (this.currentLex.class !== LexClasses.keywords.codeSegment.start.value) {
  925.                 this.Error([LexClasses.keywords.codeSegment.start.value]);
  926.             }
  927.             let temp = this.GenerateLexNode();
  928.             node.nodes.push(temp);
  929.             this.NextLex();
  930.  
  931.             if (this.currentLex.class !== LexClasses.keywords.loop.while.start.value) {
  932.                 this.Error([LexClasses.keywords.loop.while.start.value]);
  933.             }
  934.             temp = this.GenerateLexNode();
  935.             node.nodes.push(temp);
  936.             this.NextLex();
  937.  
  938.             this.LogicExpression(node);
  939.  
  940.             while (this.currentLex.class !== LexClasses.keywords.loop.while.end.value) {
  941.                 this.Operation(node);
  942.             }
  943.  
  944.             if (this.currentLex.class !== LexClasses.keywords.loop.while.end.value) {
  945.                 this.Error([LexClasses.keywords.loop.while.end.value]);
  946.             }
  947.             temp = this.GenerateLexNode();
  948.             node.nodes.push(temp);
  949.             this.NextLex();
  950.  
  951.             parrentNode.nodes.push(node);
  952.         },
  953.         Operation(parrentNode) {
  954.             // sint.assignment
  955.             //  | sint.loop.while
  956.             let node = this.GenerateTypeNode(SintClasses.Operation);
  957.             switch (this.currentLex.class) {
  958.                 case LexClasses.values.variable.value:
  959.                     this.Assignment(node);
  960.                     break;
  961.                 case LexClasses.keywords.codeSegment.start.value:
  962.                     this.WhileLoop(node);
  963.                     break;
  964.                 default:
  965.                     throw this.Error([LexClasses.values.variable.value, LexClasses.keywords.codeSegment.start.value]);
  966.             }
  967.             parrentNode.nodes.push(node);
  968.         },
  969.         parse(lexems) {
  970.             this.lexList = lexems;
  971.             this.FirstLex();
  972.             this.output = this.GenerateTypeNode(SintClasses.Code);
  973.             try {
  974.                 while (this.currentLexIndex < this.lexList.length) {
  975.                     this.Operation(this.output);
  976.                 }
  977.                 this.output.UpdateValueByNodes();
  978.             } catch (ex) {
  979.                 alert(ex);
  980.             }
  981.         },
  982.     };
  983. </script>
  984.  
  985. <script src="http://synset.com/ai/_js/tree.js"></script>
  986.  
  987. <script>
  988.     const lexAnalizerInstance = new LexAnalizer(FullAutomatesList);
  989.  
  990.     const sintAnalizerInstance = new SintAnalizer();
  991.  
  992.     function drawLexOutputTable(output) {
  993.         let outputTable = {
  994.             tag: HTMLTags.Table,
  995.             type: ItemTypes.Container,
  996.             attributes: { border: "1" },
  997.             childs: []
  998.         };
  999.  
  1000.         outputTable.childs.push({
  1001.             tag: HTMLTags.TableRow,
  1002.             type: ItemTypes.Container,
  1003.             childs: [
  1004.                 {
  1005.                     tag: HTMLTags.TableData,
  1006.                     type: ItemTypes.Value,
  1007.                     value: 'Значение'
  1008.                 },
  1009.                 {
  1010.                     tag: HTMLTags.TableData,
  1011.                     type: ItemTypes.Value,
  1012.                     value: 'Начальная позиция'
  1013.                 },
  1014.                 {
  1015.                     tag: HTMLTags.TableData,
  1016.                     type: ItemTypes.Value,
  1017.                     value: 'Конечная позиция'
  1018.                 },
  1019.                 {
  1020.                     tag: HTMLTags.TableData,
  1021.                     type: ItemTypes.Value,
  1022.                     value: 'Класс'
  1023.                 },
  1024.             ]
  1025.         });
  1026.  
  1027.         for (const o of output) {
  1028.             outputTable.childs.push({
  1029.                 tag: HTMLTags.TableRow,
  1030.                 type: ItemTypes.Container,
  1031.                 childs: [
  1032.                     {
  1033.                         tag: HTMLTags.TableData,
  1034.                         type: ItemTypes.Value,
  1035.                         value: o.word
  1036.                     },
  1037.                     {
  1038.                         tag: HTMLTags.TableData,
  1039.                         type: ItemTypes.Value,
  1040.                         value: o.position.start
  1041.                     },
  1042.                     {
  1043.                         tag: HTMLTags.TableData,
  1044.                         type: ItemTypes.Value,
  1045.                         value: o.position.end
  1046.                     },
  1047.                     {
  1048.                         tag: HTMLTags.TableData,
  1049.                         type: ItemTypes.Value,
  1050.                         value: o.class
  1051.                     },
  1052.                 ]
  1053.             });
  1054.         }
  1055.  
  1056.         return outputTable;
  1057.     }
  1058.  
  1059.     function drawGraphTable(graphNode) {
  1060.         let curNode = undefined;
  1061.         let value = `(value: "${graphNode.value}", pos: ${graphNode.position}, type: ${graphNode.type})`;
  1062.         let tableAttrs = { border: "1", cellspacing: 0 };
  1063.  
  1064.         if (graphNode.nodes.length > 0) {
  1065.             const nodesList = {
  1066.                 tag: HTMLTags.TableRow,
  1067.                 type: ItemTypes.Container,
  1068.                 childs: []
  1069.             };
  1070.  
  1071.             for (const node of graphNode.nodes) {
  1072.                 nodesList.childs.push({
  1073.                     tag: HTMLTags.TableData,
  1074.                     type: ItemTypes.Container,
  1075.                     attributes: { align: 'center', valign: 'top' },
  1076.                     childs: [
  1077.                         drawGraphTable(node)
  1078.                     ]
  1079.                 });
  1080.             }
  1081.  
  1082.             curNode = {
  1083.                 tag: HTMLTags.Table,
  1084.                 type: ItemTypes.Container,
  1085.                 attributes: tableAttrs,
  1086.                 childs: [
  1087.                     {
  1088.                         tag: HTMLTags.TableRow,
  1089.                         type: ItemTypes.Container,
  1090.                         childs: [
  1091.                             {
  1092.                                 tag: HTMLTags.TableData,
  1093.                                 type: ItemTypes.Value,
  1094.                                 attributes: { colspan: graphNode.nodes.length, align: 'center', valign: 'top' },
  1095.                                 value: value
  1096.                             }
  1097.                         ]
  1098.                     },
  1099.                     nodesList
  1100.                 ]
  1101.             };
  1102.         } else {
  1103.             curNode = {
  1104.                 tag: HTMLTags.Table,
  1105.                 type: ItemTypes.Container,
  1106.                 attributes: tableAttrs,
  1107.                 childs: [
  1108.                     {
  1109.                         tag: HTMLTags.TableRow,
  1110.                         type: ItemTypes.Container,
  1111.                         childs: [
  1112.                             {
  1113.                                 tag: HTMLTags.TableData,
  1114.                                 type: ItemTypes.Value,
  1115.                                 attributes: { align: 'center', valign: 'top' },
  1116.                                 value: value
  1117.                             }
  1118.                         ]
  1119.                     }
  1120.                 ]
  1121.             };
  1122.         }
  1123.  
  1124.         return curNode;
  1125.     }
  1126.  
  1127.     document.getElementById('parseButton').onclick = () => {
  1128.         lexAnalizerInstance.analize(inputElement.value);
  1129.         lexOutputContainer.innerHTML = '';
  1130.         lexOutputContainer.append(render(drawLexOutputTable(lexAnalizerInstance.output)));
  1131.  
  1132.         sintAnalizerInstance.parse(lexAnalizerInstance.output);
  1133.         sintOutputContainer.innerHTML = '';
  1134.         sintOutputContainer.append(render(drawGraphTable(sintAnalizerInstance.output)));
  1135.  
  1136.         if (Tree) {
  1137.             function mapToTree(node) {
  1138.                 // if (node.nodes.length < 1) {
  1139.                 //     return {
  1140.                 //         nm: `(value: "${node.value}", pos: ${node.position}, type: ${node.type})`
  1141.                 //     };
  1142.                 // }
  1143.                 let res = {
  1144.                     nm: node.value,
  1145.                     ar: []
  1146.                 };
  1147.  
  1148.                 for (let inner of node.nodes) {
  1149.                     res.ar.push(mapToTree(inner));
  1150.                 }
  1151.  
  1152.                 return res;
  1153.             }
  1154.  
  1155.             let t1 = mapToTree(sintAnalizerInstance.output); // Tree.rand(3, 4, 0.1);
  1156.             let t2 = Tree.getSVG(t1);
  1157.             document.getElementById('sintOutputCanvas').innerHTML = t2;
  1158.         }
  1159.     };
  1160. </script>
  1161.  
  1162. </html>
Add Comment
Please, Sign In to add comment