diff --git a/server/src/parser/tcl.lark b/server/src/parser/tcl.lark index 2bea195..83734cd 100644 --- a/server/src/parser/tcl.lark +++ b/server/src/parser/tcl.lark @@ -1,138 +1,250 @@ -start: script +// tcl.lark +start: script script: statement* -statement: declaracion_funcion modulo_ppal +statement: function_declaration + | top_level -declaracion_funcion: "proc" IDENTIFICADOR "{" args_funcion "}" "{" cuerpo_funcion "}" declaracion_funcion | -args_funcion: "{" IDENTIFICADOR "}" args_funcion | +// --- Function declarations (zero or more) --- +function_declaration: ("proc" IDENTIFIER "{" function_args "}" "{" function_body "}")* -cuerpo_funcion: declaracion cuerpo_funcion | puts cuerpo_funcion | gets ";" cuerpo_funcion | if_funcion cuerpo_funcion - | for_funcion cuerpo_funcion | while_funcion cuerpo_funcion | switch_funcion cuerpo_funcion - | r_return cuerpo_funcion | agrup ";" cuerpo_funcion | +// --- Function arguments (0..n blocks) --- +function_args: ("{" IDENTIFIER "}")* -if_funcion: inicio_if cuerpo_funcion "}" elseif_funcion -elseif_funcion: inicio_elseif cuerpo_funcion "}" elseif_funcion | else_funcion -else_funcion: inicio_else cuerpo_funcion "}" | +// --- Function body: zero or more statements --- +function_body: (assignment_statement + | print_statement + | input_statement ";" + | if_statement + | for_statement + | while_statement + | switch_statement + | return_statement + | grouping ";" + )* -switch_funcion: inicio_switch case_funcion "}" -case_funcion: inicio_case cuerpo_funcion "}" case2_funcion -case2_funcion: inicio_case cuerpo_funcion "}" case2_funcion | default_funcion -default_funcion: inicio_default cuerpo_funcion "}" | +// --- If / elseif / else in functions --- +if_statement: if_header function_body "}" elseif_clause -for_funcion: inicio_for cuerpo_loop_func "}" -while_funcion: inicio_while cuerpo_loop_func "}" +elseif_clause: elseif_header function_body "}" elseif_clause + | else_clause -cuerpo_loop_func: r_break cuerpo_loop_func | r_continue cuerpo_loop_func | declaracion cuerpo_loop_func - | gets ";" cuerpo_loop_func | puts cuerpo_loop_func | r_return cuerpo_loop_func - | if_loop_func cuerpo_loop_func | switch_loop_func cuerpo_loop_func | for_funcion cuerpo_loop_func - | while_funcion cuerpo_loop_func | agrup ";" cuerpo_loop_func | +else_clause: else_header function_body "}" + | /* empty */ -if_loop_func: inicio_if cuerpo_loop_func "}" elseif_loop_func -elseif_loop_func: inicio_elseif cuerpo_loop_func "}" elseif_loop_func | else_loop_func -else_loop_func: inicio_else cuerpo_loop_func "}" | +// --- Switch in functions --- +switch_statement: switch_header case_clause "}" -switch_loop_func: inicio_switch case_loop_func "}" -case_loop_func: inicio_case cuerpo_loop_func "}" case2_loop_func -case2_loop_func: inicio_case cuerpo_loop_func "}" case2_loop_func | default_loop_func -default_loop_func: inicio_default cuerpo_loop_func "}" | +case_clause: case_header function_body "}" case_clauses -modulo_ppal: declaracion modulo_ppal | r_for modulo_ppal | gets ";" modulo_ppal | r_if modulo_ppal - | puts modulo_ppal | r_while modulo_ppal | r_switch modulo_ppal | agrup ";" modulo_ppal | +case_clauses: case_header function_body "}" case_clauses + | default_clause -r_if: inicio_if cuerpo_inst "}" elseif -elseif: inicio_elseif cuerpo_inst "}" elseif | r_else -r_else: inicio_else cuerpo_inst "}" | +default_clause: default_header function_body "}" + | /* empty */ -r_switch: inicio_switch r_case "}" -r_case: inicio_case cuerpo_inst "}" case2 -case2: inicio_case cuerpo_inst "}" case2 | r_default -r_default: inicio_default cuerpo_inst "}" | +// --- For / While in functions --- +for_statement: for_header loop_body_in_function "}" +while_statement: while_header loop_body_in_function "}" -cuerpo_inst: declaracion cuerpo_inst | r_for cuerpo_inst | gets ";" cuerpo_inst | r_if cuerpo_inst - | puts cuerpo_inst | r_while cuerpo_inst | r_switch cuerpo_inst | agrup ";" cuerpo_inst | - -r_for: inicio_for cuerpo_loop "}" -r_while: inicio_while cuerpo_loop "}" +loop_body_in_function: (break_statement + | continue_statement + | assignment_statement + | input_statement ";" + | print_statement + | return_statement + | if_loop_statement + | switch_loop_statement + | for_statement + | while_statement + | grouping ";" + )* -cuerpo_loop: declaracion cuerpo_loop | r_for cuerpo_loop | gets ";" cuerpo_loop | if_loop cuerpo_loop - | puts cuerpo_loop | r_while cuerpo_loop | switch_loop cuerpo_loop | r_break cuerpo_loop - | r_continue cuerpo_loop | agrup ";" cuerpo_loop | - -if_loop: inicio_if cuerpo_loop "}" elseif_loop -elseif_loop: inicio_elseif cuerpo_loop "}" elseif_loop | else_loop -else_loop: inicio_else cuerpo_loop "}" | +if_loop_statement: if_header loop_body_in_function "}" elseif_loop_clause -switch_loop: inicio_switch case_loop "}" -case_loop: inicio_case cuerpo_loop "}" case2_loop -case2_loop: inicio_case cuerpo_loop "}" case2_loop | default_loop -default_loop: inicio_default cuerpo_loop "}" | +elseif_loop_clause: elseif_header loop_body_in_function "}" elseif_loop_clause + | else_loop_clause -puts: "puts" asignacion ";" -gets: "gets" "stdin" -declaracion: "set" IDENTIFICADOR indice asignacion ";" +else_loop_clause: else_header loop_body_in_function "}" + | /* empty */ -agrup: "[" aux_agrup -aux_agrup: expr "]" | IDENTIFICADOR param_func "]" | gets "]" | "array" aux_array -aux_array: "size" IDENTIFICADOR "]" | "exists" IDENTIFICADOR "]" +switch_loop_statement: switch_header case_loop_clause "}" -param_func: "{" aux_param | -aux_param: asignacion "}" param_func | expr "}" param_func +case_loop_clause: case_header loop_body_in_function "}" case_loop_clauses -asignacion: valor | "$" IDENTIFICADOR indice | agrup +case_loop_clauses: case_header loop_body_in_function "}" case_loop_clauses + | default_loop_clause -indice: "(" val_indice ")" | -val_indice: valor | agrup | "$" IDENTIFICADOR indice +default_loop_clause: default_header loop_body_in_function "}" + | /* empty */ -valor: VALOR_STRING | VALOR_ENTERO | VALOR_DOUBLE +// --- Top-level (module) statements (zero or more) --- +top_level: (assignment_statement + | for_main + | input_statement ";" + | if_main + | print_statement + | while_main + | switch_main + | grouping ";" + )* -incremento: VALOR_ENTERO | +// --- If / Else at top level --- +if_main: if_header main_body "}" elseif_main_clause -r_break: "break" ";" -r_continue: "continue" ";" -r_return: "return" value_return ";" -value_return: asignacion | +elseif_main_clause: elseif_header main_body "}" elseif_main_clause + | else_main_clause -expr: "expr" "{" expresion "}" -asig_for: VALOR_ENTERO | "$" IDENTIFICADOR indice | expr +else_main_clause: else_header main_body "}" + | /* empty */ -inicio_if: "if" "{" expresion "}" "then" "{" -inicio_elseif: "elseif" "{" expresion "}" "then" "{" -inicio_else: "else" "{" -inicio_switch: "switch" "$" IDENTIFICADOR indice "{" -inicio_case: "case" VALOR_ENTERO "{" -inicio_default: "default" "{" +main_body: (assignment_statement + | for_main + | input_statement ";" + | if_main + | print_statement + | while_main + | switch_main + | grouping ";" + )* -inicio_for: "for" "{" dec_for "}" "{" expresion "}" "{" "incr" IDENTIFICADOR incremento "}" "{" -dec_for: "set" IDENTIFICADOR asig_for +// --- Switch at top level --- +switch_main: switch_header main_case_clause "}" -inicio_while : "while" "{" expresion "}" "{" +main_case_clause: case_header main_body "}" main_case_clauses -expresion: exp_or -exp_or: exp_or "||" exp_and | exp_and -exp_and: exp_and "&&" exp_ig | exp_ig -exp_ig: exp_ig op_ig exp_rel | exp_rel -exp_rel: exp_rel op_rel exp_add | exp_add -exp_add: exp_add op_add exp_mul | exp_mul -exp_mul: exp_mul op_mul exp_pot | exp_pot -exp_pot: exp_pot "**" exp_una | exp_una -exp_una: op_una exp_una | term -term: "$" IDENTIFICADOR indice | agrup | valor | "(" exp_or ")" +main_case_clauses: case_header main_body "}" main_case_clauses + | default_main_clause -op_ig: "eq" | "==" | "ne" | "!=" -op_rel: ">" | "<" | ">=" | "<=" -op_add: "+" | "-" -op_mul: "*" | "/" | "%" -op_una: "-" | "!" +default_main_clause: default_header main_body "}" + | /* empty */ +// --- For / While at top level --- +for_main: for_header main_loop_body "}" +while_main: while_header main_loop_body "}" -IDENTIFICADOR: /[a-zA-Z_][a-zA-Z0-9_]*/ -VALOR_ENTERO: /'-'?[0-9]+/ -VALOR_DOUBLE: /[0-9]+ '.' [0-9]+/ -VALOR_STRING: /'"' ~[\r\n"]* '"'/ +main_loop_body: (assignment_statement + | for_main + | input_statement ";" + | if_loop_main + | print_statement + | while_main + | switch_loop_main + | break_statement + | continue_statement + | grouping ";" + )* + +if_loop_main: if_header main_loop_body "}" elseif_loop_main + +elseif_loop_main: elseif_header main_loop_body "}" elseif_loop_main + | else_loop_main + +else_loop_main: else_header main_loop_body "}" + | /* empty */ + +switch_loop_main: switch_header case_loop_main "}" + +case_loop_main: case_header main_loop_body "}" case_loop_main_clauses + +case_loop_main_clauses: case_header main_loop_body "}" case_loop_main_clauses + | default_loop_main + +default_loop_main: default_header main_loop_body "}" + | /* empty */ + +// --- Primitive statements --- +print_statement: "puts" assignment ";" +input_statement: "gets" "stdin" +assignment_statement: "set" IDENTIFIER index access_value ";" + +grouping: "[" grouping_aux "]" +grouping_aux: expression + | IDENTIFIER function_param + | input_statement + | "array" array_aux + +array_aux: "size" IDENTIFIER + | "exists" IDENTIFIER + +function_param: "{" param_aux "}" +param_aux: assignment_value + | expression + +assignment_value: value + | "$" IDENTIFIER index + | grouping + +index: "(" index_value ")" +index_value: value + | grouping + | "$" IDENTIFIER index + +value: STRING_LITERAL + | INT + | FLOAT + +increment: INT? + +break_statement: "break" ";" +continue_statement: "continue" ";" +return_statement: "return" return_value ";" +return_value: assignment_value? + +expr_command: "expr" "{" expression "}" +for_init: INT + | "$" IDENTIFIER index + | expr_command + +// --- Headers for control structures --- +if_header: "if" "{" expression "}" "then" "{" +elseif_header: "elseif" "{" expression "}" "then" "{" +else_header: "else" "{" +switch_header: "switch" "$" IDENTIFIER index "{" +case_header: "case" INT "{" +default_header: "default" "{" +for_header: "for" "{" for_declaration "}" "{" expression "}" "{" "incr" IDENTIFIER increment "}" "{" +for_declaration: "set" IDENTIFIER for_init +while_header: "while" "{" expression "}" "{" + +// --- Expression grammar --- +expression: or_expression +or_expression: or_expression "||" and_expression + | and_expression +and_expression: and_expression "&&" equality_expression + | equality_expression +equality_expression: equality_expression eq_ops relational_expression + | relational_expression +relational_expression: relational_expression rel_ops additive_expression + | additive_expression +additive_expression: additive_expression add_ops multiplicative_expression + | multiplicative_expression +multiplicative_expression: multiplicative_expression mul_ops power_expression + | power_expression +power_expression: power_expression "**" unary_expression + | unary_expression +unary_expression: unary_ops unary_expression + | term +term: "$" IDENTIFIER index + | grouping + | value + | "(" or_expression ")" + +eq_ops: "eq" | "==" | "ne" | "!=" +rel_ops: ">" | "<" | ">=" | "<=" +add_ops: "+" | "-" +mul_ops: "*" | "/" | "%" +unary_ops: "-" | "!" + +// --- Terminals --- +IDENTIFIER: /[a-zA-Z_][a-zA-Z0-9_]*/ +INT: /-?[0-9]+/ +FLOAT: /[0-9]+\.[0-9]+/ +STRING_LITERAL: /"([^"\\]|\\.)*"/ COMMENT: /#[^\r\n]*/ -WS: /[ \t]+/ -NEWLINE: /\r?\n/ -%ignore WS -%ignore COMMENT \ No newline at end of file + +%ignore /[ \t]+/ // spaces & tabs +%ignore COMMENT +%ignore _NL \ No newline at end of file