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:
(* 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:
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.