add array passing to function
Browse files- Backend/GALinterpreter.py +4 -2
- Backend/GALsemantic.py +51 -3
- Backend/cfg.py +6 -1
- Backend/icg.py +15 -5
- Backend/test_array_param.py +45 -0
- Backend/test_curly_init.py +41 -0
- Backend/test_mp16.py +77 -0
- Backend/test_mp16_full.py +113 -0
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 |
-
|
|
|
|
| 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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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)
|
| 512 |
"""<parameters> → <param> <param_next> | λ"""
|
| 513 |
-
params
|
| 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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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!")
|