Clarkoer commited on
Commit
ffd4541
·
1 Parent(s): acc0939

add array passing to function

Browse files
Backend/GALinterpreter.py CHANGED
@@ -764,7 +764,8 @@ class Interpreter:
764
  raise Exception(f"Invalid parameter: {param.value}")
765
  param_type = param.children[0].value
766
  param_name = param.children[1].value
767
- params.append({"name": param_name, "type": param_type})
 
768
 
769
  self.declare_function(func_name, return_type, params, node)
770
 
@@ -909,8 +910,9 @@ class Interpreter:
909
  param_name = param["name"]
910
  param_type = param["type"]
911
  arg_value = args[i]
 
912
  #print(f"\n[CALL] In function: {function_name} — Argument '{param_name}' of type '{param_type}' with value: {arg_value}")
913
- self.declare_variable(param_name, param_type, arg_value)
914
 
915
  try:
916
  self.eval_block(function_node.children[2])
 
764
  raise Exception(f"Invalid parameter: {param.value}")
765
  param_type = param.children[0].value
766
  param_name = param.children[1].value
767
+ is_list = any(child.node_type == "ArrayParam" for child in param.children)
768
+ params.append({"name": param_name, "type": param_type, "is_list": is_list})
769
 
770
  self.declare_function(func_name, return_type, params, node)
771
 
 
910
  param_name = param["name"]
911
  param_type = param["type"]
912
  arg_value = args[i]
913
+ is_list = param.get("is_list", False)
914
  #print(f"\n[CALL] In function: {function_name} — Argument '{param_name}' of type '{param_type}' with value: {arg_value}")
915
+ self.declare_variable(param_name, param_type, arg_value, is_list=is_list)
916
 
917
  try:
918
  self.eval_block(function_node.children[2])
Backend/GALsemantic.py CHANGED
@@ -631,11 +631,22 @@ def parse_function(tokens, index, func_name, func_type):
631
  param_node = ASTNode("Parameter")
632
  param_node.add_child(ASTNode("Type", param_type))
633
  param_node.add_child(ASTNode("Identifier", param_name))
 
 
 
 
 
 
 
 
 
 
 
 
634
  params_node.add_child(param_node)
635
- error = symbol_table.declare_variable(param_name, param_type)
636
  if error:
637
  raise SemanticError(error, line)
638
- index += 1
639
 
640
  if tokens[index].type == ",":
641
  index += 1
@@ -802,6 +813,24 @@ def parse_variable(tokens, index, var_name, var_type):
802
 
803
  list_node = build_list_node(dimensions)
804
  var_node.add_child(list_node)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
805
 
806
  else:
807
  # Uninitialized declaration: vine name; or seed x;
@@ -2281,7 +2310,26 @@ def parse_function_call(tokens, index, func_name, func_type, func_params):
2281
 
2282
  expected_type = expected_params[len(provided_args)].children[0].value
2283
 
2284
- expr_node, index = parse_expression_type(tokens, index, expected_type)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2285
 
2286
  arg_node = ASTNode("Argument")
2287
  arg_node.add_child(expr_node)
 
631
  param_node = ASTNode("Parameter")
632
  param_node.add_child(ASTNode("Type", param_type))
633
  param_node.add_child(ASTNode("Identifier", param_name))
634
+ index += 1
635
+
636
+ # Check for array parameter: seed arr[]
637
+ is_list = False
638
+ if tokens[index].type == "[":
639
+ index += 1 # skip '['
640
+ if tokens[index].type != "]":
641
+ raise SemanticError(f"Syntax Error: Expected ']' after '[' in array parameter.", line)
642
+ index += 1 # skip ']'
643
+ is_list = True
644
+ param_node.add_child(ASTNode("ArrayParam", "true"))
645
+
646
  params_node.add_child(param_node)
647
+ error = symbol_table.declare_variable(param_name, param_type, is_list=is_list)
648
  if error:
649
  raise SemanticError(error, line)
 
650
 
651
  if tokens[index].type == ",":
652
  index += 1
 
813
 
814
  list_node = build_list_node(dimensions)
815
  var_node.add_child(list_node)
