Elite Games - Свобода среди звезд!
.
  » Трансляторы XC->XASM и XASM->XC | страница 2
Конференция предназначена для общения пилотов. Для удобства она разделена на каналы, каждый из которых посвящен определенной игре. Пожалуйста, открывайте темы только в соответствующих каналах и после того, как убедитесь, что данный вопрос не обсуждался ранее.

Поиск | Правила конференции | Фотоальбом | Регистрация | Список пилотов | Профиль | Войти и проверить личные сообщения | Вход

   Страница 2 из 4
На страницу: Пред.  1, 2, 3, 4  След. | Все страницы
Поиск в этой теме:
Канал X2: The Threat: «Трансляторы XC->XASM и XASM->XC»
BVOne
 100 EGP

Репутация: 12
Сообщения: 496
Откуда: Кишинев, Молдова
Зарегистрирован: 07.12.2005
Darth Revan :
Сначала примени дизассемблер CheckerTwo, получишь x2intro.out и x2intro.asm. А затем уже можно использовать xa2c.exe.


Ну, вопервых, я думаю, об этом стоило упомянуть в описании, а не вводить людей в заблуждение. Во-вторых, не вижу причин, мешающих юзать дизасм программно, из xa2c.exe, а на вход транслятору подавать *.obj файлы.
    Добавлено: 19:31 19-01-2007   
Darth Revan
 345 EGP


Рейтинг канала: 5(153)
Репутация: 42
Сообщения: 349
Откуда: Belarus Prime
Зарегистрирован: 01.02.2006
S.A. :
Ну, вопервых, я думаю, об этом стоило упомянуть в описании, а не вводить людей в заблуждение.
В ридмишнике всё написано, читай внимательнее. Улыбка
S.A. :
не вижу причин, мешающих юзать дизасм программно, из xa2c.exe, а на вход транслятору подавать *.obj файлы.
Можно и так, но всё равно придётся в ini дизассемблера dobj.ini параметры выставлять. Конечно, и dobj.ini программно можно установить, и др. Сделать можно вообще много чего мало полезного, в то время как нужных задач до дури.
    Добавлено: 22:48 19-01-2007   
Shaddie
 555 EGP


Рейтинг канала: 4(60)
Репутация: 118
Сообщения: 259
Откуда: Томск
Зарегистрирован: 09.09.2004
Darth Revan :
Если это касается только XASM->XC транслятора, то никаких проблем - могу сделать в любом виде. Итак, меняю...
Было просто замечательно Улыбка.
Да еще для конструкции if нужно then добавить.
_________________
Быстро едешь, тихо понесут...
    Добавлено: 00:01 20-01-2007   
BVOne
 100 EGP

Репутация: 12
Сообщения: 496
Откуда: Кишинев, Молдова
Зарегистрирован: 07.12.2005
Darth Revan :
В ридмишнике всё написано, читай внимательнее.


Написано, ниже. А в описании ни слова.
    Добавлено: 00:04 20-01-2007   
Darth Revan
 345 EGP


Рейтинг канала: 5(153)
Репутация: 42
Сообщения: 349
Откуда: Belarus Prime
Зарегистрирован: 01.02.2006
А как сдвиги << и >> делать?
2 S.A. Написано в использовании, где кстати и должно. Или ты наугад проги юзаешь? Улыбка
    Добавлено: 00:05 20-01-2007   
Shaddie
 555 EGP


Рейтинг канала: 4(60)
Репутация: 118
Сообщения: 259
Откуда: Томск
Зарегистрирован: 09.09.2004
Darth Revan :
А как сдвиги << и >> делать?
<< на shl
>> на shr
_________________
Быстро едешь, тихо понесут...
    Добавлено: 00:14 20-01-2007   
Darth Revan
 345 EGP


Рейтинг канала: 5(153)
Репутация: 42
Сообщения: 349
Откуда: Belarus Prime
Зарегистрирован: 01.02.2006
Жди через полчаса. Сделаю пока отдельным файлом.
    Добавлено: 00:20 20-01-2007   
Darth Revan
 345 EGP


Рейтинг канала: 5(153)
Репутация: 42
Сообщения: 349
Откуда: Belarus Prime
Зарегистрирован: 01.02.2006
Darth Revan :
Жди через полчаса.

Улыбка Решил заодно убрать в нескольких местах постановку лишних скобок.

xa2c.rar
 Описание:
Транслятор XASM->XC Версии 1.01.01 альфа.
 Имя файла:  xa2c.rar
 Размер файла:  38.55 KB
 Скачано:  633 раз(а)
xa2c_pas.rar
 Описание:
Транслятор XASM->XC Версии 1.01.01 альфа. Версия с выводом результата в паскалеподобном виде.
 Имя файла:  xa2c_pas.rar
 Размер файла:  36.63 KB
 Скачано:  634 раз(а)
    Добавлено: 02:34 20-01-2007   
Shaddie
 555 EGP


Рейтинг канала: 4(60)
Репутация: 118
Сообщения: 259
Откуда: Томск
Зарегистрирован: 09.09.2004
Есть пара пожеланий.

1. begin и end сдвинуть влево на один знак табуляции:
Сейчас так:
Код:

function TX_AUDIO.GetSpeechPriority()
 begin
 if TX_AUDIO.current_speak_sample then
  begin
  return(TX_AUDIO.current_speak_prio);
  end
 return(-1000);
 end

Так лучше:
Код:

function TX_AUDIO.GetSpeechPriority()
begin
 if TX_AUDIO.current_speak_sample then
 begin
  return(TX_AUDIO.current_speak_prio);
 end
 return(-1000);
end


2. Тернарную операцию записывать не так:
Код:
arg1-1163596833<0?-(arg1-1163596833):arg1-1163596833

а так:
Код:
?(arg1-1163596833<0,-(arg1-1163596833),arg1-1163596833)

