PDA

Просмотр полной версии : Занимательный ActionScript (Flash 5 only!!)


Suhoff
13.06.2002, 01:42
Открываем новый fla и в в Frame Action пишем одну строчку:

foo=0*++1.2345;

... запускаем на выполнение.....
Как вы думаете чему будет равна переменная foo? Очевидно - нулю.... Ноль умножить на любое число - ноль... Логично....
Нажимает Ctrl-Alt-V............. и тихонько сползаем со стула.......
............
теперь выбрасывем foo к чёрту... пишем, например ......

10#++1.23456;

где вместо '#' может стоять ЛЮБАЯ операция-'+','-','*','/,'%','<','>','<>','|','&' - результат от этого не меняется.....
Запускаем..... Нажимает Ctrl-Alt-V...... Протитаем глаза.... Пауза..........
Вобщем - Очевидное-невероятное..... :eek:

Nox Noctis
13.06.2002, 02:58
все абсолютно правильно

1.2345 - это НЕ леводопустимое выражение
(леводопустимое, это которое может стоять слева от знака присвоения)

что по сути выполняется если написано ++1 ?
– при трансляции все числовые значения в коде являются константами
– мы берем константу и увеличиваем ее значение на 1.
ну не фигня ли это ?

это то же самое что написать:
1 = 2;

вот если написать
i=1.2345;
foo=0*++i;
то все в порядке, потому что имя переменной - это леводопустимое выражение...

зы: вот мыкс за леводопустимостью следит строго... а пятерка стандарту (как там он называется ?) не соответствует, и ошибку эту выдает, но при компиляции о ней не сообщает...

Suhoff
13.06.2002, 04:17
2Nox Noctis
...Почему фигня то, что "мы берём константу и увеличиваем её значение на 1", я не понимаю....
А по поводу того, что 1.2345 не является леводопустимым выражением..... Давайте возьмём стандат ECMA-262 (он ТАК называется) и рассмотрим следующую цепочку из описания грамматики языка.....

UnaryExpression :
PostfixExpression
delete UnaryExpression
void UnaryExpression
typeof UnaryExpression
++ UnaryExpression
-- UnaryExpression
+ UnaryExpression
- UnaryExpression
~ UnaryExpression
! UnaryExpression

PostfixExpression :
LeftHandSideExpression
..............................................................

LeftHandSideExpression :
NewExpression
CallExpression

NewExpression :
MemberExpression
new NewExpression

MemberExpression :
PrimaryExpression
FunctionExpression
MemberExpression [ Expression ]
MemberExpression . Identifier
new MemberExpression Arguments

PrimaryExpression :
this
Identifier
Literal
ArrayLiteral
ObjectLiteral
( Expression )

Literal ::
NullLiteral
BooleanLiteral
NumericLiteral
StringLiteral

а 1.2345 - по сути является NumericLiteral...........

Это с одной стороны... С другой стороны...
Постфиксный инкримент выполнятеся согласно стандарту следующим образом-
11.4.4 Prefix Increment Operator
The production UnaryExpression : ++ UnaryExpression is evaluated as follows:
1. Evaluate UnaryExpression.
2. Call GetValue(Result(1)).
3. Call ToNumber(Result(2)).
4. Add the value 1 to Result(3), using the same rules as for the + operator (see 11.6.3).
5. Call PutValue(Result(1), Result(4)).
6. Return Result(4).
..............................................
8.7.2 PutValue (V, W)
1. If Type(V) is not Reference, throw a ReferenceError exception.
2. Call GetBase(V).
3. If Result(2) is null, go to step 6.
4. Call the [[Put]] method of Result(2), passing GetPropertyName(V) for the property name and W for
the value.
5. Return.
6. Call the [[Put]] method for the global object, passing GetPropertyName(V) for the property name and
W for the value.
7. Return.

Поскольку Численный литерал не имеет тип "Reference" (его имеют идентификаторы), то "++1.2345" должно выдавать "ReferenceError exception.", чего не происходит...

А происходит то, что Flash 5 вышеприведённом случае ведёт себя таким непонятным и нелогичным образом !!!
В этом-то вся и фигня......

