2014-11-06 3 views
1

Я продолжаю работать над своим JavaCC grammar для ECMAScript 5.1. На самом деле все идет хорошо, я думаю, что теперь я рассмотрел большинство выражений.Как реализовать правило JavaScript/ECMAScript «Нет LineTerminator здесь» в JavaCC?

У меня есть два вопроса, оба из которых связаны с автоматической точкой с запятой (§7.9.1). Это одна из них.

Спецификация определяет следующую продукцию:

PostfixExpression : 
    LeftHandSideExpression 
    LeftHandSideExpression [no LineTerminator here] ++ 
    LeftHandSideExpression [no LineTerminator here] -- 

Как я могу реализовать надежные «не КонцаСтроки» проверить?

Для записи моего LINE_TERMINATOR на данный момент что-то вроде:

SPECIAL_TOKEN : 
{ 
    <LINE_TERMINATOR: <LF> | <CR> | <LS> | <PS> > 
| < #LF: "\n" > /* Line Feed */ 
| < #CR: "\r" > /* Carriage Return */ 
| < #LS: "\u2028" > /* Line separator */ 
| < #PS: "\u2029" > /* Paragraph separator */ 
} 

Я прочитал о lexical states, но я не уверен, что это правильное направление. Я проверил несколько других грамматик JavaScript, которые я нашел, но не нашел там подобных правил. (Я действительно чувствую себя total cargo culter, когда я пытаюсь что-то обгонять из этих грамматик.)

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

ответ

3

Я думаю, что для «ограниченных производств» вы можете сделать это

void PostfixExpression() : 
{} { 
    LeftHandSideExpression() 
    (
     LOOKAHEAD("++", {getToken(0).beginLine == getToken(1).beginLine}) 
     "++" 
    | 
     LOOKAHEAD("--", {getToken(0).beginLine == getToken(1).beginLine}) 
     "--" 
    | 
     {} 
    ) 
} 
+0

Хм, очень интересная идея. Я попробую. – lexicore

+0

Или, может быть, 'getToken (0) .endLine == getToken (1) .beginLine'. –

1

Update Как Гюнтера указано, мое первоначальное решение было неправильным из-за этого пункта в 7.4 спецификации:

Комментарии ведут себя как пробелы и отбрасываются, за исключением того, что если MultiLineComment содержит символ терминатора строки, то весь комментарий считается линейным тестером для целей синтаксической грамматики.

Я отправляю исправление, но оставляю свое первоначальное решение в конце вопроса.

Исправленного решение

Основная идея, предложенный Теодор Norvell является использование семантического предпросмотра. Однако я решил реализовать более безопасную проверку:

public static boolean precededByLineTerminator(Token token) { 
    for (Token specialToken = token.specialToken; specialToken != null; specialToken = specialToken.specialToken) { 
     if (specialToken.kind == EcmaScriptParserConstants.LINE_TERMINATOR) { 
      return true; 
     } else if (specialToken.kind == EcmaScriptParserConstants.MULTI_LINE_COMMENT) { 
      final String image = specialToken.image; 
      if (StringUtils.containsAny(image, (char)0x000A, (char)0x000D, (char)0x2028, 
        (char)0x2029)) { 
       return true; 
      } 
     } 
    } 
    return false; 
} 

И грамматика:

expression = LeftHandSideExpression() 
(
    LOOKAHEAD (<INCR>, { !TokenUtils.precededByLineTerminator(getToken(1))}) 
    <INCR> 
    { 
     return expression.postIncr(); 
    } 
| LOOKAHEAD (<DECR>, { !TokenUtils.precededByLineTerminator(getToken(1))}) 
    <DECR> 
    { 
     return expression.postDecr(); 
    } 
) ? 
{ 
    return expression; 
} 

Так ++ или -- считается здесь тогда и только тогда они не предшествует линию терминатор.


Оригинальное решение

Это не, как я наконец-то решил.

Основная идея, предложенная Теодором Норвелом, заключается в использовании семантического взгляда.Однако я решил реализовать более безопасную проверку:

public static boolean precededBySpecialTokenOfKind(Token token, int kind) { 
    for (Token specialToken = token.specialToken; specialToken != null; specialToken = specialToken.specialToken) { 
     if (specialToken.kind == kind) { 
      return true; 
     } 
    } 
    return false; 
} 

И грамматика:

expression = LeftHandSideExpression() 
(
    LOOKAHEAD (<INCR>, { !TokenUtils.precededBySpecialTokenOfKind(getToken(1), LINE_TERMINATOR)}) 
    <INCR> 
    { 
     return expression.postIncr(); 
    } 
| LOOKAHEAD (<DECR>, { !TokenUtils.precededBySpecialTokenOfKind(getToken(1), LINE_TERMINATOR)}) 
    <DECR> 
    { 
     return expression.postDecr(); 
    } 
) ? 
{ 
    return expression; 
} 

Так ++ или -- считается здесь тогда и только тогда они не предшествует линию терминатор.

+0

Он также обрабатывает случай, когда терминатор линии похоронен в MultiLineComment? ECMA-262 указывает, что в этом случае оно также запрещено. – Gunther

+0

@Gunther Хороший вопрос. Нет, наверное, нет. Я проверю. – lexicore

+0

Я предполагаю, что первоначальное предложение охватило бы этот случай, не так ли? Некоторое время назад я построил нечто подобное, добавив поддержку автоматической вставки точки с запятой в [генератор парсера REx] (http://bottlecaps.de/rex). Вы можете найти его, посмотрев метод followLineTerminator() в синтаксическом анализаторе, сгенерированном из [EcmaScript.ebnf] (http://bottlecaps.de/rex/EcmaScript.ebnf) с включенным '-asi' – Gunther

 Смежные вопросы

  • Нет связанных вопросов^_^