_________________
Быстро едешь, тихо понесут...
    Добавлено: 02:17 27-01-2007   
Darth Revan
 345 EGP


Рейтинг канала: 5(153)
Репутация: 42
Сообщения: 349
Откуда: Belarus Prime
Зарегистрирован: 01.02.2006
Shaddie :
1. begin и end сдвинуть влево на один знак табуляции:

У меня мелькнула такая мысль.
Всё сделаю.
    Добавлено: 01:22 29-01-2007   
Darth Revan
 345 EGP


Рейтинг канала: 5(153)
Репутация: 42
Сообщения: 349
Откуда: Belarus Prime
Зарегистрирован: 01.02.2006
Сделал два мелких исправления в трансляторе XC->XASM: не читались отрицательные константы в constants и требовались дополнительные скобки для выражений вида a[i]=b=c. Исправил и перевожу в бету.
    Добавлено: 05:32 23-02-2007   
AlexYar
 1712 EGP


Рейтинг канала: 6(412)
Репутация: 338
Сообщения: 27580

Зарегистрирован: 26.10.2003
Darth Revan :
RunNamedFunction: (functionName:2, arg:0, argType:1, retValue:5, retType:6)
{
код
}
jump RunNamedFunctionRet;


А можно поподробнее про выделенное красным? Что это, зачем и с чем едят (в смысле - что значат те или иные цифры там)? Улыбка
В сях такого синтаксиса не нашёл...

Кстати, а как кодокопатели узнали о "exe-функциях"? Или известны только те, ссылки на которые есть в обжах?

А можно как-нить встроить прямо в обжи транслятор, чтобы игра сразу файлы с функциями в формате хс понимала? Гы-гы
Можно было бы одновременно и новые функции пейсать, и проверять сразу в игре, не тратя время на компиляцию и перезагрузку игры Ну...
    Добавлено: 00:10 23-05-2007   
AlexYar
 1712 EGP


Рейтинг канала: 6(412)
Репутация: 338
Сообщения: 27580

Зарегистрирован: 26.10.2003
После работы XC исчезли части имён строковых переменных.
От "XA.Loc.Pilons" осталось только Pilons".

Цитата:

get_strg Pilons"


ХС сказал, что всё зашибись, а xa_asm отослал к едрене фене, мол:

Цитата:
pass2:(x3story_XA.inc:239483) Err: Undefined identifier 'Pilons'.


Пришлось переделывать по-другому Расстроен

Исходная строка на ХС была такой:

var data=this->GetScriptVarObjLocal(string."XA.Loc.Pilons");

Это я накосячил, или в ХС бага? Может ему точки мои не понравились? Вроде точки как точки... Гы-гы В описании вроде нигде не сказано, что между кавычками в именах строковых переменных нельзя ставить точки...
    Добавлено: 05:12 28-05-2007   
AlexYar
 1712 EGP


Рейтинг канала: 6(412)
Репутация: 338
Сообщения: 27580

Зарегистрирован: 26.10.2003
...
А вот и косяк Гы-гы


Darth Revan :
Условные операторы: switch.

Оператор switch имеет синтаксис и применение, отличающееся от используемого в C++.

switch(выражение)
{
case (число0)
{
код
}
case (число1)
{
код
}
...
case (числоn)
{
код
}
}

Если указано n+1 блоков case, то числа число0, число1, ..., числоn должны быть перестановкой множества {0,1,...,n}. Иными словами, должны присутствовать все варианты выбора от 0 до n. Переход по case(0) осуществляется в случае выхода проверяемого выражения за границы множества (т.е. если значение выражения > n), поэтому этот case должен всегда присутствовать. Числа после case можно не указывать (в этом случае круглые скобки не ставятся), тогда числа в case нумеруются в естественном порядке, начиная с последнего указанного номера или нуля, если это первый блок.
В отличие от C++, в конце блока case осуществляется выход из switch. Оператор break внутри case действует как обычно, т.е. осуществляет выход не из switch, а из текущего цикла.


Фигу там Прыгаю от радости

На самом деле xc.exe обрабатывает переходы именно по принципу С++ Улыбка И точно так же xa2c транслирует стандартные иксовые функции.
Если не будет поставлен "break;" в конце блока "case", то код будет выполняться и дальше, пока не будет встречен первый "break;".

Т.е. такая конструкция:

var loc1=2;
switch(loc1)
{
case 2:
{
loc1=2;
}
case 3:
{
loc1=3;
}
case 4:
{
loc1=4;
break;
}
case 5:
{
break;
}
}

И в итоге loc1 чему равно? Нифига не 2 Гы-гы, loc1=4 ! По крайней мере в игре такая конструкция после cpp->asm->obj работает именно так.

Может из-за этого проблемы с декомпиляцией обжей, написанных на ХС ?

Вот код, написанный Шадди для команды perform operation. Если бы было так, как написано в описании вверху, то тогда бы всё работало ок. Однако это не так Нет Код нерабочий!

Цитата:

case 124: //PlSilentJump
{
global.drPlayerJumpToSector(obj);
}
case 125: //ShipRotateTo
{
SA_RotateToAngles(obj->GetObjectID(),par1[1],par1[3],par1[5]);
obj->GetPos();
}
case 126: //SetSpeedLimit
{
var loc28=par1*500;
obj->SetSpeedLimit2(loc28);
var loc29=obj->GetObjectID();
if(loc29)
{
SA_SetSpeedLimit(loc29,loc28);
}
}
case 127: //EnableSectorDust
{
obj->EnableDustGenerator(par1);
}
case 128: //SetBgNebulaBody


При выполнении команды PlSilentJump срабатывают все команды по порядку! Наиболее это заметно по тому, что в секторе пропадает космоперхоть (результат работы команды EnableDustGenerator).

