semantics_visitor.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669
  1. import hutn_compiler.hutnparser as hp
  2. import hutn_compiler.symbol_table as st
  3. import sys
  4. from hutn_compiler.declare_functions_visitor import DeclareFunctionsVisitor
  5. from hutn_compiler.hutnparser import Tree
  6. from hutn_compiler.visitor import Visitor
  7. class SemanticsVisitor(Visitor):
  8. def __init__(self, args):
  9. Visitor.__init__(self, args)
  10. self.symbol_table = st.SymbolTable()
  11. # there is only one input file, list is for sharing it among visitors
  12. self.inputfiles = []
  13. # Count whether we are in a while or not
  14. self.while_counter = 0
  15. # inherited attribute, set in funcdecl and used in return,
  16. # to ensure that (returned type == declared type)
  17. self.current_funcdecl = None
  18. self.declare_functions_visitor = DeclareFunctionsVisitor(self.symbol_table, self.inputfiles)
  19. @staticmethod
  20. def incompatible_types(l_type, r_type):
  21. if type(l_type) != type(r_type):
  22. if "Void" in (type(l_type), type(r_type)):
  23. return True
  24. if "Element" in (type(l_type), type(r_type)):
  25. return False
  26. if l_type not in ["Integer", "Float", "Boolean"] or r_type not in ["Integer", "Float", "Boolean"]:
  27. return True
  28. return False
  29. def do_check_binary_ops_arithmetic(self, l, r):
  30. l_type, r_type = self.get_type(l), self.get_type(r)
  31. if SemanticsVisitor.incompatible_types(l_type, r_type):
  32. raise RuntimeError(
  33. "{}:{}:{}: error: invalid operands to binary operator "
  34. "(have {} and {})".format(self.inputfiles[0],
  35. l['startpos'][0],
  36. l['startpos'][1],
  37. str(l_type),
  38. str(r_type)))
  39. def check_binary_ops_arithmetic(self, tree):
  40. l, r = Tree.get_tail(tree)[0], Tree.get_tail(tree)[2]
  41. self.do_check_binary_ops_arithmetic(l, r)
  42. def generalize_binary_ops_arithmetic(self, tree):
  43. l, r = Tree.get_tail(tree)[0], Tree.get_tail(tree)[2]
  44. l_type, r_type = self.get_type(l), self.get_type(r)
  45. if l_type == "Float" or r_type == "Float":
  46. return "Float"
  47. elif l_type == "Integer" or r_type == "Integer":
  48. return "Integer"
  49. else:
  50. return "Boolean"
  51. def check_unary_ops_arithmetic(self, tree, operator_name):
  52. l = Tree.get_tail(tree)[1]
  53. l_type = self.get_type(l)
  54. if l_type not in ["Boolean", "Integer", "Float"]:
  55. raise RuntimeError(
  56. "{}:{}:{}: error: wrong type argument to unary {} "
  57. "({})".format(self.inputfiles[0],
  58. l['startpos'][0],
  59. l['startpos'][1],
  60. operator_name,
  61. str(l_type)))
  62. def promote_unary_ops_arithmetic(self, tree):
  63. l = Tree.get_tail(tree)[1]
  64. l_type = self.get_type(l)
  65. try:
  66. if l_type == "Boolean":
  67. return "Integer"
  68. elif l_type == "Integer" or l_type == "Float":
  69. return l_type
  70. else:
  71. raise RuntimeError("You cannot promote {} to a numeric type".format(str(l_type)))
  72. except RuntimeError:
  73. raise RuntimeError(
  74. "Pathological situation in promote_unary_ops_arithmetic: "
  75. "check_unary_ops_arithmetic has not been executed")
  76. # if r_type is provided, r is not used
  77. def do_check_assignment(self, l, r, r_type = None):
  78. if r_type is not None:
  79. l_type = self.get_type(l)
  80. else:
  81. l_type, r_type = self.get_type(l), self.get_type(r)
  82. if SemanticsVisitor.incompatible_types(l_type, r_type):
  83. raise RuntimeError("{}:{}:{}: error: cannot assign a value of "
  84. "type '{}' to a variable of type '{}'"
  85. .format(self.inputfiles[0],
  86. l['startpos'][0],
  87. l['startpos'][1],
  88. str(r_type),
  89. str(l_type)))
  90. def check_assignment(self, tree):
  91. l, r = Tree.get_tail(tree)[0], Tree.get_tail(tree)[2]
  92. self.do_check_assignment(l, r)
  93. def check_return(self, tree):
  94. l = self.current_funcdecl
  95. if len(Tree.get_tail(tree)) > 2:
  96. r = Tree.get_tail(tree)[1]
  97. r_type = None
  98. else:
  99. r = None
  100. r_type = "Void"
  101. if l:
  102. self.do_check_assignment(l, r, r_type)
  103. else:
  104. raise RuntimeError(
  105. "{}:{}:{}: error: 'return' is used outside of a function"
  106. .format(self.inputfiles[0],
  107. tree['startpos'][0],
  108. tree['startpos'][1]))
  109. def check_predicate(self, tree):
  110. if self.get_type(tree) == "Element":
  111. return
  112. if self.get_type(tree) not in ["Boolean", "Integer", "Float"]:
  113. raise RuntimeError(
  114. "{}:{}:{}: error: predicates of type '{}' are not allowed"
  115. .format(self.inputfiles[0],
  116. tree['startpos'][0],
  117. tree['startpos'][1],
  118. self.get_type(tree)))
  119. def replace_child_binary_op_with_call(self, tree, i=0):
  120. if i == -1:
  121. child = tree
  122. else:
  123. child = Tree.get_tail(tree)[i]
  124. if len(Tree.get_tail(child)) > 1:
  125. try:
  126. l, op, r = Tree.get_tail(child)
  127. except:
  128. # Something went wrong... this code is severely broken
  129. return
  130. l_type, r_type = self.get_type(l), self.get_type(r)
  131. if type(l_type) != type(r_type):
  132. print("Error: " + str(l_type) + " <-> " + str(r_type))
  133. raise RuntimeError(
  134. "{}:{}:{}: error: children were not casted".format(
  135. self.inputfiles[0],
  136. tree['startpos'][0],
  137. tree['startpos'][1]
  138. ))
  139. call_name = SemanticsVisitor.call_name_binary(l_type, op)
  140. call_tree = self.func_call(call_name, [l, r], tree)
  141. try:
  142. self.visit(call_tree)
  143. except RuntimeError:
  144. print(call_name)
  145. print(l_type)
  146. call_signature = "Boolean function {1}({2}, {2})".format(call_name, l_type)
  147. raise RuntimeError(
  148. "{}:{}:{}: error: cannot perform {}: function '{}' is "
  149. "not found".format(
  150. self.inputfiles[0],
  151. tree['startpos'][0],
  152. tree['startpos'][1],
  153. child['head'],
  154. call_signature))
  155. if i == -1:
  156. tree['head'] = call_tree['head']
  157. tree['tail'] = call_tree['tail']
  158. tree['_tail'] = None
  159. else:
  160. Tree.replace_child(tree, child, call_tree)
  161. self.set_type(tree, self.get_type(Tree.get_tail(tree)[i]))
  162. def replace_child_unary_op_with_call(self, tree):
  163. child = Tree.get_tail(tree)[0]
  164. if child['head'] == "keep_sign":
  165. Tree.replace_child(tree, child, Tree.get_tail(child)[1])
  166. else:
  167. op, l = Tree.get_tail(child)
  168. l_type = self.get_type(l)
  169. call_name = SemanticsVisitor.call_name_unary(l_type, op)
  170. call_tree = self.func_call(call_name, [l], tree)
  171. try:
  172. self.visit(call_tree)
  173. except RuntimeError:
  174. call_signature = "Boolean function {1}({2})".format(call_name, l_type)
  175. raise RuntimeError(
  176. "{}:{}:{}: error: cannot perform {}: function '{}' is "
  177. "not found".format(
  178. self.inputfiles[0],
  179. tree['startpos'][0],
  180. tree['startpos'][1],
  181. child['head'],
  182. call_signature))
  183. Tree.replace_child(tree, child, call_tree)
  184. self.set_type(tree, self.get_type(Tree.get_tail(tree)[0]))
  185. def cast_binary_ops_arithmetic(self, tree):
  186. l, op, r = Tree.get_tail(tree)
  187. l_type, r_type = self.get_type(l), self.get_type(r)
  188. if type(l_type) != type(r_type): # if two different numeric types
  189. if l_type == "Float" or r_type == "Float":
  190. g_type = "Float"
  191. elif l_type == "Integer" or r_type == "Integer":
  192. g_type = "Integer"
  193. else:
  194. g_type = "Boolean"
  195. self.perform_implicit_cast(tree, l, l_type, g_type)
  196. self.perform_implicit_cast(tree, r, r_type, g_type)
  197. def cast_binary_ops_logical(self, tree):
  198. l, op, r = Tree.get_tail(tree)
  199. l_type, r_type = self.get_type(l), self.get_type(r)
  200. self.perform_implicit_cast(tree, l, l_type, "Boolean")
  201. self.perform_implicit_cast(tree, r, r_type, "Boolean")
  202. def cast_unary_ops_arithmetic(self, tree):
  203. l = Tree.get_tail(tree)[1]
  204. l_type = self.get_type(l)
  205. p_type = self.promote_unary_ops_arithmetic(tree)
  206. self.perform_implicit_cast(tree, l, l_type, p_type)
  207. def func_call(self, name, params, old_tree):
  208. startpos = old_tree['startpos']
  209. endpos = old_tree['endpos']
  210. inputfile = old_tree['inputfile']
  211. tree = {"head": "func_call",
  212. "tail": [
  213. {"head": "rvalue",
  214. "tail": [
  215. {"head": "ID",
  216. "tail": [name],
  217. "startpos": startpos,
  218. "endpos": endpos,
  219. "inputfile": inputfile}],
  220. "startpos": startpos,
  221. "endpos": endpos,
  222. "inputfile": inputfile}],
  223. "startpos": startpos,
  224. "endpos": endpos,
  225. "inputfile": inputfile}
  226. for p in params:
  227. self.replace_child_binary_op_with_call(p, -1)
  228. params = [{"head": "expression", "tail": [p], "startpos": startpos, "endpos": endpos, "inputfile": inputfile} for p in params]
  229. tree['tail'].extend(params)
  230. return {"head": "expression", "tail": [tree], "startpos": startpos, "endpos": endpos, "inputfile": inputfile}
  231. @staticmethod
  232. def cast_name(from_type, to_type):
  233. to_t = str(to_type)[0].lower()
  234. cast_name = "cast_" + {"f": "float", "i": "integer", "b": "boolean", "s": "string"}[to_t]
  235. return cast_name
  236. def raise_implicit_cast_error(self, from_type, to_type, tree):
  237. cast_name = SemanticsVisitor.cast_name(from_type, to_type)
  238. cast_signature = "{} function {}({})".format(
  239. str(to_type), cast_name, str(from_type))
  240. raise RuntimeError(
  241. "{}:{}:{}: error: cannot perform implicit cast from '{}'"
  242. " to '{}': function '{}' is not found".format(
  243. self.inputfiles[0],
  244. tree['startpos'][0],
  245. tree['startpos'][1],
  246. str(to_type), str(from_type),
  247. cast_signature))
  248. def perform_implicit_cast(self, tree, child, from_type, to_type):
  249. if "Element" in (from_type, to_type):
  250. return
  251. if from_type == to_type:
  252. return
  253. cast_name = SemanticsVisitor.cast_name(from_type, to_type)
  254. cast_tree = self.func_call(cast_name, [child], tree)
  255. try:
  256. self.visit(cast_tree)
  257. except RuntimeError:
  258. self.raise_implicit_cast_error(from_type, to_type, child)
  259. Tree.replace_child(tree, child, cast_tree)
  260. types = {
  261. "Integer": "integer",
  262. "Float": "float",
  263. "Boolean": "bool",
  264. "String": "string",
  265. "Action": "action",
  266. "Element": "element",
  267. "Type": "type"
  268. }
  269. binary_ops = {
  270. "OR": "or",
  271. "AND": "and",
  272. "EQ": "eq",
  273. "NEQ": "neq",
  274. "LT": "lt",
  275. "GT": "gt",
  276. "LE": "lte",
  277. "GE": "gte",
  278. "PLUS": "addition",
  279. "MINUS": "subtraction",
  280. "STAR": "multiplication",
  281. "SLASH": "division"
  282. }
  283. unary_ops = {
  284. "NOT": "not",
  285. "MINUS": "neg"
  286. }
  287. @staticmethod
  288. def call_name_binary(operand_type, operator):
  289. # String joins should also be possible
  290. if str(operand_type) == "String":
  291. if operator['head'] == "PLUS":
  292. return "string_join"
  293. if operator['head'] == "EQ":
  294. return "value_eq"
  295. elif operator['head'] == "NEQ":
  296. return "value_neq"
  297. call_name = "{}_{}".format(SemanticsVisitor.types[str(operand_type)],
  298. SemanticsVisitor.binary_ops[operator['head']])
  299. return call_name
  300. @staticmethod
  301. def call_name_unary(operand_type, operator):
  302. call_name = "{}_{}".format(SemanticsVisitor.types[str(operand_type)],
  303. SemanticsVisitor.unary_ops[operator['head']])
  304. return call_name
  305. def dump(self):
  306. return Tree.get_text(self.tree, with_implicit=True)
  307. # return "No code generation here"
  308. # a visit_* method for each non-terminal in the grammar
  309. def visit_start(self, tree):
  310. self.symbol_table.open_scope()
  311. self.inputfiles.append(tree['inputfile'])
  312. for child in Tree.get_tail(tree):
  313. self.inputfiles[0] = child['inputfile']
  314. self.declare_functions_visitor.visit(child)
  315. for child in Tree.get_tail(tree):
  316. self.inputfiles[0] = child['inputfile']
  317. self.visit(child)
  318. self.inputfiles.pop()
  319. self.symbol_table.close_scope()
  320. self.tree = tree
  321. def visit_statement(self, tree):
  322. self.visit_children(tree)
  323. def visit_definition(self, tree):
  324. self.visit_vardecl(tree)
  325. def visit_vardecl(self, tree):
  326. type_spec = Tree.get_child(tree, "type_specifier")
  327. var_id = Tree.get_child(tree, "ID")
  328. var_type = Tree.get_text(type_spec)
  329. var_name = Tree.get_text(var_id)
  330. symbol = {"name": var_name, "type": var_type, "is_global": self.current_funcdecl is None, "node": None, "params": None}
  331. try:
  332. self.symbol_table.add(symbol)
  333. except Exception:
  334. raise RuntimeError(
  335. "{}:{}:{}: error: redeclaration of '{}'".format(
  336. self.inputfiles[0], tree['startpos'][0],
  337. tree['startpos'][1], var_name))
  338. self.set_symbol(tree, symbol)
  339. def visit_assignment(self, tree):
  340. self.visit_children(tree)
  341. self.check_assignment(tree)
  342. def visit_expression(self, tree):
  343. self.visit_children(tree)
  344. self.set_type(tree, self.get_type(Tree.get_tail(tree)[0]))
  345. def visit_binary_operation(self, tree):
  346. self.visit_children(tree)
  347. self.replace_child_binary_op_with_call(tree)
  348. def visit_disjunction(self, tree):
  349. self.visit_children(tree)
  350. if len(Tree.get_tail(tree)) == 1:
  351. self.replace_child_binary_op_with_call(tree)
  352. else:
  353. self.replace_child_binary_op_with_call(tree, 2)
  354. self.cast_binary_ops_logical(tree)
  355. self.set_type(tree, "Boolean")
  356. def visit_conjunction(self, tree):
  357. self.visit_children(tree)
  358. if len(Tree.get_tail(tree)) == 1:
  359. self.replace_child_binary_op_with_call(tree)
  360. else:
  361. self.replace_child_binary_op_with_call(tree, 2)
  362. self.cast_binary_ops_logical(tree)
  363. self.set_type(tree, "Boolean")
  364. def visit_comparison(self, tree):
  365. self.visit_children(tree)
  366. if len(Tree.get_tail(tree)) == 1:
  367. self.replace_child_binary_op_with_call(tree)
  368. else:
  369. self.replace_child_binary_op_with_call(tree, 2)
  370. self.check_binary_ops_arithmetic(tree)
  371. self.cast_binary_ops_arithmetic(tree)
  372. self.set_type(tree, "Boolean")
  373. def visit_relation(self, tree):
  374. self.visit_children(tree)
  375. if len(Tree.get_tail(tree)) == 1:
  376. self.replace_child_binary_op_with_call(tree)
  377. else:
  378. self.replace_child_binary_op_with_call(tree, 2)
  379. self.check_binary_ops_arithmetic(tree)
  380. self.cast_binary_ops_arithmetic(tree)
  381. self.set_type(tree, "Boolean")
  382. def visit_sum(self, tree):
  383. self.visit_children(tree)
  384. if len(Tree.get_tail(tree)) == 1:
  385. self.replace_child_binary_op_with_call(tree)
  386. else:
  387. self.replace_child_binary_op_with_call(tree, 2)
  388. self.check_binary_ops_arithmetic(tree)
  389. self.cast_binary_ops_arithmetic(tree)
  390. # after the cast both parameters have the same (generalized) type:
  391. self.set_type(tree, self.get_type(Tree.get_tail(tree)[0]))
  392. def visit_term(self, tree):
  393. self.visit_children(tree)
  394. if len(Tree.get_tail(tree)) == 1:
  395. self.set_type(tree, self.get_type(Tree.get_tail(tree)[0]))
  396. else:
  397. self.check_binary_ops_arithmetic(tree)
  398. self.cast_binary_ops_arithmetic(tree)
  399. # after the cast both parameters have the same (generalized) type:
  400. self.set_type(tree, self.get_type(Tree.get_tail(tree)[0]))
  401. def visit_factor(self, tree):
  402. self.visit_children(tree)
  403. if Tree.get_child(tree, "primary") is not None:
  404. self.set_type(tree, self.get_type(Tree.get_tail(tree)[0]))
  405. else:
  406. self.replace_child_unary_op_with_call(tree)
  407. def visit_logical_not(self, tree):
  408. self.visit_children(tree)
  409. l = Tree.get_tail(tree)[1]
  410. l_type = self.get_type(l)
  411. self.perform_implicit_cast(tree, l, l_type, "Boolean")
  412. self.set_type(tree, self.get_type(Tree.get_tail(tree)[1]))
  413. def visit_invert_sign(self, tree):
  414. self.visit_children(tree)
  415. self.check_unary_ops_arithmetic(tree, "minus")
  416. self.cast_unary_ops_arithmetic(tree)
  417. self.set_type(tree, self.get_type(Tree.get_tail(tree)[1]))
  418. def visit_keep_sign(self, tree):
  419. self.visit_children(tree)
  420. self.check_unary_ops_arithmetic(tree, "plus")
  421. self.cast_unary_ops_arithmetic(tree)
  422. self.set_type(tree, self.get_type(Tree.get_tail(tree)[1]))
  423. def visit_primary(self, tree):
  424. self.visit_children(tree)
  425. self.set_type(tree, self.get_type(Tree.get_tail(tree)[0]))
  426. def visit_parenthesized(self, tree):
  427. self.visit_children(tree)
  428. self.set_type(tree, self.get_type(Tree.get_tail(tree)[1]))
  429. def visit_atomvalue(self, tree):
  430. self.visit_children(tree)
  431. self.set_type(tree, self.get_type(Tree.get_tail(tree)[0]))
  432. def visit_type_specifier(self, tree):
  433. self.set_type(tree, "Type")
  434. def visit_actionname(self, tree):
  435. self.set_type(tree, "Action")
  436. def visit_string(self, tree):
  437. self.set_type(tree, "String")
  438. def visit_integer(self, tree):
  439. self.set_type(tree, "Integer")
  440. def visit_float(self, tree):
  441. self.set_type(tree, "Float")
  442. # there is no such rule in the grammar, we just avoid code duplicates
  443. def visit_id(self, tree):
  444. name = Tree.get_text(tree)
  445. #TODO this is set to the function returnvalue, even if we use the function pointer...
  446. try:
  447. symbol = self.symbol_table.get(name)
  448. except KeyError:
  449. raise RuntimeError("{}:{}:{}: error: '{}' is not declared".format(
  450. self.inputfiles[0], tree['startpos'][0],
  451. tree['startpos'][1], name))
  452. self.set_type(tree, symbol['type'])
  453. self.set_symbol(tree, symbol)
  454. def visit_rvalue(self, tree):
  455. if len(Tree.get_tail(tree)) > 1:
  456. # Complex: dict_read operation needed
  457. child = Tree.get_tail(tree)[0]
  458. node = Tree.get_child(tree, "rvalue")
  459. expression = Tree.get_child(tree, "expression")
  460. operation = "dict_read"
  461. call_tree = self.func_call(operation, [node, expression], tree)
  462. self.visit(call_tree)
  463. tree['head'] = call_tree['head']
  464. tree['_tail'] = call_tree['tail']
  465. tree['tail'] = call_tree['tail']
  466. self.set_type(tree, self.get_type(node))
  467. else:
  468. # Simple
  469. self.visit_id(tree)
  470. def visit_lvalue(self, tree):
  471. self.visit_id(tree)
  472. def visit_func_call(self, tree):
  473. self.visit_children(tree)
  474. symbol = self.get_symbol(Tree.get_tail(tree)[0])
  475. self.set_type(tree, symbol['type'])
  476. if not st.Symbol.is_func(symbol):
  477. if symbol['type'] == "Element":
  478. return # allow the call without knowing the declaration
  479. raise RuntimeError(
  480. "{}:{}:{}: error: '{}' is a variable of type '{}', not a "
  481. "function".format(self.inputfiles[0],
  482. tree['startpos'][0],
  483. tree['startpos'][1],
  484. symbol['name'],
  485. symbol['type']))
  486. expressions = Tree.get_children(tree, "expression")
  487. if len(expressions) != len(symbol['params']):
  488. raise RuntimeError(
  489. "{}:{}:{}: error: wrong number of arguments to "
  490. "function '{}'".format(self.inputfiles[0],
  491. tree['startpos'][0],
  492. tree['startpos'][1],
  493. st.Symbol.signature(symbol)))
  494. if symbol['name'] == "__input":
  495. tree['head'] = "input"
  496. elif symbol['name'] == "__output":
  497. tree['head'] = "output"
  498. def visit_input(self, tree):
  499. pass # no need to visit it again
  500. def visit_output(self, tree):
  501. pass # no need to visit it again
  502. def visit_dictionary(self, tree):
  503. self.set_type(tree, "Element")
  504. def visit_list(self, tree):
  505. self.set_type(tree, "Element")
  506. def visit_dict_item(self, tree):
  507. pass
  508. def visit_ifelse(self, tree):
  509. self.visit_children(tree)
  510. expressions = Tree.get_children(tree, "expression")
  511. for expression in expressions:
  512. self.check_predicate(expression)
  513. def visit_while(self, tree):
  514. self.while_counter += 1
  515. self.visit_children(tree)
  516. self.while_counter -= 1
  517. expression = Tree.get_child(tree, "expression")
  518. self.check_predicate(expression)
  519. def visit_block(self, tree):
  520. self.symbol_table.open_scope()
  521. self.visit_children(tree)
  522. self.symbol_table.close_scope()
  523. def visit_func_body(self, tree):
  524. self.visit_children(tree)
  525. def visit_funcdecl(self, tree):
  526. # here we only visit the body cause the declaration is already done
  527. # by declare_functions_visitor
  528. if Tree.get_child(tree, 'func_body') is not None:
  529. self.current_funcdecl = tree
  530. self.symbol_table.open_scope()
  531. self.visit_children(tree)
  532. self.symbol_table.close_scope()
  533. self.current_funcdecl = None
  534. def visit_parameter(self, tree):
  535. param_id = Tree.get_child(tree, "ID")
  536. type_spec = Tree.get_child(tree, "type_specifier")
  537. param_type = Tree.get_text(type_spec)
  538. param_name = Tree.get_text(param_id)
  539. symbol = {"name": param_name, "type": param_type, "is_global": False, "node": None, "params": None}
  540. try:
  541. self.symbol_table.add(symbol)
  542. except Exception:
  543. raise RuntimeError(
  544. "{}:{}:{}: error: redeclaration of '{}'".format(
  545. self.inputfiles[0], tree['startpos'][0],
  546. tree['startpos'][1], param_name))
  547. self.set_symbol(tree, symbol)
  548. def visit_return(self, tree):
  549. self.visit_children(tree)
  550. self.check_return(tree)
  551. def visit_bool(self, tree):
  552. self.set_type(tree, "Boolean")
  553. def visit_break(self, tree):
  554. if self.while_counter == 0:
  555. raise RuntimeError(
  556. "{}:{}:{}: error: break outside of while".format(
  557. self.inputfiles[0], tree['startpos'][0],
  558. tree['startpos'][1]))
  559. def visit_continue(self, tree):
  560. if self.while_counter == 0:
  561. raise RuntimeError(
  562. "{}:{}:{}: error: continue outside of while".format(
  563. self.inputfiles[0], tree['startpos'][0],
  564. tree['startpos'][1]))