Nox Noctis
13.06.2002, 07:07
так ты же сам и подтвердил все :)
проблема в не-леводопустимости выражения 1.2345 - это не "Reference" => "throw a ReferenceError exception".
...и компилятор пятерки не сообщает об ошибке, хотя код после этого работает черт знает как... это вроде евала в левой части... глюк из той же серии...

а насчет константы - это просто объяснение того же самого другими словами :)
1=2; не смотря ни на что приведет к ошибке, и если это дело замаскировать инкрементом, то это ничего не исправит :)

Suhoff
14.06.2002, 02:00
2Nox Noctis
.... eval в левой части не глюк... Это была возможность возвращать в левой части выражения переменную типа Reference (идентификаторы), что, кстати, допускается стандартом. Зачем эту возможность убрали в MX я пока не понимаю....
... На самом деле удивляет вот что - согласно грамматике языка допускается возможность некоторой операции (в данном случае ++const), но в АЛГОРИТМЕ РЕАЛИЗАЦИИ этой операции такая конструкция считается недопустимой!!! И как тут жить?? Возникает вопрос - что приоритетней: грамматика или алгоритм реализации этой грамматики????
Мне пока непонятно....
Может кто из гуру объяснит??

Nox Noctis
14.06.2002, 14:44
грамматика много чего разрешает...
но это всего лишь формальная правильность, а содержательная правильность проверяется либо во мремя компиляции, либо вообще в рантайме...

а сравнивать что важнее - форма или содержание, это как-то странно ;)

насчет евала в левой части присвоения : самый верхний пост (john'a) (http://www.flasher.ru/forum/showthread.php?s=&threadid=28096&perpage=15&pagenumber=12) :)


...ты видел, кстати, во что транслитруется выражение a = 0*++1.2345; в ассемблерном коде
(в сравнении с a = 0*++(b=1.2345); ) ?
...очень забавно :D

Suhoff
15.06.2002, 02:55
2Nox Noctis
.... Мда..... Мне эта ситуация напоминает поговорку - "Если нельзя, но очень хочется - то можно"! :) Или перефразируя для данной ситуации - "Если можно, но очень не хочется - то нельзя"..... Или нашу Конституцию и законы - Конституция (грамматика) вроде бы позволяет.... но законы (алгоритм реализации Конституции) ни фига...... :((((.... Ладно.... это уже флэйм и к делу не относится.....
Вывод - имеем в Flash 5 законченный БАГ.... Интересно, кстати, Micromedia о нём знает????

ЗЫ во что транслируется данные выражения - видел.... Наверное им можно пугать тех, кто смотрит коды с помощью ASV или SWF Scaner`а..... Кстати, в MX сгенерённый F5 код этой оперции прекрасно выполняется....

Спасибо за дискуссию.
С уважением. Suhoff :)

Nox Noctis
15.06.2002, 03:33
:) :) обращайтесь... ;)


напоследок я все-таки приведу этот кусочек кода c ошибкой... мало ли кому интересно...

из выражения a = 0*++1.2345; при трансляции получается:

push 'a', 0.0, 1.2345
increment
setRegister r:0
setVariable
push r:0
multiply
setVariable

расшифруем:

push 'a', 0.0, 1.2345 // имя и два числа заносиятся в стэк
increment // операция берет верхнее в стэке значение и увеличивает его на 1 прямо в стэке (т е 1.2345+1)
setRegister r:0 // в регистр r0 помещаем верхнее в стэке значение (т е 2.2345)
setVariable // берем последнее в стэке значение и запихиваем его в переменную с именем равному предпоследнему в стэке значению (в данном случае 0.0 = 2.2345 - уже хорошо :)) после присвоения операнды из стэка удаляются
push r:0 // заносим в стэк то, что до этого положили в регистр r0 (это было 2.2345)
multiply // перемножаем два оставшихся в стэке операнда (то есть 'a'*2.2345 :D ) и результат кладем в стэк...
setVariable // проделываем такую же операцию как см. выше... но учитывая, что в стэке у нас всего один операнд в данный момент (да и тот пустой :) ) - получаем полную лажу :D