Forum in READ ONLY mode! All questions and discussions on Discord official server, invite link: https://discord.gg/VxsGzJ7

Как искать и устранять ошибки в скриптах

Часто задаваемые вопросы
Post Reply
User avatar
Vizit0r
Developer
Developer
Posts: 3958
Joined: 24.03.2005 17:05
Contact:

Как искать и устранять ошибки в скриптах

Post by Vizit0r »

терпеть не могу писать руководства, да и не умею. а приходится.


итак, поехали.

в компиляторе стелса (как и в компиляторе паскаля) существует 2 типа "ошибок" (неправильный термин, но все же).
а) Error - "Compiler: [Error]" - это критическая ошибка, скрипт не будет выполняться до тех пор пока ошибка не будет устранена. основные причины описаны ниже.
б) Hint - "Compiler: [Hint]" - напоминание, подсказка
например
22:03:47 Compiler: [Hint] (11.sc at 4:1): Variable 'DT' never used
появляется по причине того, что в переменных dt объявлено

Code: Select all

var
dt:TDateTime;
а дальше в коде нигде не используется.
как правило(НЕ ВСЕГДА!), можно удалять.
другой пример:
23:01:04 Compiler: [Hint] (11.sc at 7:10): Variable 'Result' never used
почему это появляется?
пример:

Code: Select all

Program New;

function fgfg (a : Word) : String;
begin
//тут что-то делается
Result := ??? (что-то);
end;

BEGIN //Main begin
...
fgfg(12); 
углубимся ненадолго в понятие функций и процедур.
function SomeFunction (xxx : varType) : SomeType;
begin
///что-то тут делается, вычисляется, неважно.
Result := какое-то_значение (зависит от типа);
end;
означает, что функция вернет значение, которое записано в Result.

procedure SomeFunction (xxx : varType);
begin
///что-то тут делается, вычисляется, неважно.
end;
НИЧЕГО не возвращает. вообще. если попробовать присвоить Result что-то - выругается.

так что если в двух словах - function возвращает значение, procedure - нет.
итак, в данном случае мы имеем вызов функции, которая возвращает значение String - но оно никому не нужно - банально не используется. это не критическая ошибка, скрипт выполнится - но все же так делать не стоит.
в данном примере правильно было бы:

Code: Select all

Program New;

procedure fgfg (a : Word);
begin
//тут что-то делается
end;

BEGIN //Main begin
...
fgfg(12); 
I) общие ошибки:

1) Unknown identifier 'хххх' - неправильно написанное название функции\процедуры либо служебного идентификатора (например findTyp вместо findType или beg in вместо begin)

2) Identifier expected 'хххх' незаконченная предыдущая строка (либо наоборот, преждевременно законченое выражение), а ошибку соответственно показывает на следующей строке.
например

Code: Select all

if X > 1 then
  begin
    ...
  end;
else  // <== ошибка приведет сюда, не на end; !!!!
  ..
хотя на самом деле ошибка в том, что предыдущей строке стоит ; в конце строки - и закрывается условие.
возможны вариации, но общая суть примерна такова.

3) Out Of Range
одна из любимых юзверями ошибок - потому что не ведет в конкретное место, а просто выдается и все.
ошибка выхода за диапазон.
причина возникновения:
обращение к ячейке массива, которая находится вне объявленного диапазона.
пример:

Code: Select all

var
a : array [0..1] of Word;
...
begin
a[2] := 3;
a обьявлено как массив из двух элементов - 0 и 1. а я обращаюсь к 2 элементу - а его не существует. вот и здрасте.

4) List index out of bounds
тоже горячо любимый пользователями error:

Code: Select all

var
a : TStringList;
...
begin
a := TStringList.Create;
UOSay('buy');
a := GetShopList;
//да, предполагается, что наш стринглист заполнился.
// да, опытный скриптер поставит проверку типа if a.Count > 0 then...
// а неопытный (в случае если что-то не сработало и стринглист НЕ заполнится) - получит при обращении, например к a.Strings[1] красивую ошибку
[quote]Exception: List index out of bounds (2) at 0.85[/quote]
// ну пустой этот стринглист, пустой. нет у него даже нулевой строки, не говоря уж за третью...
a.Free;
если коротко - ВСЕГДА проверяйте наличие строки(обьекта и т.п.) в List (стринглист, либо какой-то другой List).

