.. raw:: html
Definición de gramática
=======================
Este capítulo dará algunas definiciones gramaticales relacionadas con
Berry. Usamos **Extended Backus Normal Form** (EBNF) para definir o
expresar la gramática. No usamos la gramática EBNF estricta para
definir, pero hicimos muchas simplificaciones, pero estas
simplificaciones no afectarán la comprensión de la gramática por parte
de los lectores.
La definición EBNF de la gramática del lenguaje Berry es la siguiente:
.. code::
(* program define *)
program = block;
(* block define *)
block = {statement};
(* statement define *)
statement = class_stmt | func_stmt | var_stmt | if_stmt | while_stmt |
for_stmt | break_stmt | return_stmt | expr_stmt | import_stmt |
try_stmt | throw_stmt | ';';
if_stmt = 'if' expr block {'elif' expr block} ['else' block] 'end';
while_stmt = 'while' expr block 'end';
for_stmt = 'for' ID ':' expr block 'end';
break_stmt = 'break' | 'continue';
return_stmt = 'return' [expr];
(* function define statement *)
func_stmt = 'def' ID func_body;
func_body = '(' [arg_field {',' arg_field}] ')' block 'end';
arg_field = ['*'] ID;
(* class define statement *)
class_stmt = 'class' ID [':' ID] class_block 'end';
class_block = {'var' ID {',' ID} | 'static' ['var'] ID ['=' expr] {',' ID ['=' expr] } | 'static' func_stmt | func_stmt};
import_stmt = 'import' (ID (['as' ID] | {',' ID}) | STRING 'as' ID);
(* exceptional handling statement *)
try_stmt = 'try' block except_block {except_block} 'end';
except_block = except_stmt block;
except_stmt = 'except' (expr {',' expr} | '..') ['as' ID [',' ID]];
throw_stmt = 'raise' expr [',' expr];
(* variable define statement *)
var_stmt = 'var' ID ['=' expr] {',' ID ['=' expr]};
(* expression define *)
expr_stmt = expr [assign_op expr];
expr = suffix_expr | unop expr | expr binop expr | range_expr | cond_expr;
cond_expr = expr '?' expr ':' expr; (* conditional expression *)
assign_op = '=' | '+=' | '-=' | '*=' | '/=' |
'%=' | '&=' | '|=' | '^=' | '<<=' | '>>=';
binop = '<' | '<=' | '==' | '!=' | '>' | '>=' | '||' | '&&' |
'<<' | '>>' | '&' | '|' | '^' | '+' | '-' | '*' | '/' | '%';
range_expr = expr '..' [expr]
unop = '-' | '!' | '~';
suffix_expr = primary_expr {call_expr | ('.' ID) | '[' expr ']'};
primary_expr = '(' expr ')' | simple_expr | list_expr | map_expr | anon_func | lambda_expr;
simple_expr = INTEGER | REAL | STRING | ID | 'true' | 'false' | 'nil';
call_expr = '(' [expr {',' expr}] ')';
list_expr = '[' {expr ','} [expr] ']';
map_expr = '{' {expr ':' expr ','} [expr ':' expr] '}';
anon_func = 'def' func_body;
(* anonymous function *)
lambda_expr = '/' [arg_field {',' arg_field}] | {arg_field}] '->' expr;
El formato EBNF estándar se puede encontrar en materiales relacionados.
Aquí hay una explicación de los detalles que necesitan atención al leer
la gramática anterior. Los símbolos que han aparecido a la izquierda del
signo igual son símbolos no terminales, y los demás son símbolos
terminales. El terminador encerrado entre comillas ``'`` es una cadena
fija, que suele ser una palabra clave u operador de idioma. Hay varios
terminadores que son inconvenientes para describir directamente en EBNF:
``INTEGER`` representa el valor nominal del entero; ``REAL`` representa
el valor nominal del número real; ``STRING`` representa el valor literal
de cadena; ``ID`` representa el identificador. Estos terminadores se
pueden definir mediante expresiones regulares:
- ``ENTERO``: ``0x[a-fA-F0-9]+|\d+``.
- ``REAL``: ``(\d+\.?|\.\d)\d*([eE][+-]?\d+)?``.
- ``CADENA``: ``"(\\.|[^"])*"|'(\\.|[^'])*'``.
- ``ID``: ``[_a-zA-Z]\w*``
Los símbolos que aparecen secuencialmente en el EBNF estándar están
separados por comas. Por intuición, uso espacios para implementar la
función de coma. El símbolo de barra vertical “\|” se pronuncia como
“o”, significa que los patrones izquierdo y derecho solo pueden
coincidir con uno de ellos, o tiene la prioridad más baja. Por ejemplo,
la gramática *a* 0 *a* 1 \|\ *a* 2 significa la fórmula correspondiente
*a* 0 *a* 1 o la combinación *a* 2 . Los corchetes indican que la
subexpresión dentro de los paréntesis coincide 0 o 1 veces, las llaves
indican que la subexpresión interna coincide 0 o más veces, y los
paréntesis solo tienen la función de tomar la subexpresión interna como
un todo.
La siguiente es la definición de gramática JSON admitida por el módulo
JSON en la biblioteca estándar de Berry. El uso de EBNF aún cumple con
las convenciones anteriores:
.. code::
json = value;
value = object | array |
string | number | 'true' | 'false' | 'null';
object = '{' [ string ':' value ] { ',' string ':' value } '}';
array = '[' [json] { ',' json } ']';
Los símbolos no terminales ``cadena`` y ``número`` también se pueden
definir mediante expresiones regulares. http://www.json.org proporciona
la gramática estándar de JSON, que también incluye las definiciones de
``cadena`` y ``número``. El soporte para números de la biblioteca Berry
JSON es diferente del estándar. Los números JSON estándar deben comenzar
con “-” o el número “0-9”, mientras que la biblioteca Berry JSON también
acepta números que comienzan con un punto decimal.