816
+
817
+ # Handle optional initialization after size: seed nums[3] = {10, 20, 30} ;
818
+ if tokens[index].type == "=":
819
+ index += 1 # skip '='
820
+ if tokens[index].type == "{":
821
+ index += 1 # skip '{'
822
+ elements = []
823
+ while tokens[index].type != "}":
824
+ expr, index = parse_expression_type(tokens, index, var_type)
825
+ elements.append(expr)
826
+ if tokens[index].type == ",":
827
+ index += 1
828
+ index += 1 # skip '}'
829
+ value_node = ListNode(elements=elements, line=line)
830
+ # Replace the default list_node with the initialized values
831
+ var_node.children[-1] = value_node
832
+ else:
833
+ raise SemanticError(f"Syntax Error: Expected '{{' after '=' in array initialization.", line)
834
 
835
  else:
836
  # Uninitialized declaration: vine name; or seed x;
 
2310
 
2311
  expected_type = expected_params[len(provided_args)].children[0].value
2312
 
2313
+ # Check if the expected parameter is an array parameter
2314
+ expected_param = expected_params[len(provided_args)]
2315
+ is_array_param = any(child.node_type == "ArrayParam" for child in expected_param.children)
2316
+
2317
+ if is_array_param:
2318
+ # Array parameter: expect an array identifier
2319
+ if tokens[index].type != "id":
2320
+ raise SemanticError(f"Semantic Error: Expected array variable for parameter {len(provided_args) + 1} of '{func_name}'.", line)
2321
+ arg_name = tokens[index].value
2322
+ arg_info = symbol_table.lookup_variable(arg_name)
2323
+ if isinstance(arg_info, str):
2324
+ raise SemanticError(arg_info, line)
2325
+ if not arg_info.get("is_list", False):
2326
+ raise SemanticError(f"Semantic Error: Argument '{arg_name}' is not an array. Parameter {len(provided_args) + 1} of '{func_name}' expects an array.", line)
2327
+ if arg_info["type"] != expected_type:
2328
+ raise SemanticError(f"Semantic Error: Array argument '{arg_name}' is of type '{arg_info['type']}', but parameter expects '{expected_type}'.", line)
2329
+ expr_node = ASTNode("Identifier", arg_name, line=line)
2330
+ index += 1
2331
+ else:
2332
+ expr_node, index = parse_expression_type(tokens, index, expected_type)
2333
 
2334
  arg_node = ASTNode("Argument")
2335
  arg_node.add_child(expr_node)
Backend/cfg.py CHANGED
@@ -367,10 +367,15 @@ cfg = {
367
  ],
368
 
369
  "<param>": [
370
- ["<data_type>", "id"], # Parameter: primitive type + name
371
  ["id", "id"], # Parameter: bundle type + name (e.g., Pair p)
372
  ],
373
 
 
 
 
 
 
374
  "<param_next>": [
375
  [EPSILON], # Last parameter
376
  [",", "<param>", "<param_next>"], # More parameters
 
367
  ],
368
 
369
  "<param>": [
370
+ ["<data_type>", "id", "<param_array>"], # Parameter: primitive type + name (optionally array)
371
  ["id", "id"], # Parameter: bundle type + name (e.g., Pair p)
372
  ],
373
 