5) Type mismatch
несовпадение типов:
1) самое банальное - сравнивать разные типы, например String сравнивать с Word.
a : String;
b : Word;
....
if a <> b then // а вот и ошибка - ведь типы совсем разные.
2) if X=0 and Y = 0 then //и тут ошибка. почему?
а все потому, что в условиях ОБЯЗАТЕЛЬНО надо разные условиях ограждать скобками.
в данном случае
if( X=0) and (Y = 0) then //ошибки не вызовет.
if ( (X = 0) and (Y = 0) ) or ( (Z = 0) and ( not (W = 0)) ) then //правильно

Кстати, одно условие можно скобками не ограждать -
if X=0 then
не будет ошибкой, а очень даже нормально выполнится.

6) Semicolon (';') expected
Пример
Compiler: [Error] (Taming.sc at 19:1): Semicolon (';') expected
В 99 процентах случаев это значит, что в конце предущей строки отсутствует точка с запятой. просто поставить и все.
Last edited by Vizit0r on 19.04.2010 8:28, edited 13 times in total.
"Пишите код так, как будто сопровождать его будет склонный к насилию психопат, который знает, где вы живете". (с) Макконнелл, "Совершенный код".
User avatar
Vizit0r
Developer
Developer
Posts: 3958
Joined: 24.03.2005 17:05
Contact:

Post by Vizit0r »

некоторые частные ошибки.

Compiler: [Error] (11.sc at 32:4): period ('.') expected
отсутствует завершающий end. (конец программы)
пример

Code: Select all

Program New;
begin
while (not dead) do
//что-то
end;  { while }
end; // <== а здесь ошибка - должно быть "end." !
Compiler: [Error] (11.sc at 11:1): 'BEGIN' expected
отсутствует основной begin. внимательно проверить все пары begin-end
Unexpected end of file
внимательно проверить все пары begin-end, потому что какая-то пара незакрыта и захватывается завершающий "end."
"Пишите код так, как будто сопровождать его будет склонный к насилию психопат, который знает, где вы живете". (с) Макконнелл, "Совершенный код".
User avatar
Vizit0r
Developer
Developer
Posts: 3958
Joined: 24.03.2005 17:05
Contact:

Post by Vizit0r »

итак, со скриптом происходит что-то неправильное. например, завершает работу, хотя не должен. какие-то неправильные значения. или еще какая фигня

Надо найти строку, где происходит фигня.

самый банальный вариант, который я использую достаточно часто и который меня до сих не подводил:

Code: Select all

AddToSystemJournal('циферка');
использовать примерно так:

Code: Select all

Program New;
begin
AddToSystemJournal('1');
Step(2,True);
AddToSystemJournal('2');
Exit;
AddToSystemJournal('3');
end.
здесь я задал явный выход, но суть в общем-то понятна - в сисжурнал придут сообщения "1", "2", а вот "3" не придет - значит проблема где-то между 2 и 3. весьма удобно в поиске глючных мест.

То же самое с поиском неправильных значений

Code: Select all

Program New;
var a : Byte;
begin
a := Step(2,True);
AddToSystemJournal('StepResult : '+ intToStr(a));
end.
и так после каждой подозрительной функции.
смотрим, что же пишется в сисжурнал. ага, вот здесь возвращается что-то не то, что должно было бы. здесь и нужно значит ковырять.


если скрипт большой или очень большой с функциями\процедурами дополнительными, то стоит начать с возвращаемых значений функций, а дальше потрошить ту, что возвращает неправильное значение.

и так далее, и тому подобное.



Так же в отладке весьма неплохо помогают TestVars.
Для тех кто не помнит\не знает - напоминаю

Code: Select all