Если же потом специально включить дуст командой EnableDustGenerator, а потом отдать команду PlSilentJump - получаем мёртвый вис D3D до нажатия Reset Расстроен

Поэтому в конце каждого блока case нужно обязательно ставить "break;", если мы не хотим последовательного выполнения кода.

Цитата:
Переход по case(0) осуществляется в случае выхода проверяемого выражения за границы множества (т.е. если значение выражения > n), поэтому этот case должен всегда присутствовать.


Не должен. По крайней мере во многих функциях Егософта его нет.
Пример - TX_AUDIO.PlaySpeechFaceDirect. В случае выхода проверяемого выражения за границы множества - переходов по case не будет в таких случаях. Егософт case 0 иногда ставит последним , что подтверждает последовательность переходов (вариант с++).

( сразу скажу, что настройка SwitchAutoBreaks = 1 в xc.ini не помогает, т.е. не работает, но если бы она и работала, то тогда бы вообще вся таблица переходов была бы испорчена).

Вот кусок тестового кода, можно вставить прямо в начало функции TCLIENT.Run , откомпилировать обж и начать новую игру. Потом заходим в папку \debug, смотрим и думаем Улыбка

Цитата:

// Проверка case<>switch

var locTest=0;

switch(locTest)
{
case 0:
{
SE_WriteFile("debug/case0.txt","ok");
}
case 1:
{
SE_WriteFile("debug/case1.txt","ok");
}
case 2:
{
SE_WriteFile("debug/case2.txt","ok");
}
case 3:
{
SE_WriteFile("debug/case3.txt","ok");
}
case 4:
{
SE_WriteFile("debug/case4.txt","ok");
}
case 6:
case 7:
case 41:
case 59:
{
SE_WriteFile("debug/case59.txt","ok");
break;
}
}


Отсюда наверное и растут ноги у несовместимости xa_asm->dobj.

Поправьте меня, если я чего-то не того написал.

Последний раз редактировалось: AlexYar (18:28 29-05-2007), всего редактировалось 2 раз(а)
    Добавлено: 18:07 29-05-2007   
AlexYar
 1712 EGP


Рейтинг канала: 6(412)
Репутация: 338
Сообщения: 27580

Зарегистрирован: 26.10.2003
Darth Revan :
Оператор break внутри case действует как обычно, т.е. осуществляет выход не из switch, а из текущего цикла.


Здесь, кстати, тоже неправильно. Если циклов нет, то по break происходит выход из switch. Иначе никак не выйти, чтобы не выполнялись следующие case.
    Добавлено: 18:20 29-05-2007   
AlexYar
 1712 EGP


Рейтинг канала: 6(412)
Репутация: 338
Сообщения: 27580

Зарегистрирован: 26.10.2003
Еще буг-репорт небольшой. Такая строка:

string=arrayString+")\r\n\n;

- приводит xa.exe в тупик Расстроен Вылетает даже без попытки объяснения причин, поэтому отловить баг крайне затруднительно.
Если его можно научить выдавать ошибку с указанием строки - было бы очень хорошо Улыбка (кто не заметил - отсутствует закрывающая кавычка, т.е. ошибка синтаксиса).

Есть и альтернативный выход - юзать Crimson Editor для правки кода, у него есть широкая возможность настраивать подсветку ключевых слов и конструкций (я настроил текст между кавычек показывать красным, поэтому пропуск закрывающей кавычки сразу заметен при написании кода).

зыж Но в целом претензий к ХА нет, всё работает ок. А любые трудности всегда можно обойти Улыбка Респект автору.
    Добавлено: 01:21 31-05-2007   
AlexYar
 1712 EGP


Рейтинг канала: 6(412)
Репутация: 338
Сообщения: 27580

Зарегистрирован: 26.10.2003
Вопрос есть такой. В обже все классы начинаются с буквы Т.
Это обязательное условие, или можно по-другому называть?

Еще вопрос - как создавать новые классы? Какое им в константах десятичное значение присваивать? От балды, лишь бы не совпадало с имеющимися? Или его можно вообще не указывать, если не предполагается использовать конструкции типа "new(NUMBER)->create" ?


зыж Для кодописателей будет полезно знать, что если не заbreakовать последний CASE в конструкции SWITCH, то транслятор упадёт, при этом выдаст сообщение об ошибке, которой на самом деле нет.

Пример: если написать так

switch(loc1)
{
case 0:
{
break;
}
case 1:
{
loc2=3
break;
}
case 2:
case 3:
}


то транслятор дойдёт до первой функции после объявления следующего класса вниз по коду и скажет, что она должна быть defined in the global scope.

На самом деле функция та не при чём, а виноват именно незабрикованный кейз.

Отловить такой баг в своём коде несложно, если учитывать то, что я написал выше.
    Добавлено: 19:04 04-06-2007   
Darth Revan
 345 EGP


Рейтинг канала: 5(153)
Репутация: 42
Сообщения: 349
Откуда: Belarus Prime
Зарегистрирован: 01.02.2006
AlexYar :
Кстати, а как кодокопатели узнали о "exe-функциях"? Или известны только те, ссылки на которые есть в обжах?

И те, которые в доке описаны. В целом, почти все понятны.

AlexYar :
А можно как-нить встроить прямо в обжи транслятор, чтобы игра сразу файлы с функциями в формате хс понимала?

Можно было бы одновременно и новые функции пейсать, и проверять сразу в игре, не тратя время на компиляцию и перезагрузку игры


Тут без компиляции не обойтись. Почему я говорю, что патч надо ращбивать на две части. Основная, на основе дезассемблированного обжа, и маленькая дополнительная, ставящаяся уже поверх первого. Во второй части по возможности надо стараться часто меняющиеся или тестовые вещи делать. Тогда можно тесты и прочее делать, компилируя маленький патч и загружая с сохранения. Т.е. секунд тридцать, и изменение уже можно тестировать в игре. Свму игру (т.е. экээшник) перезапускать вообще не нужно. Обж x*story.obj грузится при старте новой игры или загрузке с сохранения.

