Оберон-клуб «ВЄДАsoft»

Твердыня модульных языков
Текущее время: 03 сен 2025, 11:09

Часовой пояс: UTC + 2 часа




Начать новую тему Ответить на тему  [ Сообщений: 72 ]  На страницу Пред.  1, 2, 3, 4, 5, 6 ... 8  След.
Автор Сообщение
СообщениеДобавлено: 19 май 2013, 19:08 
Не в сети
Администратор
Аватара пользователя

Сообщения: 273
Откуда: Россия
Saferoll писал(а):
Замена вычисления количества итераций константой и удаление IF с константным условием? Думаю это несложно сделать.
На самом деле это "несложно" все-таки заметно усложнило построение цикла FOR.
Код: "OBERON"
  1. ELSIF sym = for THEN (* построение синтаксического дерева для FOR *)
  2. OPS.Get(sym); (* взять символ после FOR *)
  3. IF sym = ident THEN qualident(id); (* если это идентификатор, уточнить его *)
  4. IF ~(id^.typ^.form IN intSet) THEN err(68) END ;(* он должен быть целого типа*)
  5. CheckSym(becomes); Expression(y); pos := OPM.errpos; (* потом д б «:= выражение (А)» *)
  6. x := OPB.NewLeaf(id); OPB.Assign(x, y); SetPos(x);(* вставим в дерево «id := А» *)
  7. apar:=y; (* apar = "A" *)
  8. CheckSym(to); Expression(y); pos := OPM.errpos; (* далее д б ТО выражение (В) *)
  9. IF sym = by THEN (* если далее задан шаг BY Step,*)
  10. OPS.Get(sym); ConstExpression(z) (* то читаем его как константное выражение*)
  11. ELSE
  12. z := OPB.NewIntConst(1) (*иначе берем константу 1*)
  13. END ;
  14. (* x = "id:=A" y=B z=Step apar="A" *)
  15. e := FALSE; (* в общем случае IF не отбрасывается*)
  16. IF (y^.class = Nconst) THEN
  17. obj := id; t := id;
  18. IF (y^.typ^.form < SInt) OR (y^.typ^.form > x^.left^.typ^.form) THEN
  19. err(113); t := id; obj := NIL; (* то это д б константа совместимого типа *)
  20. END;
  21. IF obj # NIL THEN
  22. IF apar^.class = Nconst THEN (* A и B - константы *)
  23. IF (z^.conval^.intval # 0) & (apar^.conval^.intval = y^.conval^.intval) THEN
  24. e:= FALSE; t:= NIL; (* цикл выполнится ровно 1 раз*)
  25. ELSIF (z^.conval^.intval > 0) & (apar^.conval^.intval <= y^.conval^.intval) OR
  26. (z^.conval^.intval < 0) &(apar^.conval^.intval >= y^.conval^.intval) THEN
  27. e:= TRUE; t :=id; (* цикл заведомо выполнится хотя бы раз, *)
  28. ELSIF (z^.conval^.intval > 0) & (apar^.conval^.intval >= y^.conval^.intval) OR
  29. (z^.conval^.intval < 0) &(apar^.conval^.intval <= y^.conval^.intval) THEN
  30. t := NIL; e:= TRUE; (* цикл не выполнится ни разу*)
  31. END ;
  32. END;
  33. IF t # NIL THEN
  34. IF (ABS(z^.conval^.intval)=1)& (ABS(y^.conval^.intval) <= 1) THEN
  35. (* частные случаи, когда переменная t не нужна*)
  36. t := id; (* вместо t используем id *)
  37. IF y^.conval^.intval = 0 THEN obj := NIL
  38. ELSIF y^.conval^.intval = z^.conval^.intval THEN obj := id
  39. ELSE obj := z.typ.strobj; ASSERT( obj # id);
  40. END
  41. ELSE
  42. name := "@@"; OPT.Insert(name, t); (* нужна переменная t*)
  43. END;
  44. END;
  45. END;
  46. ELSE (* B - не константа *)
  47. name := "@@"; OPT.Insert(name, t); (* нужна переменная t*)
  48. END;
  49.  
  50. IF (t # NIL) OR (e=FALSE) THEN
  51. OPB.Link(stat, last, x); (* добавим в дерево id := A*)
  52. IF ( t # id) & (t # NIL) THEN
  53. t^.name := "@for" ; t^.mode := Var; t^.typ := x^.left^.typ; (* в таблице имен создаем*)
  54. obj := OPT.topScope^.scope; (*вспомогательную *)
  55. IF obj = NIL THEN OPT.topScope^.scope := t (* переменную t для счетчика повторений*)
  56. ELSE
  57. WHILE obj^.link # NIL DO obj := obj^.link END ;
  58. obj^.link := t
  59. END ;
  60. obj:= t; ASSERT( obj # id);
  61. END;
  62. (* Переменные t и obj задают 4 случая цикла *)
  63. IF (t # id) & (t # NIL) THEN
  64. IF ~e THEN
  65. x:= OPB.NewLeaf(t); OPB.Assign(x, y); SetPos(x); (* t := B*)
  66. OPB.Link(stat, last, x);
  67. END;
  68. pos := OPM.errpos; (* теперь ошибка будет указывать на шаг*)
  69. x := OPB.NewLeaf(id);
  70. (* z = "Step", x = "id", y = "B" *)
  71.  
  72. IF z^.conval^.intval > 0 THEN (* подготовим выражение "кол-во повторений" *)
  73. IF e THEN
  74. x := OPB.NewIntConst( (y^.conval^.intval -apar^.conval^.intval) DIV z^.conval^.intval + 1)
  75. ELSE
  76. y:=OPB.NewLeaf(t);
  77. OPB.Op(minus, y,x); (* B-x *)
  78. OPB.Op(div, y, OPB.NewIntConst( z^.conval^.intval)); (* (B-x) div Step *)
  79. OPB.Op(plus, y, OPB.NewIntConst(1)); (* (B-x) div Step +1 *)
  80. x := y;
  81. END;
  82. ELSIF z^.conval^.intval < 0 THEN (* в зависимости от знака Step*)
  83. IF e THEN
  84. x := OPB.NewIntConst( (apar^.conval^.intval -y^.conval^.intval) DIV (-z^.conval^.intval) + 1)
  85. ELSE
  86. y:=OPB.NewLeaf(t);
  87. OPB.Op(minus, x, y); (* x-B *)
  88. OPB.Op(div, x, OPB.NewIntConst( -z^.conval^.intval)); (* (x-B) div Step *)
  89. OPB.Op(plus, x, OPB.NewIntConst(1)); (* (x-B) div Step +1 *)
  90. END
  91. ELSE err(63); OPB.Op(minus, x, y)
  92. END ;
  93. (* x = " (B-x) div Step +1" или "(x-В) div Step +1 " *)
  94. y := OPB.NewLeaf(t);OPB.Assign(y, x); SetPos(y); (* y = "t := (B-x) div Step +1 " *)
  95. ELSE (* без переменной t *)
  96. IF t # NIL THEN
  97. IF (obj = NIL) OR (obj = id) THEN (* нужно нейтрализовать первый инкремент*)
  98. y := OPB.NewLeaf(id); OPB.StPar1(y, z, decfn); SetPos(y); (* x= "DEC(id,Step)"*)
  99. ELSE
  100. y := OPB.NewLeaf(id); (* y = "id" - фиктивный оператор, т.к. нейтрализация не нужна *)
  101. END
  102. END
  103. END;
  104. pos := OPM.errpos;
  105. IF z^.conval^.intval=0 THEN err(63) END; (* нулевой шаг недопустим*)
  106. IF t # NIL THEN
  107. x := OPB.NewLeaf(id); OPB.StPar1(x, z, incfn); SetPos(x); (* x= "INC(id,Step)"*)
  108. y^.link := x; (* t := (B-x) div Step +1; INC(id,Step) *)
  109. IF t # id THEN (* добавить DEC(t) *)
  110. x := OPB.NewLeaf(t); OPB.StPar1(x, OPB.NewIntConst(1), decfn); SetPos(x);
  111. y^.link^.link := x; (* t := (B-x) div Step +1; INC(id,Step); DEC(t) *)
  112. END;
  113. END;
  114. CheckSym(do); StatSeq(s); (* дальше д б DO и тело цикла s *)
  115. IF t # NIL THEN
  116. IF s = NIL THEN
  117. s := y^.link; (* если тело цикла — пусто, то там д б только INC(id,Step); [ DEC(t) ] *)
  118. ELSIF (obj=NIL) OR (obj = id) THEN
  119. y^.link^.link := s; s:=y^.link; (* добавляем в начало тела цикла INC(n,Step); *)
  120. ELSE (* ищем конец тела цикла *)
  121. x := s;
  122. WHILE x^.link # NIL DO x := x^.link END ;
  123. x^.link := y^.link; (* добавляем в конец тела цикла INC(n,Step); [ DEC(t) ]*)
  124. END;
  125. END;
  126. CheckSym(end); (* в конце д б END *)
  127. IF t # NIL THEN
  128. IF obj # id THEN
  129. x := OPB.NewLeaf(t); OPB.Op(eql, x, OPB.NewIntConst(0)); (* условие "t = 0" "(id = 0)" *)
  130. ELSE
  131. x := OPB.NewLeaf(id);
  132. IF z^.conval^.intval > 0 THEN OPB.Op(gtr, x, OPB.NewIntConst(0)) (* условие id > 0 *)
  133. ELSIF z^.conval^.intval < 0 THEN OPB.Op(lss, x, OPB.NewIntConst(0)) (* или id < 0 *)
  134. END
  135. END;
  136. OPB.Construct(Nrepeat, s,x);SetPos(s); (* REPEAT ...UNTIL t=0; (id >0, id <0)*)
  137. y^.link := s; (* t := (B-x) div Step +1; REPEAT ... UNTIL t=0; *)
  138. IF y^.class = Nvar THEN (* фиктивный оператор *)
  139. s:=y^.link ; (* отбросим фиктивный оператор*)
  140. ELSE
  141. s:=y
  142. END;
  143. x := OPB.NewLeaf(id); (*начинаем строить условие IF*)
  144. IF t # id THEN y := OPB.NewLeaf(t)
  145. ELSIF obj = NIL THEN y := OPB.NewIntConst(0)
  146. ELSIF obj = id THEN y := z
  147. ELSE y:= OPB.NewIntConst( -z^.conval^.intval )
  148. END;
  149. END;
  150. (* y = <B> = "t" или "+-Step" (для условия IF) *)
  151. IF e OR (t = NIL) THEN x := OPB.NewBoolConst(TRUE)
  152. ELSIF z^.conval^.intval > 0 THEN OPB.Op(leq, x, y) (* условие id <= B *)
  153. ELSE OPB.Op(geq, x, y); (* или id >= B*)
  154. END ;
  155. ELSE (* цикл не выполнится ни разу*)
  156. CheckSym(do); StatSeq(s); (* дальше д б DO и тело цикла s *)
  157. x := OPB.NewBoolConst(FALSE);
  158. CheckSym(end);
  159. END;
  160. OPB.Construct(Nif, x, s); SetPos(x); lastif := x; (* строим IF id<=B THEN ...*)
  161. OPB.Construct(Nifelse, x, NIL); (* ветви ELSE нет*)
  162. OPB.OptIf(x); pos := OPM.errpos
  163. ELSE err(ident)
  164. END
Пришлось добавить к ранее введенным флажкам еще
    t=NIL, e=TRUE: цикл не выполнится ни разу (поэтому целиком отбрасывается)
    t=NIL, e=FALSE: цикл выполнится ровно 1 раз (поэтому превращается в id:=A;тело_цикла;
    t # NIL, e = TRUE: цикл выполнится хотя бы 1 раз (поэтому IF id <= B (или id >= B) THEN можно отбросить)
    t # NIL, e = FALSE: цикл выполнится неизвестное число раз (наиболее общий случай)
Пока это рабочий вариант. Мне не нравится, что получилось слишком запутанно, подумаю как исправить.
Сразу скажу, что подробно не тестировал. Случаев становится много, много признаков, флажков, условий. Необходим продуманный набор тестов.

_________________
А кроме того, я думаю, что корFORген должен быть разрушен!


Вернуться к началу
 Профиль  
Ответить с цитатой  
СообщениеДобавлено: 20 май 2013, 18:12 
Не в сети
Администратор
Аватара пользователя

Сообщения: 273
Откуда: Россия
И вот, пожалуйста, сразу выявилась проблема:
Код: "OBERON"
  1. MODULE Unsigned;
  2. IMPORT SYSTEM, P:=Platform, B := Basic;
  3. TYPE
  4. BYTE = SHORTINT;
  5. VAR
  6. byte: BYTE; (* -128..127 *)
  7. BEGIN
  8. FOR byte := -125 TO 2 BY 1 DO
  9. B.PRWORD(byte); B.PRCHAR(" ");
  10. END;
  11. END Unsigned.
дает "несовместимое присваивание". Если исправить FOR byte := -125 TO 1 BY 1 DO или FOR byte := -124 TO 2 BY 1 DO, то проходит. В чем проблема? В вычислении количества повторений. В общем случае, количество повторений не влезает в знаковый тип, даже если "А" и "В" принадлежат этому типу. В данном случае, число повторений, равно 2 - (-125) +1 =128 > 127 = MAX(SHORTINT). Раньше выражение t := 2 - (-125) +1 проходило в Си в неизменном виде. Но поскольку, мы стали свертывать константное выражение, Ofront видит t := 128 и сразу же протестует.

_________________
А кроме того, я думаю, что корFORген должен быть разрушен!


Вернуться к началу
 Профиль  
Ответить с цитатой  
СообщениеДобавлено: 20 май 2013, 21:15 
Не в сети
Аватара пользователя

Сообщения: 1019
Откуда: Днепропетровская обл.
А вот так работает:
Код: "OBERON"
  1. MODULE Unsigned;
  2. IMPORT P := Platform, B := Basic;
  3. VAR
  4. i: SHORTINT; (* -128..127 *)
  5. BEGIN
  6. FOR i := -125 TO P.Unsigned(2) BY 1 DO
  7. B.PRINT(i); B.PRCHAR(" ");
  8. END;
  9. END Unsigned.
Понимаю, что это не решение. Здесь надо бы чтобы переменная была беззнаковая. Или хотя бы объявлялась как знаковая, а интерпретировалась как без знака. И переполнение контролировалось с учётом этого.

Пока за отсутствием лучшей идеи предлагаю откатиться до:
Код: "C"
	Unsigned_i = -125;
Unsigned__for__1 = 2;
if (Unsigned_i <= Unsigned__for__1) { // Это можно убрать, если выражения константные и условие истинно.
Unsigned__for__1 = (Unsigned__for__1 - Unsigned_i) + 1; // А вот это пока что придётся оставить.
do {
// ...
Unsigned_i += 1;
Unsigned__for__1 -= 1;
} while (!(Unsigned__for__1 == 0));
}


Вернуться к началу
 Профиль  
Ответить с цитатой  
СообщениеДобавлено: 21 май 2013, 05:11 
Не в сети
Администратор
Аватара пользователя

Сообщения: 273
Откуда: Россия
Zorko писал(а):
А вот так работает:
Код: "OBERON"
  1. MODULE Unsigned;
  2. IMPORT P := Platform, B := Basic;
  3. VAR
  4. i: SHORTINT; (* -128..127 *)
  5. BEGIN
  6. FOR i := -125 TO P.Unsigned(2) BY 1 DO
  7. B.PRINT(i); B.PRCHAR(" ");
  8. END;
  9. END Unsigned.
Понимаю, что это не решение. Здесь надо бы чтобы переменная была беззнаковая. Или хотя бы объявлялась как знаковая, а интерпретировалась как без знака. И переполнение контролировалось с учётом этого.
Работает, потому что P.Unsigned(2) - не константа.
Цитата:
Пока за отсутствием лучшей идеи предлагаю откатиться до:...

Что же, уберем вычисление константных выражений при вычислении количества итераций. Для этого нужно вот так исправить фрагмент:
Код: "OBERON"
  1.  
  2. (* Переменные t и obj задают 4 случая цикла *)
  3. IF (t # id) & (t # NIL) THEN
  4. IF TRUE THEN
  5. x:= OPB.NewLeaf(t); OPB.Assign(x, y); SetPos(x); (* t := B*)
  6. OPB.Link(stat, last, x);
  7. END;
  8. pos := OPM.errpos; (* теперь ошибка будет указывать на шаг*)
  9. x := OPB.NewLeaf(id);
  10. (* z = "Step", x = "id", y = "B" *)
  11.  
  12. IF z^.conval^.intval > 0 THEN (* подготовим выражение "кол-во повторений" *)
  13. IF FALSE THEN
  14. x := OPB.NewIntConst( (y^.conval^.intval -apar^.conval^.intval) DIV z^.conval^.intval + 1)
  15. ELSE
  16. y:=OPB.NewLeaf(t);
  17. OPB.Op(minus, y,x); (* B-x *)
  18. OPB.Op(div, y, OPB.NewIntConst( z^.conval^.intval)); (* (B-x) div Step *)
  19. OPB.Op(plus, y, OPB.NewIntConst(1)); (* (B-x) div Step +1 *)
  20. x := y;
  21. END
  22. ELSIF z^.conval^.intval < 0 THEN (* в зависимости от знака Step*)
  23. IF FALSE THEN
  24. x := OPB.NewIntConst( (apar^.conval^.intval -y^.conval^.intval) DIV (-z^.conval^.intval) + 1)
  25. ELSE
  26. y:=OPB.NewLeaf(t);
  27. OPB.Op(minus, x, y); (* x-B *)
  28. OPB.Op(div, x, OPB.NewIntConst( -z^.conval^.intval)); (* (x-B) div Step *)
  29. OPB.Op(plus, x, OPB.NewIntConst(1)); (* (x-B) div Step +1 *)
  30. END
  31. ELSE err(63); OPB.Op(minus, x, y)
  32. END;
Так пока и оставим IF TRUE THEN, IF FALSE THEN, чтобы эти константы напоминали о необходимости переписать это место программы.

_________________
А кроме того, я думаю, что корFORген должен быть разрушен!


Вернуться к началу
 Профиль  
Ответить с цитатой  
СообщениеДобавлено: 21 май 2013, 21:21 
Не в сети
Администратор
Аватара пользователя

Сообщения: 273
Откуда: Россия
Попробуем такой подход к решению проблемы. Количество итераций влезет, в общем случае, только в беззнаковый тип, которого у нас нет. Однако, если мы сможем создать знаковую константу содержащую тот же набор битов, что у нужной нам беззнаковой, то проблема решена! Присвоим эту знаковую константу вспомогательной переменной и пусть она уменьшается до нуля декрементом на каждой итерации. Нуль для знаковой и беззнаковой совпадают, так что цикл выполнится нужное число раз.
По аналогии с OPB.NewIntConst и OPB.SetIntType создадим процедуры OPB.NewUnsignedConst и OPB.SetUnsignedType. Несмотря на их название они делают нечто прямо противоположное - создают знаковую константу, которая содержит ту же комбинацию битов, что и переданная в качестве параметра беззнаковая. Т.е. позволяют поместить в дерево нужную нам беззнаковую константу, закодировав ее в виде знаковой.
В модуле ОРВ после
Код: "OBERON"
  1. PROCEDURE SetIntType(node: OPT.Node);
  2. VAR v: INTEGER;
  3. BEGIN v := node^.conval^.intval;
  4. IF (OPM.MinSInt <= v) & (v <= OPM.MaxSInt) THEN node^.typ := OPT.sinttyp
  5. ELSIF (OPM.MinInt <= v) & (v <= OPM.MaxInt) THEN node^.typ := OPT.inttyp
  6. ELSIF (OPM.MinLInt <= v) & (v <= OPM.MaxLInt) (*bootstrap or cross*) THEN
  7. node^.typ := OPT.linttyp
  8. ELSE err(203); node^.typ := OPT.sinttyp; node^.conval^.intval := 1
  9. END
  10. END SetIntType;
  11.  
  12. PROCEDURE NewIntConst*(intval: INTEGER): OPT.Node;
  13. VAR x: OPT.Node;
  14. BEGIN
  15. x := OPT.NewNode(Nconst); x^.conval := OPT.NewConst();
  16. x^.conval^.intval := intval; SetIntType(x); RETURN x
  17. END NewIntConst;
  18.  
разместим наши новые процедуры, написанные по аналогии (по аналогии с OPB.NewIntConst,OPB.SetIntType и Рlatform.Unsigned):
Код: "OBERON"
  1. PROCEDURE SetUnsignedType(node: OPT.Node);
  2. (* превращает беззнаковую константу в знаковую *)
  3. VAR v: INTEGER;
  4. BEGIN v := node^.conval^.intval;
  5. IF (0 <= v) & (v <= 2*OPM.MaxSInt+2) THEN
  6. node^.typ := OPT.sinttyp;
  7. node^.conval^.intval := SHORT(SHORT (v ));
  8. ELSIF (0 <= v) & (v <= 2*OPM.MaxInt+2) THEN
  9. node^.typ := OPT.inttyp;
  10. node^.conval^.intval := SHORT (v );
  11. ELSE (* всё прочее - LINT. Дополнить, когда введем "настоящие" беззнаковые типы! *)
  12. node^.typ := OPT.linttyp;
  13. END
  14. END SetUnsignedType;
  15.  
  16. PROCEDURE NewUnsignedConst*(uintval: LONGINT): OPT.Node;
  17. (* создание новой знаковой константы, по соответствующей (кодируемой той же комбинацией битов)
  18. беззнаковой константе uintval *)
  19. VAR x: OPT.Node;
  20. BEGIN
  21. x := OPT.NewNode(Nconst); x^.conval := OPT.NewConst();
  22. x^.conval^.intval :=SHORT( uintval); SetUnsignedType(x); RETURN x
  23. END NewUnsignedConst;
Пояснения требует система целых типов, используемая Ofront в транслируемых им программах и система используемая средой BlackBox, в которой работает Ofront. Они задаются одинаковыми идентификаторами, но не совпадают!
Код: "OBERON"
  1. Целые типы Ofront
  2. SHORTINT (1 байт) INTEGER (2 байта) LONGINT (4 байта)
  3. MinSInt := -80H; MinInt := -8000H; MinLInt := 80000000H; (*-2147483648*)
  4. MaxSInt := 7FH; MaxInt := 7FFFH; MaxLInt := 7FFFFFFFH; (*2147483647*)
  5. ---------------------------------------------------------------------------------------------
  6. Целые типы BlackBox
  7. SHORTINT (2 байта) INTEGER (4 байта) LONGINT (8 байтов)
  8. MIN = -8000H; MIN := 80000000H; MIN := 8000000000000000H;
  9. MAX = 7FFFH; MAX := 7FFFFFFFH; MAX := 7FFFFFFFFFFFFFFFH;
Как видите, типы ББ в 2 раза шире, что позволяет внутри транслятора работать с повышенной точностью, обрабатывая константы в транслируемой программе без переполнения. Вернее так должно быть, но кое-какие трудности с большими числами мы увидим.
У процедуры NewUnsignedConst параметр uintval имеет тип LONGINT (тип ББ), что вроде бы должно без проблем обработать любые типы в транслируемой программе. Попробуем написать в модуле ОРР вместо
Код: "OBERON"
  1. x := OPB.NewIntConst( (y^.conval^.intval -apar^.conval^.intval) DIV z^.conval^.intval + 1)
  2. ...
  3. x := OPB.NewIntConst( (apar^.conval^.intval -y^.conval^.intval) DIV (-z^.conval^.intval) + 1)
вычисление количества итераций оператором
Код: "OBERON"
  1. x := OPB.NewUnsignedConst( (y^.conval^.intval -apar^.conval^.intval) DIV z^.conval^.intval + 1)
  2. ...
  3. x := OPB.NewUnsignedConst( (apar^.conval^.intval -y^.conval^.intval) DIV (-z^.conval^.intval) + 1)
Конечно, заменим IF TRUE и IF FALSE на прежнее IF ~e и IF e, соответственно.
Это вроде бы работает для Ofront-овских 1 и 2 байтовых целых типов, но как насчет LONGINT (4 байта)? Поля y^.conval^.intval, apar^.conval^.intval имеют тип ББ INTEGER (что соответствует Оfront-овскому LONGINT). По правилам ББ разность двух величин INTEGER есть величина INTEGER, однако y^.conval^.intval -apar^.conval^.intval в INTEGER может не вместиться. Попытка задать
Код: "OBERON"
  1. x := OPB.NewUnsignedConst( (LONG(y^.conval^.intval) -apar^.conval^.intval) DIV z^.conval^.intval + 1)
(если один из операндов разности имеет тип LONGINT, то результат имеет тип LONGINT), вызывает при компиляции ТРАП 0 (Dev)CPC486:
Код: "OBERON"
  1. PROCEDURE CheckAv* (reg: INTEGER);
  2. BEGIN
  3. ASSERT(reg IN WReg)
  4. END CheckAv;
Не совсем понятно почему? Что-то "не пролазит" в регистр ЦП? Жаль, получается что пока использовать тип LONGINT в цикле FOR нельзя. Конечно одно- и двух-байтовые величины в циклах важнее, но тем не менее... Если этот тип нельзя использовать в цикле, то нужно это оговорить в документации и выдавать ошибку компилятора. А уж если компилятор пропускает, то и обработка должна быть верная.
Что же, если сведение к большему типу при помощи LONG не работает, то обработку для этого случая следует произвести отдельно, специальным образом, избегая переполнений. Кстати, особой обработки требует и DIV (-z^.conval^.intval), ведь может быть z^.conval^.intval=MIN(INTEGER). Чему тогда равно (-z^.conval^.intval), ведь противоположного положительного числа нет? Этот особый случай тоже требует отдельного изучения. А пока можно тестировать FOR для 1 и 2-байтных типов.

_________________
А кроме того, я думаю, что корFORген должен быть разрушен!


Вернуться к началу
 Профиль  
Ответить с цитатой  
СообщениеДобавлено: 22 май 2013, 00:48 
Не в сети
Аватара пользователя

Сообщения: 1019
Откуда: Днепропетровская обл.
Zorko писал(а):
Значения MIN(T) и MAX(T) Офронт берёт из файла Obj/Ofront.par, и в подсистеме WinDev у меня не получается скомпилировать такой код:
Код: "OBERON"
  1. MODULE TestFor;
  2. VAR i: SHORTINT;
  3.  
  4. BEGIN
  5. i := 127+1; (* Здесь переполнение *)
  6. FOR i := -128 TO 129 DO (* А здесь тем более *)
  7. END;
  8. END TestFor.
Олег, оказывается, Ofront вообще не предполагает, что SHORTINT может быть чем-то отличным от байта, поэтому предлагаю такой коммит для решения этой проблемы.

Почему в WinDev размер типа SHORTINT составляет два байта? Думаю, это просто целесообразно. Для байта остаётся тип SYSTEM.BYTE, INTEGER логично сделать четырёхбайтовым, ибо такая арифметика наиболее эффективна для Intel 80386+. Чтобы сохранить возможность работать с двухбайтовыми значениями — остаётся только тип SHORTINT.


Вернуться к началу
 Профиль  
Ответить с цитатой  
СообщениеДобавлено: 22 май 2013, 17:04 
Не в сети
Администратор
Аватара пользователя

Сообщения: 273
Откуда: Россия
Zorko писал(а):
Олег, оказывается, Ofront вообще не предполагает, что SHORTINT может быть чем-то отличным от байта, поэтому предлагаю такой коммит для решения этой проблемы.

Почему в WinDev размер типа SHORTINT составляет два байта? Думаю, это просто целесообразно. Для байта остаётся тип SYSTEM.BYTE, INTEGER логично сделать четырёхбайтовым, ибо такая арифметика наиболее эффективна для Intel 80386+. Чтобы сохранить возможность работать с двухбайтовыми значениями — остаётся только тип SHORTINT.
Я предлагаю не трогать внутренние типы Ofront, неизвестно как они друг с другом связаны и во что выльется исправление. Например при реализации FOR предполагается, что SHORTINT - наименьший тип для параметра цикла (BYTE не подходит). Есть правило для определения типа целых констант - наименьший, в который влезет. Я бы не менял набор типов внутри самого Ofront, пусть остается как есть. А проблему предлагаю решить введением внешних типов - типов, которые программист пишет в программе, транслируемой Ofront по F11.
Т.е. идентификаторы внешних типов - это некие "алиасы" внутренних типов Ofront. Связь между внутренними и внешними типами настраивается отдельно для каждой платформы. Вот нужно сделать SHORTINT 2-байтовым - пожалуйста, настраиваем внешнее название SHORTINT на внутренний тип INTEGER. В результате Ofront читает идентификатор типа SHORTINT , а "видит" INTEGER, c которым и работает.
Единственная проблема может быть в сообщениях об ошибке, если есть сообщения с упоминаем конкретного "внутреннего" имени типа. Но это не так критично, ведь это просто текстовые сообщения. Мы можем их легко исправить, заменить все конкретные названия типа на "целый тип размера Х байтов", например.
Вот сейчас я размышляю о способах вычислении количества итераций цикла FOR без переполнения. Для этого смотрю на внутренности Ofront в операциях присваивания, контроля типов, определении типа целой константы и т.д. И, думаю, что исправления константы только в OPM.GetProperties() недостаточно. Так не лучше ли ввести систему внешних типов, а внутренности не править? Иначе мне придется проводить особые исправления в реализации FOR для ZXDev, и особые для WinDev, а особые для какой-то еще системы, потому что там своя разрядность. А так мы получаем единый Ofront, c единым внутренним набором типов. И реализацию FOR (и другие модификации) тоже не придется писать для каждой платформы отдельно.

Можно расширить систему типов Ofront, добавив новые внутренние типы (например большей разрядности, чем 4-байтовый LONGINT). Но сделать это надо так, чтобы не испортить имеющиеся. Жаль, что безнаковые простыми алиасами не введешь. Беззнаковые типы - иные по своей природе, это не изменение разрядности.

_________________
А кроме того, я думаю, что корFORген должен быть разрушен!


Вернуться к началу
 Профиль  
Ответить с цитатой  
СообщениеДобавлено: 22 май 2013, 21:46 
Не в сети
Аватара пользователя

Сообщения: 1019
Откуда: Днепропетровская обл.
В принципе, Ofront не препятствует задать размеры всех типов в файле Ofront.par, чем я активно пользуюсь, задавая двухбайтовый (для Z80) или четырёхбайтовый (для Wintel) размер типа INTEGER. Размер SHORTINT тоже берётся из Ofront.par, просто Дж.Темпл, видимо, никогда не предполагал, что он может быть двухбайтовым. Получается, что задавать разрядность типов в Ofront'е внешним конфигуратором — это его встроенная возможность. И, осмелюсь заметить, полезная. Ибо разрядность типов стандартом Оберона не зафиксирована.

Я уверен, что Дж.Темпл согласится и у себя ввести фикс под двухбайтовый SHORTINT. Хотя, похоже, он забил на развитие Ofront'а. :(

Так что предлагаю при доработке Ofront'а опираться на размер в байтах OPM.SIntSize, минимальное значение OPM.MinSInt и максимальное OPM.MaxSInt (для типа SHORTINT). Всё, что делает мой коммит, — это корректирует MinSInt и MaxSInt для предусмотренной и встроенной возможности иметь другой размер типа SHORTINT. Которая может быть полезной, ибо с если сделать SHORTINT байтовым — мы не сможем работать с двухбайтовыми переменными. Или ты предлагаешь сделать INTEGER тоже фиксировано двухбайтовым?

Когда мы компилим модуль подсистемой ZXDev — Ofront берёт Ofront.par из ZXDev/Obj (или ZXDev/Lib/Obj), а когда подсистемой WinDev, то он берётся из WinDev/Obj (или WinDev/Lib/Obj), так что здесь проблем нет. Так задумано. :)

Saferoll писал(а):
Я предлагаю не трогать внутренние типы Ofront, неизвестно как они друг с другом связаны и во что выльется исправление. Например при реализации FOR предполагается, что SHORTINT — наименьший тип для параметра цикла (BYTE не подходит).
:) Так мы это и не будем трогать. Пусть SHORTINT будет наименьшим. Но если нам надо активно юзать циклы с байтовыми счётчиками — мы пропишем новый размер в Ofront.par, засунем его в папку /Obj нашего проекта, и эта возможность позволяет нам сохранить гибкость при разработке. Нужно — откатимся к схеме типов 8-16-32. Не нужно — сохраним 16-32-64. Типа HUGEINT в Ofront'е нет. Да и в стандарте Оберона нет. Видимо, это расширение ETH Oberon (и AO, в котором INTEGER намертво 16-битный). Я уважаю Ofront как раз за его гибкость.

Saferoll писал(а):
Так не лучше ли ввести систему внешних типов, а внутренности не править?
Олег, ты заметь, насколько прост однострочный фикс под тип SHORTINT в два байта. Он как будто закрывает недоработанность Ofront'а: размер типа SHORTINT из Ofront.par читается, а значения переменных OPM.MinSInt и OPM.MaxSInt под него не фиксятся. Так что нам не нужно полагаться на константу -127 — что она всегда равна MIN(SHORTINT). Вот это неправильно будет. А достаточно взять просто значение переменной OPM.MinSInt, так что я даже слегка удивлён, что тебя здесь смущает. Ведь, заметь, это не константы, а переменные, не так ли?

Saferoll писал(а):
Иначе мне придется проводить особые исправления в реализации FOR для ZXDev, и особые для WinDev, а особые для какой-то еще системы, потому что там своя разрядность.
Так ты просто опирайся на значения переменных OPM.SIntSize, OPM.MinSInt и OPM.MaxSInt (для SHORTINT) и на OPM.IntSize, OPM.MinInt и OPM.MaxInt (для INTEGER). Ведь для типа INTEGER разрядность не зафиксирована в 2 байта. И коррекция MinInt и MaxInt под четырёхбайтовый тип в Ofront встроена, хотя, кажется, Темпл и не пользовался этой возможностью. Так что эти значения переменных для типа INTEGER зависят от конфигуратора Ofront.par.

Saferoll писал(а):
А так мы получаем единый Ofront, c единым внутренним набором типов. И реализацию FOR (и другие модификации) тоже не придется писать для каждой платформы отдельно.
Что ты, и так не придётся. :) Для разного размера INTEGER (2 или 4 байта) твой FOR уже и так работает.

Saferoll писал(а):
Можно расширить систему типов Ofront, добавив новые внутренние типы (например большей разрядности, чем 4-байтовый LONGINT). Но сделать это надо так, чтобы не испортить имеющиеся.
Кстати, да. Размер LONGINT для Wintel я бы конечно предпочёл сделать 64-битным. Это было бы полезно и для x86-64, и для ARM. И вписать в Ofront.par циферку 8 — не проблема, но чтобы это заработало — код, видимо, придётся серьёзно фиксить под эту возможность.

Saferoll писал(а):
Жаль, что безнаковые простыми алиасами не введешь. Беззнаковые типы - иные по своей природе, это не изменение разрядности.
Увы, это так. Тут наверное будут препятствия, которые надо серьёзно обдумать.


Вернуться к началу
 Профиль  
Ответить с цитатой  
СообщениеДобавлено: 23 май 2013, 20:18 
Не в сети
Администратор
Аватара пользователя

Сообщения: 273
Откуда: Россия
Zorko писал(а):
Олег, ты заметь, насколько прост однострочный фикс под тип SHORTINT в два байта. Он как будто закрывает недоработанность Ofront'а: размер типа SHORTINT из Ofront.par читается, а значения переменных OPM.MinSInt и OPM.MaxSInt под него не фиксятся. Так что нам не нужно полагаться на константу -127 — что она всегда равна MIN(SHORTINT). Вот это неправильно будет. А достаточно взять просто значение переменной OPM.MinSInt, так что я даже слегка удивлён, что тебя здесь смущает. Ведь, заметь, это не константы, а переменные, не так ли?
Меня смущает, что я до сих пор и не думал об изменении разрядности типов. :oops: Я работал только в системе ZXDev и только для типов 8-16-32. Поэтому очень легко написал непереносимый код, хотя и полагался на переменные Min\Max. Правда это касается только последней модификации, до этого рассуждения о FOR были достаточно общи и не зависели от разрядности типов. Далее меня смутила сама необходимость такого фикса. Ведь если это недоработано здесь, то может быть потребует изменений где-то еще?
Цитата:
Размер SHORTINT тоже берётся из Ofront.par, просто Дж.Темпл, видимо, никогда не предполагал, что он может быть двухбайтовым.

А вдруг это не просто забывчивость, а есть какие-то причины? Вдруг в каком-то месте Ofront существенно используется однобайтовость SHORTINT? Вот это тоже меня смущает.

Zorko писал(а):
В принципе, Ofront не препятствует задать размеры всех типов в файле Ofront.par, чем я активно пользуюсь, задавая двухбайтовый (для Z80) или четырёхбайтовый (для Wintel) размер типа INTEGER Получается, что задавать разрядность типов в Ofront'е внешним конфигуратором — это его встроенная возможность. И, осмелюсь заметить, полезная. Ибо разрядность типов стандартом Оберона не зафиксирована . …
Если сделать SHORTINT байтовым — мы не сможем работать с двухбайтовыми переменными. Или ты предлагаешь сделать INTEGER тоже фиксировано двухбайтовым?
По стандарту Оберона должно выполняться соотношение типов
SHORTINT <= INTEGER <=LONGINT,
Включение здесь нестрогое, т.е. INTEGER должно быть между SHORTINT и LONGINT, но может совпадать по разрядности с одним из них. Может теоретически быть совпадение и всех 3 типов, хотя на практике такие системы вряд ли нам встретятся. Учитывая текущие ограничения Ofront, имеем
INT8 <= SHORTINT <= INTEGER <=LONGINT <= INT32
Т.е. всего 3+3+1=7 возможных наборов целых типов (включая и тот вариант, когда все три однобайтовые ). И для всех этих вариантов Ofront должен давать правильный код.
Я же написал node^.conval^.intval := SHORT(SHORT (v )); что работает, только если соотношение типов 8-16-32.
Сам Ofront работает с 32-разрядным типом lint (соответствует типу ББ INTEGER), что позволяет совершать все операции, не опасаясь переполнений. А когда нужно сделать приведение типов или произвести проверку границ, Ofront опирается на значения OPM.SIntSize, OPM.MinSInt и OPM.MaxSInt, OPM.IntSize, OPM.MinInt и т.д. Это действительно переменные, устанавливаемые по файлу параметров Ofront.par.
Вчера мне показалось хорошей идеей иметь систему внутренних типов компилятора, фиксированной разрядности, а гибкость обеспечивать не заданием границ, а привязкой через файл параметров внешних алиасов типа к внутренним фиксированным. Т.е. написали в файле параметров SHORTINT=INT8 – стал SHORTINT однобайтовым, написали SHORTINT=INT16 – стал в 2 раза шире. А компилятор работает с INT8 или INT16, а до имени SHORTINT ему и дела нет. Но не подходит это для Оберона, где операции привязаны к ИМЕНИ типа. Недостаточно компилятору технических данных о разрядности, ему надо знать какой смысл программист в этот тип вкладывает - считает ли его маленьким, нормальным или большим. Вот как выполнять SHORT(INT32)? Должен тип на 1 ступеньку меньше получиться, а это не обязательно INT16, может быть INT32, а может и INT8. Привязкой алиасов в лучшем случае можно сохранить соотношение - переключаться с 8-16-32 на 16-32-64, что не подходит т.к. негибко, да и 64 нет пока. Поэтому не подходит система фиксированных типов с настройкой внешних алиасов. :(
Так что предлагаю проверить (протестировать) Ofront на случай 2-байтового SHORTINT (раз он 2-байтовым никогда не был, то и не тестировал этот случай никто). При модификации учитывать все возможные наборы целых типов, которые могут быть заданы через Ofront.par. (это я сам себе предлагаю, ты, Олег, видимо, это всегда учитывал :) )
Цитата:
Saferoll писал(а):
Иначе мне придется проводить особые исправления в реализации FOR для ZXDev, и особые для WinDev, а особые для какой-то еще системы, потому что там своя разрядность.
Так ты просто опирайся на значения переменных OPM.SIntSize, OPM.MinSInt и OPM.MaxSInt (для SHORTINT) и на OPM.IntSize, OPM.MinInt и OPM.MaxInt (для INTEGER). Ведь для типа INTEGER разрядность не зафиксирована в 2 байта. И коррекция MinInt и MaxInt под четырёхбайтовый тип в Ofront встроена, хотя, кажется, Темпл и не пользовался этой возможностью. Так что эти значения переменных для типа INTEGER зависят от конфигуратора Ofront.par.
Вот придется опираться, придется вместо X:=SHORT(Y) писать IF OPM.IntSize=2*OPM.SIntSize THEN X:=SHORT(Y) ELSE ..., потому, что типы Х и Y заранее известны, но неизвестны текущие разрядности этих типов в файле параметров. А вот была бы фиксированная система типов, было бы намного проще: X:=SHORT(Y) можно было бы написать сразу. , а в файле параметров задавались бы внешние имена типов. Но, увы, это не для Оберона. В Обероне операции привязаны именно к именам типов, без фиксации разрядности. Придется, внося модификации в Ofront, заранее думать об изменяющейся разрядности типов.
Цитата:
Saferoll писал(а):
А так мы получаем единый Ofront, c единым внутренним набором типов. И реализацию FOR (и другие модификации) тоже не придется писать для каждой платформы отдельно.
Что ты, и так не придётся. :) Для разного размера INTEGER (2 или 4 байта) твой FOR уже и так работает.
Увы, не работает...Свертка констант при помощи OPB.NewUnsignedConst и OPB.SetUnsignedType в предыдущем сообщении не работает для 4-байтовой переменной цикла. Да и для меньших типов работает, только если разрядность SHORTINT 8 бит, а INTEGER - 16 (из-за жесткого применения SHORT() и SHORT(SHORT()) без проверки соотношения разрядности). Придется переделать. Например, вот так:
Код: "OBERON"
  1. PROCEDURE SetUnsignedType(node: OPT.Node);
  2. (* превращает беззнаковую константу в знаковую *)
  3. VAR v: INTEGER;
  4. BEGIN v := node^.conval^.intval;
  5. IF (0 <= v) & (v <= 2*OPM.MaxSInt+2) THEN
  6. node^.typ := OPT.sinttyp;
  7. IF 4*OPM.SIntSize = OPM.LIntSize THEN node^.conval^.intval := SHORT(SHORT (v))
  8. ELSIF 2*OPM.SIntSize = OPM.LIntSize THEN node^.conval^.intval := SHORT (v)
  9. ELSE ASSERT (OPM.SIntSize = OPM.LIntSize )
  10. END
  11. ELSIF (0 <= v) & (v <= 2*OPM.MaxInt+2) THEN
  12. node^.typ := OPT.inttyp;
  13. IF 4*OPM.IntSize = OPM.LIntSize THEN node^.conval^.intval := SHORT(SHORT (v))
  14. ELSIF 2*OPM.IntSize = OPM.LIntSize THEN node^.conval^.intval := SHORT (v)
  15. ELSE ASSERT (OPM.IntSize = OPM.LIntSize )
  16. END
  17. ELSE (* всё прочее - LINT. Дополнить, когда введем "настоящие" беззнаковые типы! *)
  18. node^.typ := OPT.linttyp;
  19. END
  20. END SetUnsignedType;
  21.  
  22. PROCEDURE NewUnsignedConst*(uintval: LONGINT): OPT.Node;
  23. (* создание новой знаковой константы, по соответствующей (кодируемой той же комбинацией битов)
  24. беззнаковой константе uintval *)
  25. VAR x: OPT.Node;
  26. BEGIN
  27. x := OPT.NewNode(Nconst); x^.conval := OPT.NewConst();
  28. x^.conval^.intval :=SHORT( uintval); SetUnsignedType(x); RETURN x
  29. END NewUnsignedConst;
К сожалению, это будет работать только для 1 и 2 байтовых типов. Для 4-байтового возможно переполнение при вычислении количества итераций. Будем думать.
Цитата:
Размер LONGINT для Wintel я бы конечно предпочёл сделать 64-битным. Это было бы полезно и для x86-64, и для ARM. И вписать в Ofront.par циферку 8 — не проблема, но чтобы это заработало — код, видимо, придётся серьёзно фиксить под эту возможность.
Да, придется фиксить. Ввести еще 1 константу типа и переменные для ее границ тоже не сложно, задать conval^.intval:LONGINT тоже. Но вот что-то не работает LONGINT в ББ. Т.е. он вроде бы и есть, но вот пользоваться им так свободно, как прочими типами не получается - срабатывает ASSERT(reg IN WReg) в компиляторе ББ. Если уж в самом ББ 64-разрядность ограничена, то вряд ли нам удастся так легко ввести ее в Ofront.

_________________
А кроме того, я думаю, что корFORген должен быть разрушен!


Вернуться к началу
 Профиль  
Ответить с цитатой  
СообщениеДобавлено: 24 май 2013, 18:55 
Не в сети
Администратор
Аватара пользователя

Сообщения: 273
Откуда: Россия
Кратко напомню какая возникла проблема прошлый раз. При вычислении количества итераций оператором
Код: "OBERON"
  1. x := OPB.NewUnsignedConst( (LONG(y^.conval^.intval) -apar^.conval^.intval) DIV z^.conval^.intval + 1)
могло возникнуть переполнение в разности (y^.conval^.intval-apar^.conval^.intval), что искажало результат при последующем делении. Попытка перейти к типу большей разрядности при помощи LONG() вызывало ТРАП 0 (Dev)CPC486 компилятора ББ.
Сейчас удалось обойти эту особенность компилятора ББ при помощи вспомогательной переменной L: LONGINT, описание которой добавил в начало процедуры OPP.StatSeq
Код: "OBERON"
  1. PROCEDURE StatSeq(VAR stat: OPT.Node);
  2. VAR fpar, id, t, obj: OPT.Object; idtyp: OPT.Struct; e: BOOLEAN; L : LONGINT;
  3. s, x, y, z, apar, last, lastif: OPT.Node; pos: INTEGER; name: OPS.Name;

А само вычисление количества повторений проведем теперь так:
Код: "OBERON"
  1. ...
  2. IF z^.conval^.intval > 0 THEN (* подготовим выражение "кол-во повторений" *)
  3. IF e THEN
  4. L := LONG(y^.conval^.intval) -apar^.conval^.intval;
  5. L := L DIV z^.conval^.intval +1;
  6. x := OPB.NewUnsignedConst( SHORT(L));
  7. ELSE
  8. y:=OPB.NewLeaf(t);
  9. OPB.Op(minus, y,x); (* B-x *)
  10. OPB.Op(div, y, OPB.NewIntConst( z^.conval^.intval)); (* (B-x) div Step *)
  11. OPB.Op(plus, y, OPB.NewIntConst(1)); (* (B-x) div Step +1 *)
  12. x := y;
  13. END;
  14. ELSIF z^.conval^.intval < 0 THEN (* в зависимости от знака Step*)
  15. IF e THEN
  16. L:= LONG(apar^.conval^.intval) -y^.conval^.intval;
  17. L := L DIV (-LONG(z^.conval^.intval)) +1; (* обязательно -LONG(...), иначе ошибка для z^.conval^.intval=MIN(INTEGER) *)
  18. x := OPB.NewUnsignedConst( SHORT(L));
  19. ELSE
  20. y:=OPB.NewLeaf(t);
  21. OPB.Op(minus, x, y); (* x-B *)
  22. OPB.Op(div, x, OPB.NewIntConst( -z^.conval^.intval)); (* (x-B) div Step *)
  23. OPB.Op(plus, x, OPB.NewIntConst(1)); (* (x-B) div Step +1 *)
  24. END
  25. ELSE err(63); OPB.Op(minus, x, y)
  26. END ;
Поскольку мы теперь не передаем выражение LONGINT в процедуру OPB.NewUnsignedConst, то и параметр этой процедуры изменим на INTEGER:
Код: "OBERON"
  1.  
  2. PROCEDURE SetUnsignedType(node: OPT.Node);
  3. (* превращает беззнаковую константу в знаковую *)
  4. VAR v: INTEGER;
  5. BEGIN v := node^.conval^.intval;
  6. IF (0 <= v) & (v <= 2*OPM.MaxSInt+2) THEN
  7. node^.typ := OPT.sinttyp;
  8. IF 4*OPM.SIntSize = OPM.LIntSize THEN node^.conval^.intval := SHORT(SHORT (v))
  9. ELSIF 2*OPM.SIntSize = OPM.LIntSize THEN node^.conval^.intval := SHORT (v)
  10. ELSE ASSERT (OPM.SIntSize = OPM.LIntSize )
  11. END
  12. ELSIF (0 <= v) & (v <= 2*OPM.MaxInt+2) THEN
  13. node^.typ := OPT.inttyp;
  14. IF 4*OPM.IntSize = OPM.LIntSize THEN node^.conval^.intval := SHORT(SHORT (v))
  15. ELSIF 2*OPM.IntSize = OPM.LIntSize THEN node^.conval^.intval := SHORT (v)
  16. ELSE ASSERT (OPM.IntSize = OPM.LIntSize )
  17. END
  18. ELSE (* всё прочее - LINT. Дополнить, когда введем "настоящие" беззнаковые типы! *)
  19. node^.typ := OPT.linttyp;
  20. END
  21. END SetUnsignedType;
  22.  
  23. PROCEDURE NewUnsignedConst*(uintval: INTEGER): OPT.Node;
  24. (* создание новой знаковой константы, по соответствующей (кодируемой той же комбинацией битов)
  25. беззнаковой константе uintval *)
  26. VAR x: OPT.Node;
  27. BEGIN
  28. x := OPT.NewNode(Nconst); x^.conval := OPT.NewConst();
  29. x^.conval^.intval := uintval; SetUnsignedType(x); RETURN x
  30. END NewUnsignedConst;
  31.  
Интересно, что попытка соединить в одном операторе и разность и деление
Код: "OBERON"
  1. L := (LONG(y^.conval^.intval) -apar^.conval^.intval) DIV z^.conval^.intval +1;
вызывает ТРАП 0 (Dev)CPC486 компилятора ББ! Ну и ладно, не хочет вместе, посчитаем по отдельности.
Но есть еще один тонкий момент для случая отрицательного шага:
Код: "OBERON"
  1. L := L DIV (-LONG(z^.conval^.intval)) +1;(* обязательно -LONG(...), иначе ошибка для z^.conval^.intval=MIN(INTEGER) *)
Перед применением операции "унарный минус" необходимо преобразовать величину шага к большей разрядности. В противном случае для z^.conval^.intval=MIN(INTEGER) получим неверный результат, потому что в типе INTEGER для этого значения нет противоположного, MIN(INTEGER) само себе противоположно. А вот у LONGINT есть положительное число равное (-MIN(INTEGER)), поэтому и результат деления будет верным.
Кстати, обратите внимание как записывается константа MIN(INTEGER) в С-исходнике : (-2147483647-1). В построенном дереве это константа уже свернута (-2147483648), но при генерации С-программы Ofront "разворачивает" эту константу в разность (-2147483647-1).
Слегка потестировал, вроде бы теперь верно сворачивает константы и для 4-байтового параметра. Остались еще небольшие оптимизации, но сначала подумаю как "структуризировать" фрагмент OPP.StatSeq, относящийся к циклу FOR (этот фрагмент сейчас превышает по размеру построение всех остальных операторов вместе взятых!). Короче он вряд ли станет, но, надеюсь, станет яснее.

_________________
А кроме того, я думаю, что корFORген должен быть разрушен!


Вернуться к началу
 Профиль  
Ответить с цитатой  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 72 ]  На страницу Пред.  1, 2, 3, 4, 5, 6 ... 8  След.

Часовой пояс: UTC + 2 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 4


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  
cron
Создано на основе phpBB® Forum Software © phpBB Group
© VEDAsoft Oberon Club