Parsing 确定令牌是否是行上的第一个令牌

Parsing 确定令牌是否是行上的第一个令牌,parsing,compiler-construction,tokenize,Parsing,Compiler Construction,Tokenize,我正在为自定义编程语言编写lexer。首先,我想说这是一个个人练习,我想用手写的方式来做,不要使用任何生成器工具,如Lex或Flex 在我的语言中,语法之一是有三种类型的注释:单行注释、多行注释和文档注释: 单行注释: code(x, y, z); %% a comment that ends at the end of the line moreCode(x, y, z); code(x, %- a comment that starts and ends on the same line.

我正在为自定义编程语言编写lexer。首先,我想说这是一个个人练习,我想用手写的方式来做,不要使用任何生成器工具,如LexFlex

在我的语言中,语法之一是有三种类型的注释:单行注释、多行注释和文档注释:

  • 单行注释:
    code(x, y, z); %% a comment that ends at the end of the line
    moreCode(x, y, z);
    
    code(x, %- a comment that starts and ends on the same line. -% y, z);
    moreCode(x, %- a comment that starts, contains a line break,
      and then ends. -% y, z);
    
  • 多行注释:
    code(x, y, z); %% a comment that ends at the end of the line
    moreCode(x, y, z);
    
    code(x, %- a comment that starts and ends on the same line. -% y, z);
    moreCode(x, %- a comment that starts, contains a line break,
      and then ends. -% y, z);
    
  • 文件注释:
    %%%
    a doc comment. the delimiters must be on their own line
    %%%
    code(x, y, z);
    
  • 问题 这个问题是关于标记注释的文档类型(#3)。现在,我可以成功地将单行和多行标记化,并且可以将文档注释标记化为多行。但这导致了一个问题:

    错误行为 “文档注释”被视为多行注释。综上所述,我的代币器错误地生成了以下代币:

  • code
    -标识符
  • -符号
  • -符号
  • -符号
  • %%%此文本
    评论
    输出%%-注释
  • notCommentedOut
    -标识符
  • -符号
  • -符号
  • -符号
  • 预期行为 上面的标记化是不正确的,因为我希望强制分隔符在自己的行上,以便注册为文档注释,并且我希望任何不在自己行上的
    %%
    都被视为单行注释(因为它以
    %%
    开头)。 这意味着正确的标记化应该是:

  • code
    -标识符
  • -符号
  • -符号
  • -符号
  • %%%这已被注释掉。
    -注释
  • notCommentedOut
    -标识符
  • -符号
  • -符号
  • -符号
  • “也”
    -字符串
  • +
    -符号
  • -符号
  • 注释输出
    -标识符
  • -符号
  • %%%也注释掉了
    -注释
  • 相似之处 其他语言具有类似的结构,例如,在标记、标题和隔离代码块中:

    # this is a heading
    
    foobar # this is not a heading
    
    ```
    this is a fenced code block
    ```
    
    foobar ``` this is not
    a fenced code block ```
    
    在LaTeX中,我们可以将块方程:

    $$
    f(x) = 2^{x + 1}
    $$
    
    我的方法 代码 (为清晰起见,请键入脚本并缩小。)

    //提高扫描仪的`n`字符数
    函数前进(n:number=1):无效{
    如果(n==1){
    //将c0重新指定给下一个字符
    //将c1重新分配给前瞻(1)
    //将指挥控制重新分配给前瞻(2)
    }否则{
    预付款(n-1)
    预付款
    }
    }
    而(!character.done){
    if(空白。包括(c0)){
    const wstoken=新标记(character.value)
    wstoken.type=TokenType.WHITESPACE
    预付款
    while(!character.done&&whitespace.includes(c0)){
    wstoken.cargo+=c0
    预付款
    }
    //仅当我们希望lexer返回空白时,才产生wstoken//
    打破
    }
    常量标记=新标记(character.value)
    如果(c0==结束标记){
    token.type=TokenType.EOF
    预付款
    }如果(c0+c1+c2==comment\u doc\u start){//我们找到了一个doc注释:`%%%`
    token.type=TokenType.COMMENT
    token.cargo+=注释\单据\开始
    预付款(备注\单据\起始长度)
    而(!character.done&&c0+c1+c2!==comment\u doc\u end){
    如果(c0==ENDMARK)抛出新错误(“在注释结尾之前找到文件结尾”)
    token.cargo+=c0
    预付款
    }
    //将注释\文档\结尾添加到令牌
    token.cargo+=注释\单据\结束
    预付款(备注\单据\结束长度)
    }如果(c0+c1==注释\u多行\u开始){//我们找到了一个多行注释:`%-%`
    token.type=TokenType.COMMENT
    token.cargo+=注释\u多\u开始
    前进(注释\u多\u开始长度)
    而(!character.done&&c0+c1!==注释\u多\u结束){
    如果(c0==ENDMARK)抛出新错误(“在注释结尾之前找到文件结尾”)
    token.cargo+=c0
    预付款
    }
    //向令牌添加注释\u多\u结尾
    token.cargo+=注释\u多\u结束
    进阶(注释\u多个\u结束。长度)
    }如果(c0+c1===注释行){//我们找到了一行注释:`%%`
    token.type=TokenType.COMMENT
    token.cargo+=注释行
    预付款(注释行长度)
    而(!character.done&&c0!='\n'){
    如果(c0==ENDMARK)抛出新错误(“在注释结尾之前找到文件结尾”)
    token.cargo+=c0
    预付款
    }
    //不要将“\n”添加到令牌
    }否则{
    抛出新错误(`I发现一个我无法识别的字符或符号:${c0}`)
    }
    收益券
    }
    
    思维过程 我认为有两种选择,这两种都不可取

    一个选项是在
    while
    循环之外有一个全局变量,一个布尔标志,指示上一个标记是否为空白并包含
    \n
    。然后使用该标志通知下一个标记,该标记以
    %%
    开头。如果该标志为true,则注释应在下一个
    %%处关闭;否则它应该在下一次
    \n
    时关闭。我不确定我是否喜欢这个选项,因为它涉及到为每个代码标记设置标志。它也不考虑结尾分隔符,它也必须在自己的行上

    另一个选择是回溯。当lexer到达一个以
    %%%
    开头的令牌时,请检查上一个令牌是否为空白并且包含
    \n
    。如果是这样,则
    %%%%
    标记是一个文档注释,应该在下一次
    %%
    时关闭。如果不是,则为内联注释,