374
+ "<param_array>": [
375
+ [EPSILON], # Scalar parameter
376
+ ["[", "]"], # Array parameter: seed arr[]
377
+ ],
378
+
379
  "<param_next>": [
380
  [EPSILON], # Last parameter
381
  [",", "<param>", "<param_next>"], # More parameters
Backend/icg.py CHANGED
@@ -489,8 +489,12 @@ class ICGenerator:
489
  self._expect("{")
490
 
491
  self._emit("FUNC", func_name.value)
492
- for ptype, pname in params:
493
- self._emit("DECLARE", GAL_TYPE_MAP.get(ptype, ptype), None, pname)
 
 
 
 
494
 
495
  self._declaration()
496
  self._statement()
@@ -508,9 +512,9 @@ class ICGenerator:
508
  self._expect("}")
509
  self._emit("ENDFUNC")
510
 
511
- def _parameters(self) -> List[Tuple[str, str]]:
512
  """<parameters> → <param> <param_next> | λ"""
513
- params: List[Tuple[str, str]] = []
514
  if self._is_data_type(self._peek()) or self._peek().type == "id":
515
  p = self._param()
516
  params.append(p)
@@ -524,7 +528,13 @@ class ICGenerator:
524
  id_tok = self._expect("id")
525
  # For bundle types, dtype.type is "id" — use dtype.value to get the actual type name
526
  type_name = dtype.value if dtype.type == "id" else dtype.type
527
- return (type_name, id_tok.value)
 
 
 
 
 
 
528
 
529
  # ======================================================================
530
  # STATEMENTS
 
489
  self._expect("{")
490
 
491
  self._emit("FUNC", func_name.value)
492
+ for ptype, pname, *rest in params:
493
+ is_array = rest[0] if rest else False
494
+ if is_array:
495
+ self._emit("ARRAY_DECLARE", GAL_TYPE_MAP.get(ptype, ptype), "param", pname)
496
+ else:
497
+ self._emit("DECLARE", GAL_TYPE_MAP.get(ptype, ptype), None, pname)
498
 
499
  self._declaration()
500
  self._statement()
 
512
  self._expect("}")
513
  self._emit("ENDFUNC")
514
 
515
+ def _parameters(self):
516
  """<parameters> → <param> <param_next> | λ"""
517
+ params = []
518
  if self._is_data_type(self._peek()) or self._peek().type == "id":
519
  p = self._param()
520
  params.append(p)
 
528
  id_tok = self._expect("id")
529
  # For bundle types, dtype.type is "id" — use dtype.value to get the actual type name
530
  type_name = dtype.value if dtype.type == "id" else dtype.type
531
+ # Check for array parameter: seed arr[]
532
+ is_array = False
533
+ if self._peek().type == "[":
534
+ self._advance() # skip '['
535
+ self._expect("]")
536
+ is_array = True
537
+ return (type_name, id_tok.value, is_array)
538
 
539
  # ======================================================================
540
  # STATEMENTS
Backend/test_array_param.py ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Quick test for array parameter passing feature."""
2
+ from lexer import Lexer
3
+ from Gal_Parser import LL1Parser
4
+ from GALsemantic import build_ast
5
+ from GALinterpreter import Interpreter
6
+ from cfg import cfg, first_sets, predict_sets
7
+
8
+ code = '''
9
+ pollinate empty printEl(seed arr[], seed i) {
10
+ plant("{} ", arr[i]) ;
11
+ reclaim ;
12
+ }
13
+
14
+ root() {
15
+ seed nums[3] ;
16
+ nums[0] = 10 ;
17
+ nums[1] = 20 ;
18
+ nums[2] = 30 ;
19
+ printEl(nums, 0) ;
20
+ printEl(nums, 1) ;
21
+ printEl(nums, 2) ;
22
+ reclaim ;
23
+ }
24
+ '''
25
+
26
+ # Lexer
27
+ lexer = Lexer(code)
28
+ tokens, lex_errors = lexer.make_tokens()
29
+ print("Lex OK:", len(tokens), "tokens, errors:", lex_errors)
30
+
31
+ # Parser
32
+ parser = LL1Parser(cfg=cfg, predict_sets=predict_sets, first_sets=first_sets)
33
+ errors = parser.parse(tokens)
34
+ print("Parse errors:", errors)
35
+
36
+ # Semantic + AST
37
+ filtered = [t for t in tokens if t.type != '\n']
38
+ ast = build_ast(filtered)
39
+ print("Semantic + AST OK")
40
+
41
+ # Interpreter — patch plant() since no Socket.IO in test
42
+ interp = Interpreter()
43
+ interp.plant = lambda value: print(value, end="")
44
+ interp.interpret(ast)
45
+ print("\nDone")
Backend/test_curly_init.py ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Test array initialization with curly brace syntax: seed nums[3] = {10, 20, 30}"""
2
+ from lexer import Lexer
3
+ from Gal_Parser import LL1Parser
4
+ from GALsemantic import build_ast
5
+ from GALinterpreter import Interpreter
6
+ from cfg import cfg, first_sets, predict_sets
7
+
8
+ code = '''
9
+ pollinate empty printArr(seed arr[], seed n, seed i) {
10
+ spring(i >= n) {
11
+ reclaim ;
12
+ }
13
+ plant("{} ", arr[i]) ;
14
+ printArr(arr, n, i + 1) ;
15
+ reclaim ;
16
+ }
17
+
18
+ root() {
19
+ seed nums[3] = {10, 20, 30} ;
20
+ printArr(nums, 3, 0) ;
21
+ reclaim ;
22
+ }
23
+ '''
24
+
25
+ lexer = Lexer(code)
26
+ tokens, lex_errors = lexer.make_tokens()
27
+ print("Lex:", len(tokens), "tokens, errors:", lex_errors)
28
+
29
+ parser = LL1Parser(cfg=cfg, predict_sets=predict_sets, first_sets=first_sets)
30
+ errors = parser.parse(tokens)
31
+ print("Parse:", errors)
32
+
33
+ filtered = [t for t in tokens if t.type != '\n']
34
+ ast = build_ast(filtered)
35
+ print("Semantic OK")
36
+
37
+ interp = Interpreter()
38
+ interp.plant = lambda value: print(value, end="")
39
+ interp.interpret(ast)
40
+ print()
41
+ print("Done")
Backend/test_mp16.py ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Test MP16: Array print + sort with recursion using array parameter passing."""
2
+ from lexer import Lexer
3
+ from Gal_Parser import LL1Parser
4
+ from GALsemantic import build_ast
5
+ from GALinterpreter import Interpreter
6
+ from cfg import cfg, first_sets, predict_sets
7
+
8
+ code = '''
9
+ pollinate empty printArr(seed arr[], seed n, seed i) {
10
+ spring(i >= n) {
11
+ reclaim ;
12
+ }
13
+ plant("{} ", arr[i]) ;
14
+ printArr(arr, n, i + 1) ;
15
+ reclaim ;
16
+ }
17
+
18
+ pollinate empty bubblePass(seed arr[], seed n, seed i) {
19
+ spring(i >= n - 1) {
20
+ reclaim ;
21
+ }
22
+ spring(arr[i] > arr[i + 1]) {
23
+ seed temp = arr[i] ;
24
+ arr[i] = arr[i + 1] ;
25
+ arr[i + 1] = temp ;
26
+ }
27
+ bubblePass(arr, n, i + 1) ;
28
+ reclaim ;
29
+ }
30
+
31
+ pollinate empty bubbleSort(seed arr[], seed n) {
32
+ spring(n <= 1) {
33
+ reclaim ;
34
+ }
35
+ bubblePass(arr, n, 0) ;
36
+ bubbleSort(arr, n - 1) ;
37
+ reclaim ;
38
+ }
39
+
40
+ root() {
41
+ seed nums[5] ;
42
+ nums[0] = 64 ;
43
+ nums[1] = 34 ;
44
+ nums[2] = 25 ;
45
+ nums[3] = 12 ;
46
+ nums[4] = 22 ;
47
+
48
+ plant("Before sorting:") ;
49
+ printArr(nums, 5, 0) ;
50
+ plant("") ;
51
+
52
+ bubbleSort(nums, 5) ;
53
+
54
+ plant("After sorting:") ;
55
+ printArr(nums, 5, 0) ;
56
+ plant("") ;
57
+ reclaim ;
58
+ }
59
+ '''
60
+
61
+ lexer = Lexer(code)
62
+ tokens, lex_errors = lexer.make_tokens()
63
+ print("Lex:", len(tokens), "tokens, errors:", lex_errors)
64
+
65
+ parser = LL1Parser(cfg=cfg, predict_sets=predict_sets, first_sets=first_sets)
66
+ errors = parser.parse(tokens)
67
+ print("Parse:", errors)
68
+
69
+ filtered = [t for t in tokens if t.type != '\n']
70
+ ast = build_ast(filtered)
71
+ print("Semantic OK")
72
+
73
+ interp = Interpreter()
74
+ interp.plant = lambda value: print(value, end="")
75
+ interp.interpret(ast)
76
+ print()
77
+ print("Done")
Backend/test_mp16_full.py ADDED
@@ -0,0 +1,113 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Test MP16: Array Elements Print & Sort with Recursion (lex+parse+semantic only)."""
2
+ from lexer import Lexer
3
+ from Gal_Parser import LL1Parser
4
+ from GALsemantic import build_ast
5
+ from cfg import cfg, first_sets, predict_sets
6
+
7
+ code = '''
8
+ pollinate empty printArr(seed arr[], seed n, seed i) {
9
+ spring(i >= n) {
10
+ reclaim ;
11
+ }
12
+ plant("{} ", arr[i]) ;
13
+ printArr(arr, n, i + 1) ;
14
+ reclaim ;
15
+ }
16
+
17
+ pollinate empty bblPass(seed arr[], seed n, seed i) {
18
+ spring(i >= n - 1) {
19
+ reclaim ;
20
+ }
21
+ spring(arr[i] > arr[i + 1]) {
22
+ seed temp = arr[i] ;
23
+ arr[i] = arr[i + 1] ;
24
+ arr[i + 1] = temp ;
25
+ }
26
+ bblPass(arr, n, i + 1) ;
27
+ reclaim ;
28
+ }
29
+
30
+ pollinate empty sortAsc(seed arr[], seed n) {
31
+ spring(n <= 1) {
32
+ reclaim ;
33
+ }
34
+ bblPass(arr, n, 0) ;
35
+ sortAsc(arr, n - 1) ;
36
+ reclaim ;
37
+ }
38
+
39
+ pollinate empty bblPassDsc(seed arr[], seed n, seed i) {
40
+ spring(i >= n - 1) {
41
+ reclaim ;
42
+ }
43
+ spring(arr[i] < arr[i + 1]) {
44
+ seed dTemp = arr[i] ;
45
+ arr[i] = arr[i + 1] ;
46
+ arr[i + 1] = dTemp ;
47
+ }
48
+ bblPassDsc(arr, n, i + 1) ;
49
+ reclaim ;
50
+ }
51
+
52
+ pollinate empty sortDsc(seed arr[], seed n) {
53
+ spring(n <= 1) {
54
+ reclaim ;
55
+ }
56
+ bblPassDsc(arr, n, 0) ;
57
+ sortDsc(arr, n - 1) ;
58
+ reclaim ;
59
+ }
60
+
61
+ root() {
62
+ plant("Input the number of elements to be stored in the array :") ;
63
+ seed n = water(seed) ;
64
+ seed arr[20] ;
65
+
66
+ plant("Input {} elements in the array :", n) ;
67
+ cultivate(seed i = 0 ; i < n ; i++) {
68
+ plant("element - {} : ", i) ;
69
+ arr[i] = water(seed) ;
70
+ }
71
+
72
+ plant("The elements in the array are : ") ;
73
+ printArr(arr, n, 0) ;
74
+
75
+ plant("Sort Out:") ;
76
+ plant("1. Ascending") ;
77
+ plant("2. Descending") ;
78
+ plant("Enter choice (1 or 2): ") ;
79
+ seed choice = water(seed) ;
80
+
81
+ spring(choice == 1) {
82
+ sortAsc(arr, n) ;
83
+ plant("Ascending order : ") ;
84
+ printArr(arr, n, 0) ;
85
+ }
86
+ bud(choice == 2) {
87
+ sortDsc(arr, n) ;
88
+ plant("Descending order : ") ;
89
+ printArr(arr, n, 0) ;
90
+ }
91
+ wither {
92
+ plant("Invalid choice!") ;
93
+ }
94
+
95
+ reclaim ;
96
+ }
97
+ '''
98
+
99
+ # Lexer
100
+ lexer = Lexer(code)
101
+ tokens, lex_errors = lexer.make_tokens()
102
+ print("Lex OK:", len(tokens), "tokens, errors:", lex_errors)
103
+
104
+ # Parser
105
+ parser = LL1Parser(cfg=cfg, predict_sets=predict_sets, first_sets=first_sets)
106
+ errors = parser.parse(tokens)
107
+ print("Parse:", errors)
108
+
109
+ # Semantic + AST
110
+ filtered = [t for t in tokens if t.type != '\n']
111
+ ast = build_ast(filtered)
112
+ print("Semantic + AST OK")
113
+ print("All stages passed!")