Программирование игр, создание игрового движка, OpenGL, DirectX, физика, форум
GameDev.ru / Программирование / Форум / Парсинг текстового файла без напряга для GC и без unsafe

Парсинг текстового файла без напряга для GC и без unsafe

Страницы: 1 2 315 16 Следующая »
Polyflow3dПостоялецwww6 мар. 201810:29#0
Собственно сабж.
Возможно ли? Или лучше даже не пытаться..
ZabПостоялецwww6 мар. 201810:54#1
Проблема то в чем? Рекурсивный спуск писать не умеешь?
Или формат файла слишком сложный, грамматику не построить? Что парсить то надо?
Polyflow3dПостоялецwww6 мар. 201811:02#2
Zab
Проблема то в чем? Рекурсивный спуск писать не умеешь?

не, не умею.
obj файл парсить надо, 3д формат который

ZabПостоялецwww6 мар. 201811:15#3
Polyflow3d
> не, не умею.
Ну так, научись. Компиляторостроение - отдельная дисциплина в программировании, каждый профессиональный программист должен этим владеть. Учебников много. За пару месяцев минимальный объем освоишь.

>obj файл парсить надо
Без четкого формального описания формата, по наитию, много не напарсишь.

DampireУчастникwww6 мар. 201811:27#4
В чем проблема с GC при парсинге не подскажешь? И нах там unsafe?
string[] lines = File.ReadAllLines(filename);
foreach(line in lines)
{
  string[] arg = line.Split(' ');
  int _int;  
  if(int.TryParse(arg[0], out _int))
    Console.WriteLine("Awesome, without GC problems and unsafe stuff. I'm fucking genius.");
}

Правка: 6 мар. 2018 11:27

ZabПостоялецwww6 мар. 201811:30#5
Dampire
Он вообще не знает как строится парсинг по науке.
Объяснять это прямо тут нет смысла, слишком большой объем. Не опишешь в нескольких абзацах то, что в институтах год изучают.
Вооружиться парой-тройкой хороших книжек - за пару месяцев освоится, если тратить на это по половине дня каждый день.
DampireУчастникwww6 мар. 201811:33#6
Zab
> Объяснять это прямо тут нет смысла, слишком большой объем. Не опишешь в
> нескольких абзацах то, что в институтах год изучают.
Парсинг в институте? На C#? Год? Чтобы разбить строку по пробелам/запятым на сегменты и скормить из TryParse? Ну ок, чо.
ZabПостоялецwww6 мар. 201811:35#7
Dampire
> Парсинг в институте? На C#? Год? Чтобы разбить строку по пробелам/запятым на сегменты и скормить из TryParse? Ну ок, чо.
Удачи тебе по жизни с таким "парсингом"! Удача понадобится, потому что провалы будут постоянные.
Ничего сложнее ini-файла таким наивным способом не разберешь, да и в ini-файле рискуешь запутаться.
Polyflow3dПостоялецwww6 мар. 201811:37#8
Dampire
проблема в том аллоцируется память вот тут например
string[] arg = line.Split(' ');
FordPerfectПостоялецwww6 мар. 201811:53#9
А разве для obj не хватит лексера (конечного автомата)?
ZabПостоялецwww6 мар. 201811:54#10
Вот так примерно выглядит правильный парсинг в тривиальном случае...
Нашел у себя в архиве разбор формата файлов одной игры, которую когда-то анализировал. Формат похож на json.
Особой подчисткой кода не заморачивался, писалось все на ходу. Подобные разборы файлов пишутся очень быстро, за считанные часы, если рука набита.
CLexAn::CLexAn( const char * FilePrefix, const char * FileName )
{
  m_FilePrefix = FilePrefix;
  m_FileName = FileName;
  m_hFile = fopen( (m_FilePrefix+m_FileName).c_str(), "r" );
  if (!m_hFile) throw ESyntError("File \'%s\' not found", FileName);
  m_Line = 1;
  Next();
}