AlexYar :
Исходная строка на ХС была такой:

var data=this->GetScriptVarObjLocal(string."XA.Loc.Pilons");


А надо

var data=this->GetScriptVarObjLocal("XA.Loc.Pilons");

string тут не нужен. В целом, форму со string можно считать устаревшей.

AlexYar :
На самом деле xc.exe обрабатывает переходы именно по принципу С++ И точно так же xa2c транслирует стандартные иксовые функции.
Если не будет поставлен "break;" в конце блока "case", то код будет выполняться и дальше, пока не будет встречен первый "break;".

Есть pragma-константа SwitchAutoBreaks. Значение 0 - не вставляет автоматически break, 1 - вставляет. Для кода обжей в начало файла вставляется
#pragma {SwitchAutoBreaks=0;}
поскольку в обжах есть пару мест, где действительно break нет, т.е. два блока выполнятся подряд. Для собственного кода удобно выставлять SwitchAutoBreaks=1. Т.е. в xc.ini ставим SwitchAutoBreaks=0, а в своём файле, где хотим использовать режим автобрэйка в конце блока, делаем, например, так:
#pragma {SwitchAutoBreaks=1;}
код
#pragma {SwitchAutoBreaks=default;}

Кстати, если ращместить две директивы pragma внутри одной функции, то они не отработают так, как ожидается. Т.е. например,
function f()
{
код
#pragma {some_parameter=0;}
код
#pragma {some_parameter=1;}
код
}
оттранслируется со значением {some_parameter=1;}

AlexYar :
Darth Revan :

Оператор break внутри case действует как обычно, т.е. осуществляет выход не из switch, а из текущего цикла.


Здесь, кстати, тоже неправильно. Если циклов нет, то по break происходит выход из switch. Иначе никак не выйти, чтобы не выполнялись следующие case.

Имелся в виду случай, когда внутри case есть циклы. Т.е. break выбрасывает из ближайщего блока case или цикла, в зависимости от того, какой ближе (и какой, собственно, присутсвует). Точно так же break(2) выбрасывает из второго по вложености и т.д.

Пример использования break с параметром. Допустим, имеется что-нибудб подобное следующему коду:
Код:
var f=0;
for(var i=0;i<10;i=i+1)
 {
 if(a[i]>0)
  {
  f=1;
  break;
  }
 }
if(f==1)
 {
 код
 }

Любители использования меток могли бы написать так:
Код:
for(var i=0;i<10;i=i+1)
 {
 if(a[i]>0)
  {
  goto l1;
  }
 }
goto l2;
l1:
 код
l2:


Это чуть эффективнее, но некрасиво и при разрастании использования таких приёмов приводит к снижению читаемости кода. Всё равно goto в XC нет. Отчасти и поэтому. Зато то же самое можно написать так:
Код:
while
 {
 while
  {
  for(var i=0;i<10;i=i+1)
   {
   if(a[i]>0)
    {
    break(2);
    }
   }
  break(2);
  }
 код
 break;
 }


Это эквивалентно
Код:
for(var i=0;i<10;i=i+1)
 {
 if(a[i]>0)
  {
  goto l1;
  }
 }
goto l2;
l1:
 код
 goto l2
l2:


Ну, это для примера. Улыбка Часто можно проще (с одним дополнительным блоком). А как правило просто не нужно. С другой стороны, достанет большое число флагов...

AlexYar :
Еще буг-репорт небольшой. Такая строка:

string=arrayString+")\r\n\n;

- приводит xa.exe в тупик

А ты попробуй пропусти точку с запятой в конце оператора, будет ещё круче. Улыбка А в данном случае фишка в том, что здесь точка с запятой считается частью строки и, соответственно, просмотр идёт до закрывающейся кавычки. А она на самом деле открывающаяся. В строки попадают операторы и т.д. Это сложная ошибка, её трудно отследить. Это одно из больных мест обработки ошибок. Самое больное - отсутствие точки с запятой в конце оператора. А в целом, они на каждом шагу, проблемы эти.

AlexYar :
Вопрос есть такой. В обже все классы начинаются с буквы Т.
Это обязательное условие, или можно по-другому называть?
Те, которые есть, лучше не трогать, там некоторые методы из экзэшника вызываются, и имя привязано. А вообще, можно любые, но лучше с T, поскольку иначе, если ты сделаешь патч к файлу с новыми классами, то их не получиться использовать в патче, поскольку в xasm.ini имена прописываются без T, и T потом приписывается ассемблером.

AlexYar :
Еще вопрос - как создавать новые классы? Какое им в константах десятичное значение присваивать? От балды, лишь бы не совпадало с имеющимися?

Угу. Выбери себе число, не очень большое, и начиная с него нумеруй. Пропиши, лучше в файле констант, константу, совпадающую с именем класса, и назначь ей значение, совпадающее с этим id.

AlexYar :
зыж Для кодописателей будет полезно знать, что если не заbreakовать последний CASE в конструкции SWITCH, то транслятор упадёт, при этом выдаст сообщение об ошибке, которой на самом деле нет.

Пример: если написать так

switch(loc1)
{
case 0:
{
break;
}
case 1:
{
loc2=3;
break;
}
case 2:
case 3:
}

Проблема не в break, а в том, что каждый case (или их группа) должен иметь блок (пусть и пустой). Это так же, как if/else. Это исключительно проблемы транслятора, т.е. так мне было проще транслятор писать. Есть, конечно, некоторые неудобства. Если в связи с последующими версиями иксов потребуется серьёзная доработка транслятора, то я попытаюсь улучшить. Просто там придётся достаточно серьёзные изменения делать в таким местах кода, что могут пойти баги, а этого не хочется делать с отлаженным траслятором. Возвращаясь к примеру, можно написать так:
Код:
switch(loc1)
{
case 0:
{
break;
}
case 1:
{
loc2=3;
break;
}
case 2:
case 3:
{
}
}


