当然取决于语言 :-) 但在大多数语法中它是相当直接的(见下文)。
不过,有一条评论。正如下面的语法所示,成员访问(如函数调用,通常还有下标)就像一个后缀运算符;点后面的符号(或箭头,在类 C 语言中)是表示成员名称的符号。它不是一种表达;成员查找中的唯一表达式位于运算符的左侧。所以a.b.c 应该对应一个 AST 节点,比如:
MemberLookup(MemberLookup(Variable("a"), "b"), "c")
和a.b.func(2, c)应该变成:
MethodCall(MemberLookup(Variable("a"), "b"),
"func",
List(Number(2), Variable("c")))
或者,也许,
Apply(MemberLookup(MemberLookup(Variable("a"), "b"), "func"),
List(Number(2), Variable("c"))
(区别在于隐含的self/this 参数;有多种策略来处理这个问题。对比Java、Python 和Lua 三种完全不同的策略。)
不管怎样,这里有几个简单的语法片段:
C
这是 C 语法的摘录(见 C 标准的附录 A:
postfix-expression:
primary-expression
postfix-expression '[' expression ']'
postfix-expression '(' argument-expression-listopt ')'
postfix-expression '.' identifier
postfix-expression '->' identifier
postfix-expression '++'
postfix-expression '--'
我不仅包括成员访问函数,因为它表明.identifier 和->identifier 的处理方式与任何其他后缀运算符一样,这是一个有用的见解。相同的产生式还包括两个后缀括起来的运算符,下标 ([...]) 和函数调用 ((...)),这似乎与此处相关。但是我省略了复合文字(我会放入primary-expression)。
Python
Python 3.9 文档的类似摘录:
primary:
primary '.' NAME
primary '(' [arguments] ')'
primary '[' slices ']'
primary genexp
atom