CLexAn::~CLexAn()
{
  if (!m_hFile)
    fclose(m_hFile);
}

int CLexAn::GetChar()
{
  m_CharBuf = fgetc(m_hFile);
  if ( m_CharBuf==EOF ) 
  {
    //printf("\rEOF %d %s          ", m_Line, m_FileName.c_str());
  }
  else if ( m_CharBuf=='\n' ) 
  {
    ++m_Line;

    //if (m_Line==2 || m_Line%400==0)
    //  printf("\r%d %s          ", m_Line, m_FileName.c_str());
  }

  return m_CharBuf;
}

void CLexAn::UnGetChar()
{
  ungetc( m_CharBuf, m_hFile );
  if ( m_CharBuf=='\n' ) 
  {
    --m_Line;
  }
}

inline bool isValueChar ( int c )
{
  return isalnum(c) || c=='_' || c=='-' || c=='.';
}

void CLexAn::Next()
{
  m_CurLex.Clear();

  if (!m_hFile) return;

  enum CState { ST_BEGIN, ST_VALUE, ST_STRING, ST_COMMENT };
  CState State = ST_BEGIN;

  while (true)
  {
    int c = GetChar();
    if ( c==EOF ) break;

    switch ( State )
    {
    case ST_BEGIN:
      switch ( c )
      {
      case'#':
        State = ST_COMMENT;
        break;

      case'\"':
        State = ST_STRING;
        break;

      case' ':
      case'\n':
      case'\r':
      case'\t':
        break;

      case'=':
      case'{':
      case'}':
        m_CurLex.Add( c );
        return;

      default:
        if (!isValueChar(c))
          throw ESyntError( "unexpected char %c(%d)", c, c );

        m_CurLex.Add( c );
        State = ST_VALUE;
        break;
      }
      break;
    case ST_VALUE:
      if (!isValueChar(c))
      {
        UnGetChar();
        State = ST_BEGIN;
        return;
      }

      m_CurLex.Add( c );
      break;
    case ST_STRING:
      switch ( c )
      {
      case'\"':
        State = ST_BEGIN;
        return;

      case'\n':
      case'\r':
        throw ESyntError( "unpair char \"" );

      default:
        m_CurLex.Add( c );
        break;
      }
      break;
    case ST_COMMENT:
      switch (c)
      {
      case'\n':
      case'\r':
        State = ST_BEGIN;
        break;
      default:
        break;
      }
      break;
    }
  }
}

/*
<запись> ::= <имя> "=" <значение>
<запись> ::= <имя> "=" <группа>
<запись> ::= <имя> "=" "{" {<группа>}... "}"
<запись> ::= include = <имя_файла>
<группа> ::= "{" {<запись>}... "}"
*/
void netRule( CLexAn & LexAn, CLoader * pFather )
{
  try
  {
    CLex tName = LexAn.Get();
    LexAn.Next();

    if (tName==CLex("include"))
    {
      if (LexAn.Get() != CLex("=") )
        throw ESyntError( "expected char \'=\'");
      LexAn.Next();

      CLex tFileName = LexAn.Get();
      LexAn.Next();

      CLexAn IncLexAn( LexAn.GetFilePrefix().c_str(), tFileName.Text().c_str() );
      while ( IncLexAn.Get() != CLex() )
      {
        netRule( IncLexAn, pFather );
      }
    }
    else
    {
      std::auto_ptr<CLoader> pItem ( pFather->AddName( tName.Text() ) );
      if (!pItem.get())
        throw ESyntError( "unknown name \'%s\'", tName.Text().c_str() );
      bool IsInited = false;

      if (LexAn.Get() == CLex("=") )
      {
        LexAn.Next();
        if (LexAn.Get() != CLex("{") )
        {
          CLex tArg = LexAn.Get();
          LexAn.Next();
          pItem->AddValue( tArg.Text() );
        }
        else
        {
          LexAn.Next();
          while ( LexAn.Get() != CLex("}") )
          {
            //if (LexAn.Get() == CLex() )  throw ESyntError("unexpected EOF");
            if (LexAn.Get() == CLex() )  break;

            if (LexAn.Get() != CLex("{") )
            {
              netRule( LexAn, pItem.get() );
            }
            else
            {
              LexAn.Next();
              if (IsInited)
              {
                pItem = std::auto_ptr<CLoader>( pFather->AddName( tName.Text() ) );
                if (!pItem.get())
                  throw ESyntError( "unknown name \'%s\'", tName.Text().c_str() );
                IsInited = false;
              }
              while ( LexAn.Get() != CLex("}") )
              {
                if (LexAn.Get() == CLex() )  break;
                netRule( LexAn, pItem.get() );
              }
              LexAn.Next();
              IsInited = true;
            }
          }
          LexAn.Next();
        }
      }
    }
  }
  catch ( ESyntError e )
  {
    if ( e.m_Line == 0 )
      e.m_Line = LexAn.CurLine();
    if ( e.m_FileName.empty() )
      e.m_FileName = LexAn.GetFileName();
    throw e;
  }
}