AlexYar :
Darth Revan :
Переход по case(0) осуществляется в случае выхода проверяемого выражения за границы множества (т.е. если значение выражения > n), поэтому этот case должен всегда присутствовать.


Не должен. По крайней мере во многих функциях Егософта его нет.


Верно. Я изменил в одной из версий генерацию switch (собственно, когда потребовалось приводить транслятор к более нормальному виду из-за необходимости созлания замены KC-коду), так что если для значения блок case отсутствует, то осуществляется переход в конец switch (т.е. аналог пустого блока с break).
    Добавлено: 03:23 06-08-2007   
Darth Revan
 345 EGP


Рейтинг канала: 5(153)
Репутация: 42
Сообщения: 349
Откуда: Belarus Prime
Зарегистрирован: 01.02.2006
Extern-функции.

Реализована поддержка внешних (extern) функций. По сути, осуществляется некоторый аналог связывания (link), что позволяет упростить раздельное ассемблирование файлов. Дело в том, что с появлением ассеблера, могущего полностью ассемблировать обж и, как следствие, сборки обжей целиком, появились и свои проблемы. По сути, проблем две: во первых, большой asm-файл, содержащий многие сотни тысяч строк, медленно компилируется. Вторая проблема - сдвиг адресов при изменении файла. Если такое изменение происходит не в самом конце обжа, то практически гарантированно новый обж будет несовестим со тарыми сохранениями.

Естественный способ преодоления этих неудобств - разбиение большого файла asm-файла (соответственно, и xc-кода) как минимум на две части - основная, содержащая практически весь код игры, и дополнительная, небольшая, содержащая код, находящийся в отладке, часто меняемый код и др. Имеется в виду не просто разделение файлов на модули, а разделение на две группы так, чтобы можно было их ассеблировать по отдельности (можно считать, что при ассеблировании все модули сливаются в один файл). Соответственно, вссемблирование идёт в два приёма: сначала ассемблируется большой основной файл, а затем маленький, причём второй ассеблируется как патч к обжу, сгенерированному на первом этапе. Соответсвенно, меняя второй asm-файл, нет необходимости ассемблировать первый, и, как следствие, небольшое время компиляции и, при определённых, как правило выполняющихся условиях, будет и совместимость сохранений. Впрочем, это решает лишь часть проблемы, поскольку далеко не весь нужный код из большого файла легко перенести в файл-патч: если мы переносим некоторую функцию из основного файла в маленький, то эту функцию становится невозможно напрямую вызвать из основного файла. Действительно, в основном файле она уже не определена, а патч присоединяется к обжу уже после того, как последний будет создан. Иными словами, функции, определённые в основном обже, без проблем доступны из патча, но в обратную сторону всё не так радужно, поскольку у ассемблера просто нет информации о вызываемой функции (этой функции на момент ассемблирования просто ещё нет). В некоторых случаях может спасти полифорфизм, поскольку для виртуальных функций происходит динафическое связывание (уже на этапе выполнения); в иных случаях оставалось городить огород. Поэтому я решил сделать возможность внешнего связывания на уровне транслятора xc, позволяя организовывать вызов xc-функций, определённых в патчах, из основного файла и не занимаясь собственноручно возьнёй с адресами и дополнительным кодом.

Все дополнительные действия по связыванию происходят на этапа xc-трансляции и ассемблирования. На этапе же выполнения вызов extern-функции требует всего одной дополнительной инструкции.

Объявление и определение.

Объявление и имплементацию extern-функций можно осуществить двумя способами.

Первый способ. Для объявления extern-функции в основном обже достаточно приписать к ней префикс extern. Такое объявление должно заканчиваться точкой с запятой. Например,

Код:
extern function TMONITORCONTROL.OverlayLoop();


Теперь основной обж будет ассемблироваться при том, что тело функции TMONITORCONTROL.OverlayLoop() при ассемблировании ещё отсутствует.

Чтобы имплементировать extern-функцию в коде обжа-патча, достаточно приписать к ней префикс implement. Например,

Код:
implement function TMONITORCONTROL.OverlayLoop()
 {
 код
 }


Второй способ. Имеется возможность автоматизировать экспортирование функций из xc-кода основного обжа в обжи-патчи. Для этого необходимо вынести код функций, предназначенных для экспорта в отдельный файл(ы) и подключить их как к xc-коду основного обжа, так и к xc-коду патча, причём перед подключением необходимо использовать директиву #pragma с параметром FuncAutoExportMode. В зависимости от значения этого параметра все функции, которые дальше встретятся транслятору, будут им рассматриваться как объявление extern-функции (FuncAutoExportMode=extern), либо как имплементация (FuncAutoExportMode=implement). Значение FuncAutoExportMode=none переключает трансляцию функций в обычный режим.

Пусть, например, в файлах file1.xc и file2.xc имеется некоторый набор функций основного обжа. Чтобы быстро их все сделать extern-функциями и добиться того, чтобы их код прописывался в обже-патче, а не основном обже, достаточно строки в xc-коде основного обжа

Код:
#include "file1.xc";
#include "file2.xc";


заменить на

Код:
#pragma {FuncAutoExportMode=extern;}
#include "file1.xc";
#include "file2.xc";

#pragma {FuncAutoExportMode=none;}[/code]

В xc-код обж-патча следует добавить строки

Код:
#pragma {FuncAutoExportMode=implement;}
#include "file1.xc";
#include "file2.xc";

#pragma {FuncAutoExportMode=none;}[/code]

Как видно из примера, код для обж-патча отличается лишь значением параметра FuncAutoExportMode директивы #pragma. Если экспортировать функции, скажем, находящиеся в файле file1.xc в обж-патч больше не требуется, то можно сделать, например, следующие небольшие изменения в xc-коде основного обжа

