当前位置: 首页 > 面试题库 >

Pythonic宏语法

刘瀚
2023-03-14
问题内容

我一直在研究Python的另一种编译器前端,其中所有语法都是通过宏解析的。我最终要指出的是,我可以在宏是不可或缺的组件的Python语言的超集上开始工作。

我的问题是我无法提出pythonic宏定义语法。我在下面的答案中以两种不同的语法发布了一些示例。任何人都可以提出更好的语法吗?不必以任何方式构建我提出的语法-
我在这里完全打开了。任何评论,建议等都将有所帮助,显示我发布的示例的替代语法也将有所帮助。

如我所发布的示例所示,有关宏结构的注释:使用MultiLine / MLMacro和Partial /
PartialMacro告诉解析器如何应用宏。如果是多行,则宏将匹配多个行列表;通常用于构造。如果是局部的,则宏将匹配列表中间的代码;通常用于运营商。


问题答案:

在几天前考虑了一下之后,没有提出任何值得发表的内容,我现在回到它,并提出了一些我喜欢的语法,因为它几乎像python

macro PrintMacro:
  syntax:
    "print", OneOrMore(Var(), name='vars')

  return Printnl(vars, None)
  • 使所有宏“关键字”看起来像创建python对象(Var()而不是simple Var
  • 将元素名称作为“关键字参数”传递给我们要为其命名的项目。仍然很容易在解析器中找到所有名称,因为无论如何都需要以某种方式解释此语法定义以填充宏类语法变量。

需要进行转换以填充结果宏类的语法变量。

内部语法表示也可能看起来相同:

class PrintMacro(Macro):
  syntax = 'print', OneOrMore(Var(), name='vars')
  ...

OneOrMore这样的内部语法类将遵循此模式以允许子项目和可选名称:

class MacroSyntaxElement(object):
  def __init__(self, *p, name=None):
    self.subelements = p
    self.name = name

当宏匹配时,您只需收集所有具有名称的项目并将它们作为关键字参数传递给处理程序函数:

class Macro():
   ...
   def parse(self, ...):
     syntaxtree = []
     nameditems = {}
     # parse, however this is done
     # store all elements that have a name as
     #   nameditems[name] = parsed_element
     self.handle(syntaxtree, **nameditems)

然后将定义处理程序函数,如下所示:

class PrintMacro(Macro):
  ...
  def handle(self, syntaxtree, vars):
    return Printnl(vars, None)

我添加了语法树作为始终传递的第一个参数,因此,如果您只想在语法树上做非常基本的事情,则不需要任何命名项。

另外,如果您不喜欢装饰器,为什么不像“基类”那样添加宏类型呢?IfMacro然后将如下所示:

macro IfMacro(MultiLine):
  syntax:
    Group("if", Var(), ":", Var(), name='if_')
    ZeroOrMore("elif", Var(), ":", Var(), name='elifs')
    Optional("else", Var(name='elseBody'))

  return If(
      [(cond, Stmt(body)) for keyword, cond, colon, body in [if_] + elifs],
      None if elseBody is None else Stmt(elseBody)
    )

并在内部表示形式中:

class IfMacro(MultiLineMacro):
  syntax = (
      Group("if", Var(), ":", Var(), name='if_'),
      ZeroOrMore("elif", Var(), ":", Var(), name='elifs'),
      Optional("else", Var(name='elseBody'))
    )

  def handle(self, syntaxtree, if_=None, elifs=None, elseBody=None):
    # Default parameters in case there is no such named item.
    # In this case this can only happen for 'elseBody'.
    return If(
        [(cond, Stmt(body)) for keyword, cond, body in [if_] + elifs],
        None if elseNody is None else Stmt(elseBody)
      )

我认为这将提供一个相当灵活的系统。主要优点:

  • 易于学习(看起来像标准python)
  • 易于解析(类似于标准python的解析)
  • 可选项目很容易处理,因为您可以None在处理程序中使用默认参数
  • 灵活使用命名项:
    • 如果不需要,则无需命名任何项目,因为语法树始终会传入。
    • 您可以在大型宏定义中命名任何子表达式,因此很容易挑选出您感兴趣的特定内容
  • 如果要向宏结构添加更多功能,可以轻松扩展。例如Several("abc", min=3, max=5, name="a")。我认为这也可以用于将默认值添加到可选元素,例如Optional("step", Var(), name="step", default=1)

我不确定带有“ quote:”和“ $”的quote /
unquote语法,但是需要一些语法,因为如果您不必手动编写语法树,它将使工作变得更加轻松。要求(或只是允许?)“
$”括号可能是个好主意,因此,如果需要,您可以插入更复杂的语法部分。像$(Stmt(a, b, c))

ToMacro看起来像这样:

# macro definition
macro ToMacro(Partial):
  syntax:
    Var(name='start'), "to", Var(name='end'), Optional("inclusive", name='inc'), Optional("step", Var(name='step'))

  if step == None:
    step = quote(1)
  if inclusive:
    return quote:
      xrange($(start), $(end)+1, $(step))
  else:
    return quote:
      xrange($(start), $(end), $(step))

# resulting macro class
class ToMacro(PartialMacro):
  syntax = Var(name='start'), "to", Var(name='end'), Optional("inclusive", name='inc'), Optional("step", Var(name='step'))

  def handle(syntaxtree, start=None, end=None, inc=None, step=None):
    if step is None:
      step = Number(1)
    if inclusive:
      return ['xrange', ['(', start, [end, '+', Number(1)], step, ')']]
    return ['xrange', ['(', start, end, step, ')']]


 类似资料:
  • #define 叫做 宏定义命令,它也是C语言预处理命令的一种。所谓 宏定义,就是用一个标识符来表示一个字符串,如果在后面的代码中出现了该标识符,那么就全部替换成指定的字符串。 我们先通过一个例子来看一下 #define 的用法: 运行结果: 120 注意第 6 行代码 , 被 代替了。 就是宏定义, 为宏名, 是宏的内容(宏所表示的字符串)。在预处理阶段,对程序中所有出现的“宏名”,预处理器都会

  • 问题内容: 我只是继承了一些使我感到不安的代码:有一个测试库,其中充满了与我们网站上的网页相对应的类,并且每个网页类都有使该页面上的功能自动化的方法。 有一些方法可以单击页面之间的链接,这将返回链接页面的类。这是一个简化的示例: 文件homePageLib.py: 文件calendarLib.py: 然后,这允许脚本文件单击页面,并从该方法获取对象作为返回值,这意味着脚本作者在站点中导航时不必继续

  • 问题内容: 有没有像我在C ++中那样做的pythonic首选方式: 我真的很喜欢这种语法,它比在各处都有临时变量要干净得多。不太复杂的唯一其他方法是 我想我是在抱怨一个很时髦的问题。我只是想念以前的语法。 问题答案: 怎么样 或更实用

  • 问题内容: 已关闭 。这个问题是基于观点的。它当前不接受答案。 想改善这个问题吗? 更新问题,以便通过编辑此帖子以事实和引用的形式回答。 7年前关闭。 改善这个问题 这个问题困扰了我很长时间(正如我之前的问题所证明的):为什么比(确切地说是更pythonic的)更好? 对于那些不知道的人,该语句已更改为Python 3.0中的函数。正式文档在PEP 3105中 ,动机在Guido van Ross

  • 我有一个方法,按顺序调用4个其他方法来检查特定条件,并且每当返回Truthy的内容时立即返回(不检查以下内容)。 这似乎有很多行李编码。我宁愿这样做,而不是每个2行if语句: 但这是无效的Python。我是否错过了一个简单、优雅的解决方案?顺便提一下,在这种情况下,这四种检查方法可能很昂贵,因此我不想多次调用它们。

  • 本项目创意来源于前天Twitter的一个热门段子,看到段子后当即动手,实现了这个Pythonic PHP Code Formatter。 这个工具可以自动化地把PHP中讨厌的分号以及花括号对齐到右侧,让PHP代码看起来就像Python! 但是请注意这只是一个玩具,使用该格式化工具会让你的代码变得难以维护,千万请不要在生产环境中使用! 在线演示地址: http://www.94cb.com/Pyth

  • 记录一系列操作,在需要的时候运行 例如给一个单词加 " ,可以分解为以下操作: M-b 移动到词首"M-f 移动到词尾" 这种重复的操作往往需要经常执行,手动未免太没有效率。我们可以把这些操作制作成宏,然后运行这个宏 当然,这只是最简单的宏。结合正则表达式进行匹配,以宏进行操作,可以完成许多复杂的操作 定义与运行 表 25.14. Emacs 宏 开始录制 C-x ( (M-x kmacro-

  • 您可以将一系列的操作录制为一个宏,然后执行它 q宏名称 开始录制宏。宏名称为一个字符 q 录制中按下“q”键,结束录制 @宏名称 执行宏 可以使用 :registers(寄存器列表) 命令查看已记录的宏