CAT-SOOP is a flexible, programmable learning management system based on the Python programming language. https://catsoop.mit.edu
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

148 lines
3.6 KiB

  1. # This file is part of CAT-SOOP
  2. # Copyright (c) 2011-2020 by The CAT-SOOP Developers <catsoop-dev@mit.edu>
  3. #
  4. # This program is free software: you can redistribute it and/or modify it under
  5. # the terms of the GNU Affero General Public License as published by the Free
  6. # Software Foundation, either version 3 of the License, or (at your option) any
  7. # later version.
  8. #
  9. # This program is distributed in the hope that it will be useful, but WITHOUT
  10. # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  11. # FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
  12. # details.
  13. #
  14. # You should have received a copy of the GNU Affero General Public License
  15. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. import ast
  17. def parser(lex=None, yacc=None):
  18. tokens = (
  19. "PLUS",
  20. "MINUS",
  21. "TIMES",
  22. "DIVIDE",
  23. "EXP",
  24. "COMMA",
  25. "LPAREN",
  26. "RPAREN",
  27. "NAME",
  28. "NUMBER",
  29. )
  30. t_ignore = " \t"
  31. t_PLUS = r"\+"
  32. t_MINUS = r"-"
  33. t_TIMES = r"\*"
  34. t_DIVIDE = r"/"
  35. t_EXP = r"\^"
  36. t_COMMA = r","
  37. t_LPAREN = r"\("
  38. t_RPAREN = r"\)"
  39. t_NAME = r"[A-Za-z][A-Za-z0-9]*(_[A-Za-z0-9]*)?"
  40. t_NUMBER = r"((\d+\.\d*|\.\d+)([eE][-+]?\d+)?|\d+[eE][-+]?\d+|\d+)[jJ]?"
  41. lex.lex()
  42. precedence = (
  43. ("left", "PLUS", "MINUS"),
  44. ("left", "TIMES", "DIVIDE"),
  45. ("right", "UMINUS"),
  46. ("right", "EXP"),
  47. )
  48. def p_expression_binop(t):
  49. """
  50. expression : expression PLUS expression
  51. | expression MINUS expression
  52. | expression TIMES expression
  53. | expression DIVIDE expression
  54. | expression EXP expression
  55. | number name EXP expression
  56. | number name
  57. """
  58. if len(t) == 4:
  59. t[0] = [t[2], t[1], t[3]]
  60. elif len(t) == 5:
  61. t[0] = ["*", t[1], ["^", t[2], t[4]]]
  62. else:
  63. t[0] = ["*", t[1], t[2]]
  64. def p_expression_grouped(t):
  65. """
  66. expression : LPAREN expression RPAREN
  67. """
  68. t[0] = t[2]
  69. def p_expression_call(t):
  70. """
  71. expression : name LPAREN list_of_expressions RPAREN
  72. """
  73. t[0] = ["CALL", t[1], t[3]]
  74. def p_expression_impmul(t):
  75. """
  76. expression : LPAREN expression RPAREN LPAREN expression RPAREN
  77. | number LPAREN expression RPAREN
  78. """
  79. if len(t) == 5:
  80. t[0] = ["*", t[1], t[3]]
  81. else:
  82. t[0] = ["*", t[2], t[5]]
  83. def p_list_of_expressions(t):
  84. """
  85. list_of_expressions : empty
  86. | expression COMMA list_of_expressions
  87. | expression opt_comma
  88. """
  89. if len(t) == 4:
  90. t[0] = [t[1]] + t[3]
  91. elif len(t) == 3:
  92. t[0] = [t[1]]
  93. else:
  94. t[0] = []
  95. def p_opt_comma(t):
  96. """
  97. opt_comma : empty
  98. | COMMA
  99. """
  100. pass
  101. def p_expression_uminus(t):
  102. """
  103. expression : MINUS expression %prec UMINUS
  104. """
  105. t[0] = ["u-", t[2]]
  106. def p_expression_atom(t):
  107. """
  108. expression : number
  109. | name
  110. """
  111. t[0] = t[1]
  112. def p_number(t):
  113. """
  114. number : NUMBER
  115. """
  116. t[0] = ["NUMBER", t[1]]
  117. def p_name(t):
  118. """
  119. name : NAME
  120. """
  121. t[0] = ["NAME", t[1]]
  122. def p_empty(p):
  123. """
  124. empty :
  125. """
  126. pass
  127. return yacc.yacc(optimize=False, debug=False, write_tables=False)