Код:
#include "file1.xc";
#pragma {FuncAutoExportMode=extern;}
#include "file2.xc";

#pragma {FuncAutoExportMode=none;}[/code]

и xc-коде обж-патча

Код:
#pragma {FuncAutoExportMode=implement;}
//#include "file1.xc";
#include "file2.xc";

#pragma {FuncAutoExportMode=none;}[/code]

Применительно ко второму способу создания extern-функций следует иметь в виду, что код из файлов между директивами #pragma участвует в ассемблировании обоих обжей. Поскольку транслятор xc обратывает все определения функций в этих файлах, то их тела дважды ассемблироваться, конечно, не будут. Однако этого нельзя сказать об описании классов, глобальных функций или переменных. Указанные описания должны производится только в главном обже, так что можно если они есть в указанных файлах, то следует либо переместить из в какое-нибудь другое место в коде главного обжа, например, отдельным файлом, и подключить его перед первой директивой #pragma, либо использовать директивы условного ассемблирования.

Файлы линковки.

Для осуществления линковки extern-функций транслятор генерирует и использует дополнительную информацию. Часть этой информации - таблица адресов - храниться в самом главном обже, другая часть - в дополнительных файлах.

Таблица адресов. Таблица адресов используется транслятором для хранения адресов extern-функций. Поэтому для использования возможности создания extern-функций необходимо эту таблицу создать. Проще всего это сделать в самом начале asm-файла основного обжа. Если основной файл в asm-формате, то это нужно сделать, например, добавив сразу после директив .extern ассемблера следующие строки:

Код:
           .include   "addr_table.inc"

_AddressTableBegin
_AddressTable50Elements
_AddressTableEnd


В случае, если asm-файла основного обжа генерируется xc-транслятором, то последние строки нужно оформить в виде ассемблерной вставки:

asm
{
_AddressTableBegin
_AddressTable50Elements
_AddressTableEnd
}[/code]

Первая строка кода подключает файл с макросами, три последних строки - собственно макросы для создания таблицы. _AddressTableBegin и _AddressTableEnd - макросы для указания начала и конца таблицы. В середине может быть один или несколько макросов из списка

Код:
_AddressTable10Elements
_AddressTable50Elements
_AddressTable100Elements
_AddressTable500Elements


Например, для создания таблицы на двухста элементов можно записать так:

Код:
           .include   "addr_table.inc"

_AddressTableBegin
_AddressTable100Elements
_AddressTable100Elements
_AddressTableEnd


Если по каким-либо причинам таблицу адресов желательно разместить не в самом начале основного файла, то в соответствующих xc-файлах для основного обжа и патча(патчей) следует использовать директиву

Код:
#pragma {LinkTableAddress=адрес;}


где адрес - адрес начала данных таблицы. Для таблицы, созданной в начале файла при помощи указанных макросов, LinkTableAddress=20.

По мере создания extern-функций транслятор будет последовательно заполнять таблицу адресов. В случае, если необходимо зарезервировать часть таблицы для собственного использования, можно указать транслятору номер последней зарезервированной ячейки, так что адреса начнут записываться со сделующей. Для этого необходимо использовать директиву #pragma с параметром FuncAutoExportSlot. Например, директива

Код:
#pragma {FuncAutoExportSlot=1;}


означает, что транслятор начнёт заполнять адреса со второй ячейки. По умолчанию FuncAutoExportSlot=0. Следует отметить, что директива не будет иметь эффекта, если значение FuncAutoExportSlot задано меньшим, чем текущее значение счётчика адреса. Иными словами, транслятор не начнёт перезаписывать таблицу.

Для контроля над возможностью переполнения таблицы служит директива #pragma с параметром LinkTableSize. Например, директива

Код:
#pragma {LinkTableSize=500;}


сообщит транслятору, что в таблице 500 элементов. Если будет переполнение, т.е. транслятор попытается записать в ячейку с номером выше указанного в директиве, то быдут выдана ошибка.

Дополнительные файлы. При объявлении extern-функций их имена и номера использованных ячеек в таблице адресов заносятся в специальный файл с тем же именем, что и корневой транслируемый файл (т.е. тот файл, имя которого передаётся в качестве аргумента транслятору) и с расширением lnk. В начале xc-кода обж-патча имя этого файла (без расширения) следует указать в качестве значения параметра LinkFile директивы #pragma. Например, если xc-код основного обжа транслировался при помощи строки xc main.xc, то в начале xc-кода следует указать

Код:
#pragma {LinkFile=main;}


Замечания.

1. Экспортировать можно как функции-члены классов, так и глобальные функции с любым числом параметров.

2. Вызов extern-функций происходит также, как и обычных функций. Если в основном обже объявить некоторую extern-функцию, но не определить её в обжах патчах, то при вызове такая extern-функция вернёт нуль.

3. В принципе, обжей-патчей к основному обжу может быть любое число. Они применяются последовательно. При изменении кода в некотором патче (в том числе в коде основного обжа), необходимо переассеблировать все последующие, но не нужно переассемблировать предыдущие.

4. Если обжей-патчей несколько, то в них также можно объявлять extern-функции. В этом случае в xc-код обж-патчей следует добавлять директиву #pragma с параметрами LinkTableSize для всех предыдущих относительно порядка ассемблирования файлов. Одну и туже функцию следует объявлять extern-функцией лишь один раз, даже если она используется в других обж-патчах: если функция объявлена как extern-функция, то она становится видимо во всех последующих по порядку ассемблирования обж-патчах вне зависимости от того, в каком обж-патче она определяется; extern-функция, определённая в основном обже, видима везде.

