【问题标题】:Do not match if a char is between quotation marks(AKA has a programming string pattern)如果字符在引号之间,则不匹配(AKA 具有编程字符串模式)
【发布时间】:2014-05-09 08:19:06
【问题描述】:

我被分配为Basic programming language 编写编译器。基本上,代码用新行或: 标记分隔。例如,遵循代码是有效的。
型号#1

 10 PRINT "Hello World 1" : PRINT "Hello World 2"

型号#2

 10 PRINT "Hello World 1"
 20 PRINT "Hello World 2"

你可以测试那些here
在我的编译器中解析代码之前,我需要做的第一件事是拆分代码。
我已经按行拆分代码,但我坚持要找到一个正则表达式来拆分以下代码示例:
以下代码示例应拆分为 2 个PRINT 代码。

 10 PRINT "Hello World 1" : PRINT "Hello World 2"

但不要匹配这个:
以下代码示例是一个独立的命令。

 10 PRINT "Hello World 1" ": PRINT Hello World 2"

问题

任何正则表达式模式都可以匹配上述第一个代码示例,其中: 在一对" 之外并且不匹配第二个?

有人可以帮我吗?
任何事情都会有所帮助。 :)

【问题讨论】:

  • 你不应该用正则表达式解析这种结构。正则表达式只能匹配常规语言,这不适合您的问题。您应该改用 this 之类的构造。
  • @Mauren 确实如此。我最终会这样做,但首先我需要标记源代码,并净化代码(即删除 cmets 等......)。所以我相信我首先需要标记:
  • 我建议您通过构建一个循环来进行标记化,在该循环中查看每个字符并确定它属于哪个标记,而不是通过正则表达式进行。请查看之前链接的源代码的第 86 行。
  • @Mauren 谢谢,这是一个巨大的帮助:)
  • @Mauren:我同意“完整的”正则表达式解决方案不是此类任务的最佳方式,但是,不要相信像 boost(或其他现代正则表达式工具)这样的库) 无法匹配非正则语言。我们离理论上的考虑和 POSIX 正则表达式引擎的能力还很远。

标签: c++ regex boost basic compiler-construction


【解决方案1】:

我相信对您来说最好的选择是使用循环等设备标记您的源代码,而不是尝试使用正则表达式对其进行标记。

在伪代码中

string lexeme;
token t;

for char in string
    if char fits current token
        lexeme = lexeme + char;
    else
        t.lexeme = lexeme;
        t.type = type;
        lexeme = null;
    end if
    // other treatments here
end for

您可以在this source code 中看到此设备的实际实现,更具体地说,在第 86 行。

【讨论】:

  • 下面的答案是您提案的实施。谢谢。
【解决方案2】:

避免此类问题的想法是在尝试匹配冒号之前匹配引号内的内容示例:

"(?>[^\\"]++|\\{2}|\\.)*"|:

您可以添加捕获组以了解已匹配的交替部分。

然而,做这种任务的好工具可能是 lex/yacc

【讨论】:

  • @Dariush:你想做什么?
  • @Dariush:方法不同。如果将交替的第一部分放在捕获组中,则只需检查捕获组是否无效或存在即可知道模式是否匹配任何引号外的冒号。
【解决方案3】:

感谢@Mauren,我成功地完成了我想做的事情。
这是我的代码(以后可能会对某人有所帮助):
注意char* buffervector<string> source_code中包含的源文件内容。

    /* lines' tokens container */
    std::string token;
    /* Tokenize the file's content into seperate lines */
    /* fetch and tokenizing line version of readed data  and maintain it into the container vector*/
    for(int top = 0, bottom = 0; top < strlen(buffer) ; top++)
    {
        /* inline tokenizing with line breakings */
        if(buffer[top] != '\n' || top == bottom)
        { /* collect current line's tokens */ token += char(buffer[top]); /* continue seeking */continue; }
        /* if we reach here we have collected the current line's tokens */
        /* normalize current tokens */
        boost::algorithm::trim(token);
        /* concurrent statements check point */
        if(token.find(':') != std::string::npos)
        {
            /* a quotation mark encounter flag */
            bool quotation_meet = false;
            /* process entire line from beginning */
            for(int index = 0; true ; index++)
            {
                /* loop's exit cond. */
                if(!(index < token.length())) { break; }
                /* fetch currently processing char */
                char _char = token[index];
                /* if encountered  a quotation mark */
                /* we are moving into a string */
                /* note that in basic for printing quotation mark, should use `CHR$(34)` 
                 * so there is no `\"` to worry about! :) */
                if(_char == '"')
                {
                    /* change quotation meeting flag */
                    quotation_meet = !quotation_meet;
                    /* proceed with other chars. */
                    continue;
                }
                /* if we have meet the `:` char and also we are not in a pair quotation*/
                if(_char == ':' && !quotation_meet)
                {
                    /* this is the first sub-token of current token */
                    std::string subtoken(token.substr(0, index - 1));
                    /* normalize the sub-token */
                    boost::algorithm::trim(subtoken);
                    /* add sub-token as new line */
                    source_codes.push_back(subtoken);
                    /* replace the rest of sub-token as new token */
                    /**
                     * Note: We keep the `:` mark intentionally, since every code line in BASIC 
                     * should start with a number; by keeping `:` while processing lines starting with `:` means 
                     * they are meant to execute semi-concurrent with previous numbered statement.
                     * So we use following `substr` pattern instead of `token.substr(index + 1, token.length() - 1);`
                     */
                    token = token.substr(index, token.length() - 1);
                    /* normalize the sub-token */
                    boost::algorithm::trim(token);
                    /* reset the index for new token */
                    index = 0;
                    /* continue with other chars */
                    continue;
                }
            }
            /* if we have any remained token and not empty one? */
            if(token.length())
                /* a the tokens into collection */
                goto __ADD_TOKEN;
        }
__ADD_TOKEN:
        /* if the token is not empty? */
        if(token.length())
            /* add fetched of token to our source code */
            source_codes.push_back(token);
__NEXT_TOKEN:
        /* move pointer to next tokens' position */
        bottom = top + 1;
        /* clear the token buffer */
        token.clear();
        /* a fail safe for loop */
        continue;
    }
    /* We NOW have our source code departed into lines and saved in a vector */

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-20
    • 2021-04-16
    • 1970-01-01
    • 1970-01-01
    • 2018-04-17
    • 2020-10-19
    • 1970-01-01
    相关资源
    最近更新 更多