项目作者: artifact-project

项目描述 :
Tiny lexical analyzer (Draft)
高级语言: TypeScript
项目地址: git://github.com/artifact-project/skeletik.git
创建时间: 2016-07-11T15:08:58Z
项目社区:https://github.com/artifact-project/skeletik

开源协议:

下载


Skeletik

Tiny lexical analyzer

  1. npm i --save-dev skeletik

API

  1. const parse = skeletik({
  2. // Ranges
  3. // key — name of range
  4. // value — array of symbols and intervals (ex 0-9 or a-b)
  5. '$number': ['0-9'],
  6. '$binary': ['+', '-', '/', '*'],
  7. }, {
  8. // States
  9. '': { // <- initial and also default state
  10. // State Rules
  11. // key — one symbol or region name
  12. // value — handler or next name of a state
  13. '$number': 'NUMBER',
  14. // any
  15. '': (lex, bone) => lex.error(`Invalid character \`${lex.getChar()}\`, state: ${lex.state}`, bone);
  16. },
  17. 'NUMBER': {
  18. // ...
  19. }
  20. });

Example

  1. // Tokens
  2. const T_GROUP = 'group';
  3. const T_NUMBER = 'number';
  4. const T_BINARY = 'binary';
  5. // Priority of operations
  6. const PRIORITY = {
  7. '/': 1,
  8. '*': 1,
  9. };
  10. // Бинарные опреации
  11. const BINARY = {
  12. '/': function (a, b) { return a / b },
  13. '*': function (a, b) { return a * b },
  14. '+': function (a, b) { return a + b },
  15. '-': function (a, b) { return a - b },
  16. };
  17. // Create parser
  18. const ast = {};
  19. const parse = skeletik({
  20. 'number': ['0-9'],
  21. 'binary': ['+', '-', '/', '*'],
  22. }, {
  23. // Inited state
  24. '': {
  25. 'number'(lex, bone) {
  26. const chr = lex.getChar();
  27. const last = bone.last;
  28. if (last && (last.type === T_NUMBER || !last.prev || last.prev.type === T_BINARY)) {
  29. last.type = T_NUMBER;
  30. last.raw += chr;
  31. } else {
  32. bone.add(T_NUMBER, chr);
  33. }
  34. },
  35. 'binary'(lex, bone) {
  36. bone.add(T_BINARY, lex.getChar());
  37. },
  38. '(': (lex, bone) => bone.add(T_GROUP).last,
  39. ')': (lex, bone) => bone.parent,
  40. },
  41. });
  42. function calculator(expr) {
  43. const root = parse(expr);
  44. return (function _calc(root) {
  45. const stack = [];
  46. const ops = [];
  47. for (let i = 0; i < root.length; i++) {
  48. const bone = root.nodes[i];
  49. if (bone.type === T_BINARY) {
  50. if (PRIORITY[bone.raw]) {
  51. stack[stack.length - 1] = BINARY[bone.raw](stack[stack.length - 1], +bone.next.raw);
  52. i++;
  53. } else {
  54. ops.push(bone.raw);
  55. }
  56. } else {
  57. stack.push(bone.type === T_GROUP ? _calc(bone) : +bone.raw);
  58. }
  59. }
  60. let results = stack.pop();
  61. while (ops.length) {
  62. results = BINARY[ops.pop()](results, stack.pop());
  63. }
  64. return results;
  65. })(root);
  66. };
  67. const str = '(1 + 2) * 4 / -3 + 1';
  68. console.log('results:', calculator(str), eval(str) === calculator(str));