5. В коде обжа-патча может быть как объявление, так и имплементация некоторой extern-функции. Однако настоятельно не рекомендуется имплементировать extern-функции в коде основного обжа. В принципе, последнее - совершенно бессмысленное занятие, поскольку функции основного обжа могут быть вызваны из обжа-патча обычным образом.


Блок '_'.

Добавлена поддержка блока _ (нижнее подчёркивание). Это такой же блок, как и блок без названия, т.е. сам по себе он не добавляет никакого кода, лишь создавая дополнительную область видимости переменных. Однако, в отличие от пустого блока, он считается уровнем при переходах break и continue. Может использоваться, например, для организации структурных безусловных переходов.

Например, достаточно часто встречается необходимость использования безусловного перехода в ситуации такого типа:

Код:
while(условие1)
 {
 код1
 if(условие2)
  {
  код2
  goto label;
  }
 код3
 }
код4
label:


Поскольку неструктурные переходы не поддерживаются, альтернативой как правило является использование флага.

Код:
var f=0;
while(условие1)
 {
 код1
 if(условие2)
  {
  код2
  f=1;
  break;
  }
 код3
 }
if(!f)
 {
 код4
 }


При помощи блока _ это можно записать по другому, причём код будет сгенерирован такой же, как в случае использования безусловного перехода:

Код:
_{
 while(условие1)
  {
  код1
  if(условие2)
   {
   код2
   break(2);
   }
  код3
  }
 код4
 }



Оператор double.

Добавлен оператор double для задания констант с плавающей точкой (8 байт). Формат константы обычный. Например,

Код:
var x=double(-1.2);
var y=x*double(1.4e+10);


Для чисел с плавающей точкой поддерживаются только арифметические операции. Результатом арифметической операции целого числа и числа с плавающей точкой будет число с плавающей точкой. Следующий пример иллюстрирует приведение целого числа к числу с поавающей точкой:
Для перевода целого числа в число

Код:
var integer=10;              //int
var db11=integer+double(0);  //double
var d0=double(0);
var db12=integer+d0;         //double


Для приведения числа с плавающей точкой к целому служит функция SE_ToInt.


Другие дополнения.

Теперь можно объявлять локальные переменные, явно не задавая начальное значение. В этом случае переменные инициируются нулём. Например,

Код:
var x,y,z;



Убрана генерация транслятором ряда недостижимого кода.

Новая версия в первом посте.
    Добавлено: 20:09 29-08-2007   
Darth Revan
 345 EGP


Рейтинг канала: 5(153)
Репутация: 42
Сообщения: 349
Откуда: Belarus Prime
Зарегистрирован: 01.02.2006
Багфикс для транслятора xa2c и небольшое связанное с этим обновление транслятора xc.

Каюсь, давно должен был исправить. Я подозревал о том, что что-то с xa2c не так с самого начала, но не был уверен, и неглубокие поиски ошибок ничего не давали. В X3 на транслированном xa2c и xc обже вроде есть висы, потом в патче вроде их как бы и нет. Спасибо AlexYar, я понял, что проблема точно есть. Пришлось дихотомией локализовывать функцию, которая вешает X3. Оказалось, что это функция TQUEST194.__GetParseTemplates. Вынужден признаться, проблема не оказалась неожиданной. Задним умом я помню, что когда я писал урезание и свёртку тернарных операторов в логичекие И и ИЛИ для транслятора xa2c, я засомневался, что всё будет всегда правильно работать и хотел подумать над этим, но на том этапе ещё вообще не понятно было, получится ли вообще завершить транслятор xa2c. И если условия, при которых происходило преобразование тернарных операций в логические И и ИЛИ были достаточно приемлимыми, то с обработка тернарных операций вида A?1:0, где A - некоторое выражение, производилось отвратительно, а именно, производились небезопасные преобразования такого выражения к A. Поясню.

В оригинальных обжах конструкция A?1:0, где A - некоторое выражение, встречается очень часто. В подавляющем большинстве случаев она используется для приведению выражения к булевскому типу в логических операциях И и ИЛИ. Для примера рассмотрим логическое И. Egosoft КС выражение A&&B, где A и B - некоторые выражения, представляет примерно следующим образом: A?(B?1:0):0. Ясно, что если результат выражения B является булевым, т.е. может принимать только значения 0 или 1, то тернарная операция B?1:0 является излишней. В действительности, именно так обычно и происходит - B является либо логической операцией над другими выражениями, либо операцией сравнения других выражений. Аналогично, тернарная операция B?1:0 может быть опущена, если известно, что либо результат выражения A?(B?1:0):0 является булевым, либо он, например, используется в каком-нибудь условном операторе. В результате оригинальные обжи оказываются перегружены большим количеством лишним сравнений. Как мы видим, в большинстве случаев их можно избежать, используя упрощенную представление выражения A&&B - A?B:0.

Тем не менее, в большинстве случаев не означает всегда. Поскольку в обжах переменные имеют вариантный тип, и программно уследить за типом конкретной переменной не всегда возможно, то встречаются случаи, когда невозможно определить, будет ли значение вырадения B всегда булевым, даже если реально оказывается, что это всегда так. В этих сравнительно редких случаях выражение A?(B?1:0):0 восстанавливается транслятором xa2c с сохранением тернарной операции B?1:0.

Например, если есть две переменных A и B, причём неизвестно о значениях, которые может принимать B, то выражение if(A?(B?1:0):0) может быть восстановлено в виде if(A&&B), в то время как выражение var C=A?(B?1:0):0 можно упростить лишь до вида var C=A&&B?1:0 (приоритет у тернарной операции выше, чем у логического И, так что сначала выполниется приведение B к булевскому типу B?1:0).


