Разбор основных скриптовый язык


Я работаю на написание скриптовый язык с ANTLR и C++. Это мой первый переезд из ANTLR грамматики в языке C++ API, поэтому я хотел бы знать, если это будет хороший способ структурировать грамматику (позже я буду добавлять парсер дерево или дерево, хотя правила переписывания).

grammar dyst;

options
{
  language = C;
  output = AST;
  ASTLabelType=pANTLR3_BASE_TREE;
}

program : statement*;

statement : stopUsingNamespaceStm|usingNamespaceStm|namespaceDefineStm|functionStm|defineStm|assignStm|funcDefineStm|ifStm|whileStm|returnStm|breakStm|eventDefStm|eventCallStm|linkStm|classDefStm|exitStm|importStm|importOnceStm|directive;

namespaceDefineStm : 'namespace' ident '{' statement* '}';

usingNamespaceStm : 'using' 'namespace' ident (',' ident)* ';';

stopUsingNamespaceStm : 'stop' 'using' 'namespace' ident (',' ident)* ';';

directive : '@' directiveId argList? ';';

directiveId : ID (':' ID)*;

importOnceStm : 'import_once' expression ';';

importStm : 'import' expression ';';

exitStm : 'exit' expression? ';';

classDefStm : 'class' ident ('extends' ident (',' ident)*)? '{' (classSection|funcDefineStm|defineStm|eventDefStm)* '}';

classSection : ('public'|'private'|'protected') ':';

linkStm : 'link' ident 'to' ident (',' ident)* ';';

eventCallStm : 'call' ident (',' argList)? ';';

eventDefStm : 'event' ident '(' paramList? ')' ';';

returnStm : 'return' expression ';';

breakStm : 'break' int ';';

ifStm : 'if' '(' expression ')' '{' statement* '}';

whileStm : 'while' '(' expression ')' '{' statement* '}';

defineStm : 'global'? 'def' ident ('=' expression)? ';';

assignStm : ident '=' expression ';';

funcDefineStm : 'function' ident '(' paramList? ')' ('handles' ident (',' ident)*)? '{' statement* '}';

paramList : param (',' param)?;

param : ident ('=' expression)?;

functionStm : functionCall ';';

functionCall : ident '(' argList? ')';

argList : expression (',' expression)*;

//Expressions!
term : functionCall|value|'(' expression ')';

logic_not : ('!')* term;

bit_not : ('~')* logic_not;

urnary : '-'* bit_not;

mult : urnary (('*'|'/'|'%') urnary)*;

add : mult ('+' mult)*;

relation : add (('<='|'>='|'<'|'>') add)*;

equality : relation (('=='|'!=') relation)*;

bit_and : equality ('&' equality)*;

bit_xor : bit_and ('^' bit_and)*;

bit_or : bit_xor ('|' bit_xor)*;

logic_and : bit_or ('&&' bit_or)*;

logic_or : logic_and ('||' logic_and)*;

expression : logic_or;


value : ident|float|int|string|boolean|newObject|anonFunc|null_val;

anonFunc : 'function' '(' paramList? ')' '{' statement* '}';

newObject : 'new' ident ('(' argList ')')?;

ident : ID (('.'|'::') ID)*;

float : FLOAT;

int : INTEGER;

string : STRING_DOUBLE|STRING_SINGLE;

boolean : BOOL;

null_val : NULL_VAL;



FLOAT : INTEGER '.' INTEGER;
INTEGER : DIGIT+;

BOOL : 'true'|'false';

NULL_VAL : 'null'|'NULL';

STRING_DOUBLE : '"' .* '"';
STRING_SINGLE : '\'' .* '\'';

ID : (LETTER|'_') (LETTER|DIGIT|'_')*;

fragment DIGIT : '0'..'9';
fragment LETTER : 'a'..'z'|'A'..'Z';

NEWLINE : ('\n'|'\r'|'\t'|' ')+ {$channel = HIDDEN;};
COMMENT : '#' .* '\r'? '\n' {$channel = HIDDEN;};
MULTI_COMMENT : '/-' .* '-/' {$channel = HIDDEN;};

Если вы задаетесь вопросом о том, что я, используя это, вы можете взглянуть здесь.



473
8
задан 27 марта 2011 в 03:03 Источник Поделиться
Комментарии
1 ответ


  1. Сама грамматика довольно нечитабельный "как есть". Правило как:

    statement : stopUsingNamespaceStm|usingNamespaceStm|namespaceDefineStm|functionStm|defineStm|assignStm|funcDefineStm|ifStm|whileStm|returnStm|breakStm|eventDefStm|eventCallStm|linkStm|classDefStm|exitStm|importStm|importOnceStm|directive;

    будет гораздо более читабельным, когда объявляется такой:

    statement 
    : stopUsingNamespaceStm
    | usingNamespaceStm
    | namespaceDefineStm
    | functionStm
    | defineStm
    | assignStm
    | funcDefineStm
    | ifStm
    | whileStm
    | returnStm
    | breakStm
    | eventDefStm
    | eventCallStm
    | linkStm
    | classDefStm
    | exitStm
    | importStm
    | importOnceStm
    | directive
    ;

  2. Вы хотите, чтобы явно заканчивается точкой вашего парсера, правило программы, на конец файла маркер, в противном случае парсер может перестать разбора преждевременно. С ВФ, можно заставить парсер читать весь маркеров потока.

    program 
    : statement* EOF
    ;

  3. Сделать явные маркеры для ключевых слов, не смешивать их внутри правил парсера.

    Вместо:

    importStm 
    : 'import' expression ';'
    ;

    это лучше делать:

    importStm 
    : Import expression ';'
    ;

    Import
    : 'import'
    ;

    Это облегчит вашу жизнь на более позднем этапе (ходячее дерево). Без явного анализатор маркеров, непонятно для вас при отладке, что маркеры есть на самом деле в вашем дереве.


  4. Правила лексер:

    STRING_DOUBLE : '"' .* '"';
    STRING_SINGLE : '\'' .* '\'';

    не может содержать двойные или одинарные кавычки. Таким образом, невозможно иметь строковый литерал с двойной и одинарной кавычки в нем.

    Лучше сделать что-то вроде этого:

    STRING_DOUBLE 
    : '"' ('\\' ('\\' | '"') | ~('\\' | '"'))* '"'
    ;

    что позволит в двойные кавычки строка содержит двойные кавычки, а также.


Это все, что я увидел на первый взгляд. Я не смотрела очень внимательно, так что может быть больше, что может быть улучшено.

7
ответ дан 31 марта 2011 в 01:03 Источник Поделиться