2016-09-11 8 views
0

Я работаю на построение лексического анализатора для вымышленного языка XML-стиля, и я в настоящее время пытаюсь включить следующую лексическую спецификацию в Java код:Использования Regex в лексическом анализаторе (Java)

Name -> Initial Other* 
Initial -> Letter | _ | : 
Other -> Initial | Digit | - | . 
String -> " (Char | ')* " | '(Char | ")* ' 
Data -> Char+ 
Char -> Ordinary | Special | Reference 
Ordinary -> NOT (< | > | " | ' | &) 
Special -> &lt; | &gt; | &quot; | &apos; | &amp; 
Reference -> &#(Digit)+; | &#x(Digit|a...f|A...F)+; 
Letter -> a...z | A...Z 
Digit -> 0...9 

I «Нет эксперта, но я знаю, что для этого нужно использовать регулярные выражения. Так что мой Tokenizer теперь выглядит следующим образом:

public Tokenizer(String str) { 
    this.tokenContents = new ArrayList<TokenContent>(); 
    this.str = str; 

    // Name = Initial Other* 
    String initial = "[a-zA-Z] | _ | :"; 
    String other = initial + " | [0-9] | - | \\."; 
    String name = initial + "(" + other + ")*"; 
    tokenContents.add(new TokenContent(Pattern.compile(name), TokenType.NAME)); 
    // String = " " (Char | ')* " | ' (Char | ")* ' 
    String ordinary = "(?!(< | > | \" | ' | &))"; 
    String special = "&lt; | &gt; | &quot; | &apos; | &amp;"; 
    String reference = "&#[0-9]+; | &#x([0-9] | [a-fA-F])+;"; 
    String character = ordinary + " | " + special + " | " + reference; 
    String string = "\"(" + character + " | " + "')* \" | ' (\"" + character + " | " + "\")* '"; 
    tokenContents.add(new TokenContent(Pattern.compile(string), TokenType.STRING)); 
    // Data = Char+ 
    String data = character + "+"; 
    tokenContents.add(new TokenContent(Pattern.compile(data), TokenType.DATA)); 
    // The symbol < 
    tokenContents.add(new TokenContent(Pattern.compile("<"), TokenType.LEFT_TAG)); 
    // The symbol > 
    tokenContents.add(new TokenContent(Pattern.compile(">"), TokenType.RIGHT_TAG)); 
    // The symbol </ 
    tokenContents.add(new TokenContent(Pattern.compile("</"), TokenType.LEFT_TAG_SLASH)); 
    // The symbol /> 
    tokenContents.add(new TokenContent(Pattern.compile("/>"), TokenType.RIGHT_TAG_SLASH)); 
    // The symbol = 
    tokenContents.add(new TokenContent(Pattern.compile("="), TokenType.EQUALS));  
} 

Для простоты, вы можете видеть, я мое регулярное модульное выражение в соответствии с приведенной выше спецификацией. Однако, после нескольких тестовых примеров запуска lexer на примерном входном файле, я получаю ошибки синтаксического анализа. Я считаю, что это могут быть мои регулярные выражения, поэтому Мне бы хотелось, чтобы некоторые предложения о том, как я могу правильно перевести приведенную выше спецификацию в код и исправить мой токенизатор.

Мои жетоны Name, String, Data, <, >, </, /> и =. Все они указаны в классе enum, который здесь не отображается. Пример входного файла:

<recipe name="bread" prep_time="5 mins" cook_time="3 hours"> 
    <title>Basic bread</title> 
    <ingredient amount="3" unit="cups">Flour</ingredient> 
    <ingredient amount="0.25" unit="ounce">Yeast</ingredient> 
    <ingredient amount="1.5" unit="cups" state="warm">Water</ingredient> 
    <ingredient amount="1" unit="teaspoon">Salt</ingredient> 
    <instructions> 
    <step>Mix all ingredients together.</step> 
    <step>Knead thoroughly.</step> 
    <step>Cover with a cloth, and leave for one hour in warm room.</step> 
    <step>Knead again.</step> 
    <step>Place in a bread baking tin.</step> 
    <step>Cover with a cloth, and leave for one hour in warm room.</step> 
    <step>Bake in the oven at 350&#x00B0; F for 30 minutes.</step> 
    </instructions> 
</recipe> 

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

+0

Пожалуйста, разместите несколько тестовых примеров, которые вы пытаетесь проанализировать. – 11thdimension

+0

Добавлен пример входного файла. Благодаря! –

+0

Вы не можете использовать простой синтаксический анализ XML? – 11thdimension

ответ

0
String ordinary = "(?!(< | > | \" | ' | &))"; 

Этот шаблон не будет делать то, что вы хотите. Lookahead - это функция, которая используется для сопоставления шаблонов, только если она соблюдена (или, в случае отрицательного обзора, как вы здесь используете, не) по определенному шаблону. Сам взгляд не потребляет никакого ввода.

Возьмем, к примеру, рисунок [a-z]+(?=\s). Это будет соответствовать последовательности букв, за которыми следует пробел, но не сам пробел. Таким образом, шаблон будет соответствовать «abc» в «abc def» и не будет соответствовать чему-либо в «abc_def». Но в любом случае совпадение не включало бы пространство. Если вы используете это в токенизаторе (который также имеет правило для пробелов), это приведет к тому, что «abc def» будет обозначаться как «abc», «», «def», «», а не «abc», «def ». Так что это полезно.

Но в вашем случае ваш весь узор выглядит. Поэтому, если вы подменили что-то, используя ваше правило, результат будет больше похож на «", "", ... ad infinitum. Это менее полезно.

Что вы хотите - это класс отрицательных символов, который создается с помощью [^...], где ... - это список символов или диапазонов символов, которые вы используете с обычным классом символов. Он совпадает с одним символом, если этот символ не указан в указанном списке. Используя это, ваше регулярное выражение будет выглядеть так:

String ordinary = "[^<>\"'&]"; 

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

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