Для того, чтобы не перегружать код, выдаваемый транслятором xa2c, в транслятор xc введена возможность неявного преобразования переменных к булевскому типу в логических операциях И и ИЛИ. Для управления этой возможностью используется директива #pragma с параметром SafeLogicalOps. Если SafeLogicalOps=1, то результат логических операций И и ИЛИ, если он не используется непосредственно в каком-нибудь операторе, проверяющем условия (if, while, второй оператор в for), гарантированно примет булево значение, т.е. при необходимости будет произведено преобразование к булевскому типу B?1:0. Так что выражение var C=A&&B будет транслироваться как var C=A&&B?1:0. Соответственно, опция командной строки -skipbc, которую можно передавать в качестве третьего параметра транслятору xa2c, указывает транслятору xa2c, что xc-код на выходе будет транслироваться с включённым автоприведением к булевскому типу вторых параметров логических операций И и ИЛИ (в начало выходного xc-файла вставляется директива #pragma {SafeLogicalOps=1;}) и, следовательно, соответствующие явные приведения B?1:0 к булевому типу опускаются в выходном xc-файле.


Как уже отмечалось, различия, которые получаются в выходном коде при включёнии и выключении опции -skipbc проявляются достаточно редко. Рассмотрим пример. Применим транслятор xa2c к файлам x3story.asm и x3story.out при включенной и выключенной опциях -skipbc. Соответственно, первое встречающееся различие в файлах x3story.xc находится в функции function TSECTOR.FindStation.

Опция -skipbc включена. Видим одну из строк кода:

var loc8=arg4&131072&&SE_IsClass(arg5,2004);

Опция -skipbc выключена.

var loc8=arg4&131072&&SE_IsClass(arg5,2004)?1:0;

В данном случае мы, кстати, видно, что различие скорее всего не существенно, поскольку функция SE_IsClass скорее всего возвращает только значения 1 или 0. Как правило, так и случается, что различие не существенно.

Далее, при pragma-параметре SafeLogicalOps=1 транслятора xc для первого случая сгенерированный код будет делать то же самое, что и сгенерированный код для второго случая (с тернарной операцией), причём второй код будет xc-траеслироваться одинаково вне зависимости от значения SafeLogicalOps. А вот первый код при SafeLogicalOps=0 xc-оттранслируется по-другому, так что никакого приведения значения SE_IsClass(arg5,2004) к булевому не будет. Опять же, в данном случае это не принципиально, поскольку SE_IsClass(arg5,2004) и так булево, но, вообще говоря, вместо SE_IsClass(arg5,2004) может оказаться выражения, принимающее произвольные значения.

Таким образом, если мы производили xa2c-трансляцию с включённой опцией -skipbc, то полученный xc-код надо xc-транслировать с параметром #pragma {SafeLogicalOps=1;} (последняя директива автоматически добавляется в начало xc-файла). Если же -skipbc был отключен, то параметр SafeLogicalOps можно устанавливать в 0, хотя включение последнего параметра вполне допустимо. В пользовательком коде


Остановлюсь подробнее на том, какие изменения произойдут в выходных файлах транслятора xa2c (в частности, x3story.xc) по сравнению с теми же файлами, но оттранслированными предыдущей версией транслятора xa2c.

1. В предыдущих версиях транслятора xa2c был серьёзный баг, который проявлялся в том, что пропадали все конструкции вида A?1:0, где A - некоторое выражение. Это происходило как в связи с логическими операторами И и ИЛИ, так и вообще отдельно от них. В первом случае xc-код будет выглядеть так же, как и ранее, если использовать опцию -skipbc (код рекомендуется транслировать с SafeLogicalOps=1). Последний же случай более важен. Самый яркий пример - TQUEST194.__GetParseTemplates. Неприятное здесь то, что баг с потерей тернарной операции вида A?1:0 носит глобальный характер и распространён по всему обжу. Поэтому если есть модифицированный код оригинального обжа, чтобы не модифицировать заново новый xc-код оригинального обжа можно сделать поиск в новом xc-коде конструкции ?1:0 (всего несколько десятков) и добавить её в соответствующие места модифицирированного обжа.

2. В связи с улучшением обработки логических И и ИЛИ тернарные операции, если это возможно, заменяются на логические И и ИЛИ не только внутри условий операторов if,while,for, но и в других участках кода. Такое изменение может носить либо чисто косметический характер (замена в записи, если это возможно, тернарной операции на логическую увеличивает читаемость), а может помимо этого и скрывать потерю операции ?1:0. Например, ранее рассмотренная строка кода в файле x3story.xc, сгенерированного предыдущей версией транслятора xc, выглядит так:

var loc8=arg4&131072?SE_IsClass(arg5,2004):0;

Таким образом, все значимые изменения второго пункта также можно выловить поиском строки ?1:0, но поиск нужно производить по файлу, сгенерированному при отключенной опции -skipbc.


Новые версии трансляторов - xc 1.10 beta и xa2c 1.02 alpha доступны для скачивания на первой странице темы.
    Добавлено: 06:17 05-12-2007   
Канал X2: The Threat: «Трансляторы XC->XASM и XASM->XC»
На страницу: Пред.  1, 2, 3, 4  След. | Все страницы
  
Показать: 
Предыдущая тема | Следующая тема |
К списку каналов | Наверх страницы
Цитата не в тему: Ой, помню, взялся раз на нем до своей базы долететь..... какой-то фильм даже успел за это время просмотреть - а секторов всего 5 или 6 было. (ImperialHunter)

  » Трансляторы XC->XASM и XASM->XC | страница 2
Каналы: Новости | Elite | Elite: Dangerous | Freelancer | Star Citizen | X-Tension/X-BTF | X2: The Threat | X3: Reunion | X3: Terran Conflict | X Rebirth | X4: Foundations | EVE Online | Orbiter | Kerbal Space Program | Evochron | VoidExpanse | Космические Миры | Онлайновые игры | Другие игры | Цифровая дистрибуция | play.elite-games.ru | ЗВ 2: Гражданская война | Творчество | Железо | Игра Мечты | Сайт
   Дизайн Elite Games V5 beta.18