procedure SetGlobal(GlobalRegion: String; VarName: String; VarValue: String); // Установка глобальной переменной, где 
GlobalRegion - Область переменной ('stealth' - глобалка видна любому скрипту любого чара, 'char' - глобалка видна только для скриптов этого чара); 
VarName - Имя переменной; 
VarValue - Значение переменной. 
в области глоб. пер. Stealth есть 5 заранее определенных названий переменных - от TestVar1 до TestVar5, при задании им значений - они автоматически появляются на закладке Main стелса в разделе ScriptVars
таким образом, вместо
AddToSystemJournal('StepResult : '+ intToStr(a));
можно сделать
SetGlobal('stealth',TestVar1);
и посмотреть на возвращаемой значение в закладке Main Стэлса.
"Пишите код так, как будто сопровождать его будет склонный к насилию психопат, который знает, где вы живете". (с) Макконнелл, "Совершенный код".
gloomia
Neophyte
Neophyte
Posts: 10
Joined: 12.07.2011 7:58
Location: Киев
Contact:

Re: Как искать и устранять ошибки в скриптах

Post by gloomia »

Code: Select all

12:01:16:373 [Satan]: Invalid Opcode at 0.161
12:01:16:383 [Satan]: Script NA_CAST_ItIdent_SSpeak.sc stopped successfuly
Это выдает после остановки скрипта вручную.
Что может быть?

Code: Select all

Program New;
uses allinc;

var 
  i: Integer; 
  Casting, Worked: Boolean; 
  Friends: array of Cardinal; 

Const
SS = $0000;


procedure DoCast(Character: Cardinal); 
begin 
  //пример каста заклинаний на игрока. 
  CheckLag(15000); 
  if TargetPresent then CancelTarget; 
  Cast('Bless'); 
  CheckLag(15000); 
  WaitForTarget(5000); 
  TargetToObject(Character); 
  CheckLag(15000); 
  Wait(3000);
  if TargetPresent then CancelTarget; 
  Cast('Agility'); 
  CheckLag(15000); 
  WaitForTarget(5000); 
  TargetToObject(Character); 
  CheckLag(15000); 
  Wait(3000); 
end; 


procedure OnSpeech(Text, SenderName: String;  SenderID: Cardinal); 
begin 
  if (not Casting) and (Text = 'Cast!') then begin 
    if Worked then begin
     while Worked do 
      begin
       Wait(1000);
      end;
    end;
    for i := 0 to Length(Friends) - 1 do begin 
      if i >= Length(Friends) then Break; 
      if SenderID = Friends[i] then begin 
        Casting := True; 
        DoCast(SenderID); 
        Casting := False; 
        Break; 
      end; 
    end; 
  end; 
end; 


begin
  SetARStatus(true);
  AddToSystemJournal('Обкаст персов по команде Cast!, Индифицирование вещей, спирит спик.');
  AddToSystemJournal('Мы стартанули. Проверяем реги на полу, проверяем контейнеры.');
  // Только наши чары. Другие нам не надо.
  SetLength(Friends, 7);  // C 0 по 6 - это 7 элементов.
  Friends[0] := $001A4247;
  Friends[1] := $001A6D9A;
  Friends[2] := $001A9554;
  Friends[3] := $001AB33D;
  Friends[4] := $001AB340;
  Friends[5] := $001AB342; 
  Friends[6] := $001A4274; 
  SetEventProc(evUnicodeSpeech, 'OnSpeech'); 
  SetEventProc(evSpeech, 'OnSpeech'); 
  while not Dead do 
  begin 
    if not Connected then 
    begin 
      Connect; 
      Wait(5000); 
      Continue; 
    end;
    hyngry(1,-1);
    Worked := True;
    Wait(10000);
    
  
     
  end; 
  SetEventProc(evUnicodeSpeech, ''); 
  SetEventProc(evSpeech, ''); 
end.
end.
Что то с эвентами? Где можно подробнее посмотреть коды ошибок?

З.Ы. В allinc - стандартные инклуды, просто мне модулем подключать лучше.
User avatar
Vizit0r
Developer
Developer
Posts: 3958
Joined: 24.03.2005 17:05
Contact:

Re: Как искать и устранять ошибки в скриптах

Post by Vizit0r »

если это можно повторить - стучись ко мне в асю.
"Пишите код так, как будто сопровождать его будет склонный к насилию психопат, который знает, где вы живете". (с) Макконнелл, "Совершенный код".
Post Reply