注释

在给Lispy添加新语法的同时,我们也可以研究一下注释。

跟C一样,我们用注释来告知其他人(或我们自己)相关代码的用途或编写原因。 C语言注释在/**/之间,Lisp注释则以;开头,并读取至行尾。

笔者曾试图研究为什么Lisp使用;作为注释,但其起源似乎已消失在时间的迷雾当中。 笔者认为这是对C和Java等命令式语言小小的反叛,它们使用分号如此无耻地经常分隔/终止语句。 与Lisp相比,所有这些语言都仅仅是注释而已。

因此在lisp中,注释定义为分号;后跟着任意数量的字符,这些字符不是由\r\n表示的换行符。 我们用另一个正则表达式来定义。

  1. comment : /;[^\\r\\n]*/ ;

和字符串一样,我们需要创建一个新的解析器并在mpca_lang中更新语法。 此外,还需将对应解析器添加到mpc_cleanup,并同步更新解析器个数。

Lispy最终语法现在看起来是这样的。

  1. mpca_lang(MPCA_LANG_DEFAULT,
  2. " \
  3. number : /-?[0-9]+/ ; \
  4. symbol : /[a-zA-Z0-9_+\\-*\\/\\\\=<>!&]+/ ; \
  5. string : /\"(\\\\.|[^\"])*\"/ ; \
  6. comment : /;[^\\r\\n]*/ ; \
  7. sexpr : '(' <expr>* ')' ; \
  8. qexpr : '{' <expr>* '}' ; \
  9. expr : <number> | <symbol> | <string> \
  10. | <comment> | <sexpr> | <qexpr>; \
  11. lispy : /^/ <expr>* /$/ ; \
  12. ",
  13. Number, Symbol, String, Comment, Sexpr, Qexpr, Expr, Lispy);

清理函数看起来则是这样。

  1. mpc_cleanup(8,
  2. Number, Symbol, String, Comment,
  3. Sexpr, Qexpr, Expr, Lispy);

因为注释仅仅是供程序员分析代码,所以用于读取代码的内置函数只是忽略它们。我们可以在lval_read中添加一个类似于括号处理方式的子句来处理注释。

  1. if (strstr(t->children[i]->tag, "comment")) { continue; }

注释在REPL没有多大用处,但在给代码加上评注方面非常有用。