cc65は
シンボル用にいくつかの種類のスコープに対応しています。
重ね合わさったスコープの外部で定義された全ての(局所的でない)シンボルは、グローバルスコープとなります。
簡易局所シンボルのためのスコープは、専用のスコープです。
A special scope is the scope for cheap local symbols.
プログラマによって作られたprovisionsを除き、ローカルシンボルで無い所から、次のところまで続きます。
全てその他のスコープは通常と異なるが、内部の同じ概念を使えます。
一般的な使用のための重なり合ったスコープは、
.SCOPE
で始まり
.ENDSCOPE
で終わる。
スコープは名前を持て、その時は、明示的スコープを使用することで外部からアクセスする事ができる。
スコープが名前を持たない場合、スコープの内側で作られた全てのシンボルはスコープでローカルであり、外部からのアクセスはできません。
重なり合ったスコープは、ローカル若しくは、
明示的なスコープ名を使わない名前で閉じられたスコープからのシンボルをアクセスできます。
いくらかの場合それらは不明瞭であり、
例えば、もしまだ定義されてないローカルシンボルへの参照があるが、外部のスコープに、同じ名前を含むシンボルが存在する場合:
.scope outer
foo = 2
.scope inner
lda #foo
foo = 3
.endscope
.endscope
上の例では,lda
命令はアキュムレータに値3をロードします。
なぜならば、スコープでfoo
が再定義されているからです。
しかしながら:
.scope outer
foo = $1234
.scope inner
lda foo,x
foo = $12
.endscope
.endscope
これは, lda
命令は、まだ$12,x
からロードしないが、
but since it is unknown to the assembler that foo
is a zeropage symbol when translating the instruction,
absolute mode is used instead.
In fact, the assembler will not use absolute mode by default,
but it will search through the enclosing scopes for a symbol with the given name.
If one is found, the address size of this symbol is used.
これは、エラーとなる。:
.scope outer
foo = $12
.scope inner
lda foo,x
foo = $1234
.endscope
.endscope
この場合、アセンブラーがlda
命令でシンボルfoo
を見つけたとき、
すでに定義されたシンボルfoo
を検索します。
スコープouter
でfoo
が見つけられ、and a close look reveals that it is a ゼロページシンボル.
すると、アセンブラーはゼロページアドレッシングモードを使います。
foo
がスコープinner
で後に再定義される場合、
アセンブラはすでに変換されたlda
命令でアドレッシングの変更を試みるが、
but since the 新しい値は絶対アドレッシングモードを必要とし、これはできず、エラーメッセージ"Range error"を出力します。
もちろん the most simple solution for the problem is to move the definition of foo
in scope inner
upwards,
so it precedes its use.
here may be rare cases when this cannot be done.
In these cases, you can use one of the address size override operators:
.scope outer
foo = $12
.scope inner
lda a:foo,x
foo = $1234
.endscope
.endscope
This will cause the lda
命令 to be translated using 絶対アドレッシングモード,
which means changing the symbol reference later does not cause any errors.
A nested procedureは、.PROC
の使用で生成されます。
It differs from a .SCOPE
in that it must have a name,
and a it will introduce a symbol with this name in the enclosing scope.
So
.proc foo
...
.endproc
is actually the same as
foo:
.scope foo
...
.endscope
This is the reason why a procedure must have a name.
If you want a scope without a name,
use .SCOPE
.
注意:
As you can see from the example above, scopes and symbols live in different namespaces.
There can be a symbol named foo
and a scope named foo
without any conflicts (but see the section titled
"Scope search order").
構造体、共用体、及び列挙は are explained in a separate section,
I do only cover them here,
because if they are declared with a name,
they open a nested scope, similar to .SCOPE
.
しかしながら, when no name is specified, the behaviour is different:
この場合, no new scope will be opened, symbols declared within a struct, union, or enum declaration will then be added to the enclosing scope instead.
Accessing symbols from other scopes is possible by using an 明示的スコープ specification,
provided that the scope where the symbol lives in has a name.
他のスコープからのアクセスに、名前空間トークン(::
)が使用される:
.scope foo
bar: .word 0
.endscope
...
lda foo::bar ; Access foo in scope bar
The only way to deny access to a scope from the outside is to declare a scope without a name
(.SCOPE
コマンドを使用する).
A special syntax is used to specify the global scope: If a symbol or scope is preceded by the namespace token, the global scope is searched:
bar = 3
.scope foo
bar = 2
lda #::bar ; Access the global bar (which is 3)
.endscope
The assembler searches for a scope in a similar way as for a symbol.
最初に, it looks in the current scope,
and then it walks up the enclosing scopes until the scope is found.
しかしながら, one important thing to note when using 明示的スコープ syntax is,
that a symbol may be accessed before it is defined,
but a scope may not be used without a preceding definition.
これは、以下の例を意味する。:
.scope foo
bar = 3
.endscope
.scope outer
lda #foo::bar ; Will load 3, not 2!
.scope foo
bar = 2
.endscope
.endscope
the reference to the スコープfoo
will use the global scope, and not the local one,
because the local one is not visible at the point where it is referenced.
Things get more complex if a complete chain of scopes is specified:
.scope foo
.scope outer
.scope inner
bar = 1
.endscope
.endscope
.scope another
.scope nested
lda #outer::inner::bar ; 1
.endscope
.endscope
.endscope
.scope outer
.scope inner
bar = 2
.endscope
.endscope
When outer::inner::bar
is referenced in the lda
instruction, the
assembler will first search in the local scope for a scope named outer
.
Since none is found, the enclosing scope (another
) is checked. There is
still no scope named outer
, so scope foo
is checked, and finally
scope outer
is found. Within this scope, inner
is searched, and in
this scope, the assembler looks for a symbol named bar
.
Please note that once the anchor scope is found, all following scopes
(inner
in this case) are expected to be found exactly in this scope. The
assembler will search the scope tree only for the first scope (if it is not
anchored in the root scope). Starting from there on, there is no flexibility,
so if the scope named outer
found by the assembler does not contain a
scope named inner
, this would be an error, even if such a pair does exist
(one level up in global scope).
Ambiguities that may be introduced by this search algorithm may be removed by
anchoring the scope specification in the global scope. In the example above,
if you want to access the "other" symbol bar
, you would have to write:
.scope foo
.scope outer
.scope inner
bar = 1
.endscope
.endscope
.scope another
.scope nested
lda #::outer::inner::bar ; 2
.endscope
.endscope
.endscope
.scope outer
.scope inner
bar = 2
.endscope
.endscope