void netFile( const char * FilePrefix, const char * FileName )
{
  CLexAn LexAn( FilePrefix, FileName );
  CBaseLoader Loader;
  while ( LexAn.Get() != CLex() )
  {
    netRule( LexAn, &Loader );
  }
}

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

SuslikМодераторwww6 мар. 201811:55#11
Zab
> Без четкого формального описания формата, по наитию, много не напарсишь.
> Вооружиться парой-тройкой хороших книжек - за пару месяцев освоится, если тратить на это по половине дня каждый день.
> Компиляторостроение - отдельная дисциплина в программировании, каждый профессиональный программист должен этим владеть. Учебников много. За пару месяцев минимальный объем освоишь.
чувак, ему надо .obj файл распарсить, какие компиляторы? какой институт? парсилка .obj формата за полчаса пишется.

читаешь первый символ в каждой строке. перенос строки или решётка — пропускаешь. v — вертекс, f — фейс, итп. формат специально разработан, чтоб его парсить инвалидам было легко.

Правка: 6 мар. 2018 11:56

Daniil PetrovЗабаненwww6 мар. 201811:55#12
Polyflow3d
> obj файл парсить надо, 3д формат который
А не проще через Assimp? Я тоже хотел ручками, чтоб библиотеку отцепить, но код в разы проще и компактней!
Тем более, что парсинг моделек я выкинул в оффлайн.
P.S. Но вот тебе на всякий случай.

Правка: 6 мар. 2018 12:11

Polyflow3dПостоялецwww6 мар. 201812:03#13
Suslik
у меня уже написан парсинг обжа давным давно. Сейчас стоит вопрос как сделать так что бы он не аллоцировал память.
То есть нужно  избавиться от regex которые я использую и от всяких string.split
Прежде чем велосипедить своё я хочу узнать - как в целом это делается?


Daniil Petrov
я хочу сделать асинхронный импорт моделей в рантайм юнити, сам парсер у меня уже есть, сейчас нужно сделать его быстрым и без нагрузки на GC.

DampireУчастникwww6 мар. 201812:43#14
Zab
> Удачи тебе по жизни с таким "парсингом"! Удача понадобится, потому что провалы
> будут постоянные.
> Ничего сложнее ini-файла таким наивным способом не разберешь, да и в ini-файле
> рискуешь запутаться.
obj сильно сложнее ini? Какого хрена ты несешь?
Polyflow3d
> проблема в том аллоцируется память вот тут например
Переходи на кресты или или C. Там память не аллоцируется. Wai.... oh shit!
Страницы: 1 2 315 16 Следующая »

/ Форум / Программирование игр / Общее

2001—2018 © GameDev.ru — Разработка игр