ковыряем компилятор
Участников: 2
FreeBasic :: Программирование :: Общее
Страница 1 из 1
ковыряем компилятор
предлагаю, в этой теме разбираться с компилятором.
компилируем компилятор, пока под win32.
это понравится тем, кто не любит всякие навороченные make файлы.
оговорюсь сразу, что мы будем компилировать пока только компилятор без RTL библиотек.
потом и rtl закомпилим.
предположим, что вы хотите изменить поведение компилятора, а функции из rtl библиотеки трогать не собираетесь, или как я- пока не собираетесь.
вот вам простой cmd файлик Win32FbcOnly.cmd
необходимый файл, который я откомпилил на mingw:
http://svalka-spb.narod.ru/progs/bfd-wrapper.o
качаем с оф сайта исходники в zip или tar архиве.
в корень распакованных исходников кидаем файл win32FbcOnly.cmd.
в корне с исходниками создадим папку "bin".
далее "\src\compiler", там создадим папку "obj" и забросим в нее файл bfd-wrapper.o.
перед запуском cmd файла, необходимо, чтоб в переменных окружения был прописан путь к установленному FreeBasic.
если лень куда-то лазить, в начале нашего cmd файла можно написать следующую строку:
запустим наш cmd файл. ждём... на моем двух-ядернике, секунд 30 компилится.
в папке "bin" получаем файл fbc.exe.
почему-то он на несколько сотен байт больше.
может из-за bfd-wrapper'а, я его компилил на последней версии mingw. фиг знает, на какой версии компилят на оф сайте.
ну теперь, можно ковырять компилятор!
я уже начал, и думаю, что потихооонечку врубаюсь.
надеюсь, что скоро начнём оптимизировать цикл while.
компилируем компилятор, пока под win32.
это понравится тем, кто не любит всякие навороченные make файлы.
оговорюсь сразу, что мы будем компилировать пока только компилятор без RTL библиотек.
потом и rtl закомпилим.
предположим, что вы хотите изменить поведение компилятора, а функции из rtl библиотеки трогать не собираетесь, или как я- пока не собираетесь.
вот вам простой cmd файлик Win32FbcOnly.cmd
- Код:
set binpath=bin\
set compilerpath=src\compiler\
set compilerobjpath=src\compiler\obj\
fbc -m fbc %compilerpath%*.bas -e -maxerr 1 -w pedantic -d ENABLE_STANDALONE -d ENABLE_FBBFD=217 %compilerobjpath%bfd-wrapper.o -l bfd -l iberty -l intl -l user32 -x %binpath%fbc.exe
pause
необходимый файл, который я откомпилил на mingw:
http://svalka-spb.narod.ru/progs/bfd-wrapper.o
качаем с оф сайта исходники в zip или tar архиве.
в корень распакованных исходников кидаем файл win32FbcOnly.cmd.
в корне с исходниками создадим папку "bin".
далее "\src\compiler", там создадим папку "obj" и забросим в нее файл bfd-wrapper.o.
перед запуском cmd файла, необходимо, чтоб в переменных окружения был прописан путь к установленному FreeBasic.
если лень куда-то лазить, в начале нашего cmd файла можно написать следующую строку:
- Код:
set path=d:\FreeBasic;%path%
запустим наш cmd файл. ждём... на моем двух-ядернике, секунд 30 компилится.
в папке "bin" получаем файл fbc.exe.
почему-то он на несколько сотен байт больше.
может из-за bfd-wrapper'а, я его компилил на последней версии mingw. фиг знает, на какой версии компилят на оф сайте.
ну теперь, можно ковырять компилятор!
я уже начал, и думаю, что потихооонечку врубаюсь.
надеюсь, что скоро начнём оптимизировать цикл while.
electrik- Сообщения : 391
Дата регистрации : 2008-09-02
Возраст : 43
Откуда : галактика Млечный путь, система Солнечная, планета Земля, страна россия, город Санкт Петербург
Re: ковыряем компилятор
Серега, а что это за враппер bfd-wrapper.o ?
Что это такое и зачем?
А вообще молодец.
----------------------------------
Я пытался по быстрому понять почему Name не работает с кирилицей, но судя по всему по быстрому не выйдет
По сути это должна быть обертка сишного rename.
rename работает нормально, видать где-то по внутренних делам коверкаются символы. Тот же трабл и с RTRIM , LTRIM и TRIM
Что это такое и зачем?
А вообще молодец.
----------------------------------
Я пытался по быстрому понять почему Name не работает с кирилицей, но судя по всему по быстрому не выйдет
По сути это должна быть обертка сишного rename.
rename работает нормально, видать где-то по внутренних делам коверкаются символы. Тот же трабл и с RTRIM , LTRIM и TRIM
trew- Сообщения : 331
Дата регистрации : 2010-10-14
Re: ковыряем компилятор
привет. фиг знает для чего нужен bfd-wrapper. я в make файле поглядел, вродь под win32 нужен.
да и когда компилишь прогу с ключиком -v, выдается следующее:
standalone, objinfo (libbfd 217)
а вообще эта штука расшифровывается как "Binary File Descriptor".
поповоду кирилицы, может досовская нормально будет работать.
ковырялся, есть функции удаления, создания каталога, а вот name пока не нашел. естественно она есть, только спрятана где-то.
я бы на их месте делал так, если win32,, юзаем напрямую апи.
некоторые функции у них так сделаны. например функция dir, ищет через win32api, если линукс, то через его сервисы.
похоже, что в библиотеках c, нет функций поиска файла, только открытие. я тут тоже хочу замутить свои говорящие часики на мульти платформенность, и хотел использовать во FreeBasic c функции, вот нет такой функции которая бы искала например:
find("*.bas)
вообще в чистом c все развивается очень медленно. вроде в 2012 году были какие-то поправки стандартов, и только в c++ появились такие функции о которых я говорю. это не сам видел, друган сказал.
да и когда компилишь прогу с ключиком -v, выдается следующее:
standalone, objinfo (libbfd 217)
а вообще эта штука расшифровывается как "Binary File Descriptor".
поповоду кирилицы, может досовская нормально будет работать.
ковырялся, есть функции удаления, создания каталога, а вот name пока не нашел. естественно она есть, только спрятана где-то.
я бы на их месте делал так, если win32,, юзаем напрямую апи.
некоторые функции у них так сделаны. например функция dir, ищет через win32api, если линукс, то через его сервисы.
похоже, что в библиотеках c, нет функций поиска файла, только открытие. я тут тоже хочу замутить свои говорящие часики на мульти платформенность, и хотел использовать во FreeBasic c функции, вот нет такой функции которая бы искала например:
find("*.bas)
вообще в чистом c все развивается очень медленно. вроде в 2012 году были какие-то поправки стандартов, и только в c++ появились такие функции о которых я говорю. это не сам видел, друган сказал.
electrik- Сообщения : 391
Дата регистрации : 2008-09-02
Возраст : 43
Откуда : галактика Млечный путь, система Солнечная, планета Земля, страна россия, город Санкт Петербург
Re: ковыряем компилятор
сегодня мы чуток попробуем исследовать компилятор. попытаемся найти самое простое, цикл while...wend. пока не будем ни чего оптимизировать, просто поймем как вообще устроено внутреннее устройство компилятора, и от стартовой функции компилятора проследуем до функций, которые создают этот цикл.
далеко не всегда просто, проследовать до той или иной функции, смотря лишь на вызываемые include файлы. приходится пересматривать кучу файлов, чтобы найти нужное.
и так, откроем файл fbc.bas, и найдем 2617 строку, далее фрагмент кода, он же является стартовой точкой всего компилятора:
вот именно самая последняя строчка "compileModules" нам и нужна.
в этом же файле на 2031 строке начинается процедура compileModules
опа, есть строчка " compileBas(module, ismain)". вызывается еще одна процедура в этом файле. начинается на 1969 строке:
в этой процедуре есть следующий вызов:
fbCompile(module->srcfile, asmfile, ismain)
все, закрываем файл fbc.bas и открываем файл fb.bas
на 643 строке начинается процедура fbCompile
обратим внимание на фрагмент кода:
в начале и в конце фрагмента, идет проверка таймера. за чем? думаю, что для определения скорости компиляции программы - не в бинарник.
смотрим фрагмент кода:
закрываем файл fb.bas и открываем файл parser-toplevel.bas.
продолжение следует.
далеко не всегда просто, проследовать до той или иной функции, смотря лишь на вызываемые include файлы. приходится пересматривать кучу файлов, чтобы найти нужное.
и так, откроем файл fbc.bas, и найдем 2617 строку, далее фрагмент кода, он же является стартовой точкой всего компилятора:
- Код:
fbcInit()
if (__FB_ARGC__ = 1) then
printOptions( )
fbcEnd( 1 )
end if
parseArgs(__FB_ARGC__, __FB_ARGV__)
if (fbc.showversion) then
printVersion()
fbcEnd( 0 )
end if
if( (listGetHead(@fbc.modules) = NULL) and _
(listGetHead(@fbc.objlist) = NULL) and _
(listGetHead(@fbc.libs.list) = NULL)) then
printOptions()
fbcEnd( 1 )
end if
if (fbc.verbose) then
printVersion()
end if
fbcInit2()
'' Compile into temporary files
compileModules()
вот именно самая последняя строчка "compileModules" нам и нужна.
в этом же файле на 2031 строке начинается процедура compileModules
- Код:
private sub compileModules()
dim as integer ismain = FALSE
dim as integer checkmain = any
select case fbGetOption( FB_COMPOPT_OUTTYPE )
case FB_OUTTYPE_EXECUTABLE, FB_OUTTYPE_DYNAMICLIB
checkmain = TRUE
case else
'' When building an object or a library (-c/-r, -lib), nothing
'' is compiled with ismain = TRUE until -m was given for it.
'' This makes sense because -c is usually used to compile
'' single modules of which only a very specific one is the
'' main one (nobody would want -c to include main() everywhere),
'' and because -lib is for making libraries which generally
'' don't include a main module for programs to use.
checkmain = fbc.mainset
end select
dim as string mainfile
if (checkmain) then
'' Note: This causes the path given with -m to be ignored in
'' the ismain check below. This is good because -m is easier
'' to use that way (e.g. fbc ../../main.bas -m main), and bad
'' because then modules with the same name but in different
'' directories will both be seen as the main one.
mainfile = hStripPath(fbc.mainname)
end if
dim as FBCIOFILE ptr module = listGetHead(@fbc.modules)
while (module)
if (checkmain) then
ismain = (mainfile = hStripPath(hStripExt(module->srcfile)))
'' Note: checking continues for all modules, because
'' "the" main module could be passed multiple times,
'' and it makes sense to always treat it the same,
'' so that <fbc 1.bas 1.bas -c> generates the same 1.o
'' twice and <fbc 1.bas 1.bas> causes a duplicated
'' definition of main().
/'checkmain = not ismain'/
end if
compileBas(module, ismain)
module = listGetNext(module)
wend
'' Make sure to add libs from command line to final lists if no input
'' .bas were given
if (module = NULL) then
strsetCopy(@fbc.finallibs, @fbc.libs)
strsetCopy(@fbc.finallibpaths, @fbc.libpaths)
end if
end sub
опа, есть строчка " compileBas(module, ismain)". вызывается еще одна процедура в этом файле. начинается на 1969 строке:
- Код:
private sub compileBas(byval module as FBCIOFILE ptr, byval ismain as integer)
'' *.o name based on input file name unless given via -o <file>
if (len(module->objfile) = 0) then
module->objfile = hStripExt(module->srcfile) & ".o"
end if
dim as string asmfile = getModuleAsmName(module)
if (fbc.preserveasm = FALSE) then
fbcAddTemp(asmfile)
end if
if (fbc.verbose) then
print "compiling: ", module->srcfile; " -o "; asmfile;
if (ismain) then
print " (main module)";
end if
print
end if
'' preserve orginal lang id, we may have to restore it.
dim as FB_LANG prevlangid = fbGetOption(FB_COMPOPT_LANG)
dim as integer restarts = 0
do
'' init the parser
fbInit(ismain, restarts)
'' add the libs and paths passed in the cmd-line, so the
'' compiler can add them to the module's objinfo section
fbSetLibs(@fbc.libs, @fbc.libpaths)
fbCompile(module->srcfile, asmfile, ismain)
'' If there were any errors during parsing, just exit without
'' doing anything else.
if (errGetCount() > 0) then
fbcEnd(1)
end if
'' Don't restart unless asked for
if (fbShouldRestart() = FALSE) then
exit do
end if
'' Restart
restarts += 1
'' Shutdown the parser before restarting
fbEnd()
loop
'' Update the list of libs and paths, with the ones found when parsing
fbGetLibs(@fbc.finallibs, @fbc.finallibpaths)
'' Shutdown the parser
fbEnd()
'' Restore original lang
fbSetOption( FB_COMPOPT_LANG, prevlangid )
end sub
в этой процедуре есть следующий вызов:
fbCompile(module->srcfile, asmfile, ismain)
все, закрываем файл fbc.bas и открываем файл fb.bas
на 643 строке начинается процедура fbCompile
- Код:
sub fbCompile _
( _
byval infname as zstring ptr, _
byval outfname as zstring ptr, _
byval ismain as integer _
)
dim as double tmr
env.inf.name = *infname
hReplaceSlash( env.inf.name, asc( FB_HOST_PATHDIV ) )
env.inf.incfile = NULL
env.inf.ismain = ismain
env.outf.name = *outfname
env.outf.ismain = ismain
'' open source file
if( hFileExists( *infname ) = FALSE ) then
errReportEx( FB_ERRMSG_FILENOTFOUND, infname, -1 )
exit sub
end if
env.inf.num = freefile
if( open( *infname, for binary, access read, as #env.inf.num ) <> 0 ) then
errReportEx( FB_ERRMSG_FILEACCESSERROR, infname, -1 )
exit sub
end if
env.inf.format = hCheckFileFormat( env.inf.num )
''
if( irEmitBegin( ) = FALSE ) then
errReportEx( FB_ERRMSG_FILEACCESSERROR, env.outf.name, -1 )
exit sub
end if
if( fbGetOption( FB_COMPOPT_PPONLY ) ) then
env.ppfile_num = freefile()
dim as string ppfile = hStripExt( env.inf.name ) + ".pp.bas"
if( open( ppfile, for output, as #env.ppfile_num ) <> 0 ) then
errReportEx( FB_ERRMSG_FILEACCESSERROR, ppfile, -1 )
exit sub
end if
else
env.ppfile_num = 0
end if
fbMainBegin( )
tmr = timer( )
fbParsePreDefines()
fbParsePreIncludes()
if (fbShouldContinue()) then
cProgram()
end if
tmr = timer( ) - tmr
fbMainEnd( )
'' save
irEmitEnd( tmr )
if( env.ppfile_num > 0 ) then
close #env.ppfile_num
end if
close #env.inf.num
'' check if any label undefined was used
if (fbShouldContinue()) then
symbCheckLabels(symbGetGlobalTbHead())
end if
end sub
обратим внимание на фрагмент кода:
- Код:
tmr = timer( )
fbParsePreDefines()
fbParsePreIncludes()
if (fbShouldContinue()) then
cProgram()
end if
tmr = timer( ) - tmr
в начале и в конце фрагмента, идет проверка таймера. за чем? думаю, что для определения скорости компиляции программы - не в бинарник.
смотрим фрагмент кода:
- Код:
if (fbShouldContinue()) then
cProgram()
end if
закрываем файл fb.bas и открываем файл parser-toplevel.bas.
продолжение следует.
electrik- Сообщения : 391
Дата регистрации : 2008-09-02
Возраст : 43
Откуда : галактика Млечный путь, система Солнечная, планета Земля, страна россия, город Санкт Петербург
Re: ковыряем компилятор
на 86 строке начинается процедура cProgram:
смотрим фрагмент кода:
вот именно cStatement нам и нужен.
закрываем файл parser-toplevel.bas и открываем файл parser-statement.bas
на 19 строке начинается процедура cStatement:
смотрим фрагмент:
нам нужна та функция которая проверяется в условии:
if( cCompoundStmt( ) = FALSE ) then
эта функция cCompoundStmt.
закрываем файл parser-statement.bas и открываем файл parser-compound.bas.
начинается самое интересное. на 68 строке начинается магическая функция cCompoundStmt:
как мы уже поняли, проверяются токены, for, next, while, wend, do, loop и т.д.
как парсер видит такие ключевые слова как while, wend, for, next, он запускает соответствующие функции/процедуры, которые проверяют синтаксис, выражения, типы данных,а затем генерируют код.
нам нужна одна функция и одна процедура.
фрагменты кода:
вот что нам нужно:
cWhileStmtBegin
cWhileStmtEnd
закрываем файл parser-compound.bas и открываем файл parser-compound-while.bas.
продолжение следует.
- Код:
sub cProgram()
dim as integer startlevel = pp.level
'' For each line...
do
parser.stmt.cnt += 1
'' line begin
astAdd( astNewDBG( AST_OP_DBG_LINEINI, lexLineNum( ) ) )
dim as ASTNODE ptr proc = astGetProc( ), expr = astGetProcTailNode( )
'' Label?
cLabel( )
'' Statement?
cStatement( )
'' Comment?
cComment( )
if (fbShouldContinue() = FALSE) then
exit sub
end if
'' emit the current line in text form
if( env.clopt.debug ) then
if( env.includerec = 0 ) then
'' don't add if proc changed (from main() to proc block or the inverse)
if( proc = astGetProc( ) ) then
astAddAfter( astNewLIT( lexCurrLineGet( ) ), expr )
end if
lexCurrLineReset( )
end if
end if
select case (lexGetToken())
case FB_TK_EOL
lexSkipToken( )
case FB_TK_EOF
case else
errReport( FB_ERRMSG_EXPECTEDEOL )
'' error recovery: skip until EOL
hSkipUntil( FB_TK_EOL, TRUE )
end select
if (fbShouldContinue() = FALSE) then
exit sub
end if
'' line end
astAdd( astNewDBG( AST_OP_DBG_LINEEND ) )
loop while (lexGetToken() <> FB_TK_EOF)
'' EOF
assert(lexGetToken() = FB_TK_EOF)
parser.stmt.cnt += 1
if (pp.level <> startlevel) then '' inside #IF block?
errReport( FB_ERRMSG_EXPECTEDPPENDIF )
end if
lexSkipToken()
'' only check compound stmts if not parsing an include file
if (env.includerec = 0) then
cCompStmtCheck()
end if
end sub
смотрим фрагмент кода:
- Код:
'' метка?
cLabel( )
'' оператор?
cStatement( )
'' комментарий?
cComment( )
вот именно cStatement нам и нужен.
закрываем файл parser-toplevel.bas и открываем файл parser-statement.bas
на 19 строке начинается процедура cStatement:
- Код:
sub cStatement()
'' ':'?
if( lexGetToken( ) = FB_TK_STMTSEP ) then
parser.stmt.cnt += 1
lexSkipToken( )
end if
do
if( cDeclaration( ) = FALSE ) then
if( cCompoundStmt( ) = FALSE ) then
if( cProcCallOrAssign( ) = FALSE ) then
if( cQuirkStmt( ) = FALSE ) then
if( cAsmBlock( ) = FALSE ) then
cAssignmentOrPtrCall( )
end if
end if
end if
end if
end if
parser.stmt.cnt += 1
'' ':'?
if( lexGetToken( ) <> FB_TK_STMTSEP ) then
exit do
end if
lexSkipToken( )
loop
end sub
смотрим фрагмент:
- Код:
if( cDeclaration( ) = FALSE ) then
if( cCompoundStmt( ) = FALSE ) then
if( cProcCallOrAssign( ) = FALSE ) then
if( cQuirkStmt( ) = FALSE ) then
if( cAsmBlock( ) = FALSE ) then
cAssignmentOrPtrCall( )
end if
end if
end if
end if
end if
нам нужна та функция которая проверяется в условии:
if( cCompoundStmt( ) = FALSE ) then
эта функция cCompoundStmt.
закрываем файл parser-statement.bas и открываем файл parser-compound.bas.
начинается самое интересное. на 68 строке начинается магическая функция cCompoundStmt:
- Код:
function cCompoundStmt as integer
function = FALSE
'' QB mode?
if( env.clopt.lang = FB_LANG_QB ) then
if( lexGetType() <> FB_DATATYPE_INVALID ) then
return FALSE
end if
end if
select case as const lexGetToken( )
case FB_TK_IF
CHECK_CODEMASK( FB_TK_IF, FB_TK_IF )
cIfStmtBegin()
function = TRUE
case FB_TK_FOR
CHECK_CODEMASK( FB_TK_FOR, FB_TK_NEXT )
function = cForStmtBegin( )
case FB_TK_DO
CHECK_CODEMASK( FB_TK_DO, FB_TK_LOOP )
cDoStmtBegin()
function = TRUE
case FB_TK_WHILE
CHECK_CODEMASK( FB_TK_WHILE, FB_TK_WEND )
cWhileStmtBegin()
function = TRUE
case FB_TK_SELECT
CHECK_CODEMASK( FB_TK_SELECT, FB_TK_SELECT )
cSelectStmtBegin()
function = TRUE
case FB_TK_WITH
CHECK_CODEMASK( FB_TK_WITH, FB_TK_WITH )
cWithStmtBegin()
function = TRUE
case FB_TK_SCOPE
CHECK_CODEMASK( FB_TK_SCOPE, FB_TK_SCOPE )
function = cScopeStmtBegin( )
case FB_TK_NAMESPACE
function = cNamespaceStmtBegin( )
case FB_TK_EXTERN
function = cExternStmtBegin( )
case FB_TK_ELSE, FB_TK_ELSEIF
function = cIfStmtNext( )
case FB_TK_CASE
function = cSelectStmtNext( )
case FB_TK_LOOP
function = cDoStmtEnd( )
case FB_TK_NEXT
function = cForStmtEnd( )
case FB_TK_WEND
function = cWhileStmtEnd( )
case FB_TK_EXIT
cExitStatement()
function = TRUE
case FB_TK_CONTINUE
cContinueStatement()
function = TRUE
case FB_TK_END
'' any compound END will be parsed by the compound stmt
if( lexGetLookAheadClass( 1 ) <> FB_TKCLASS_KEYWORD ) then
CHECK_CODEMASK( INVALID, INVALID )
return cEndStatement( )
end if
function = cCompoundEnd( )
case FB_TK_ENDIF
function = cIfStmtEnd( )
case FB_TK_USING
function = cUsingStmt( )
case else
return FALSE
end select
end function
как мы уже поняли, проверяются токены, for, next, while, wend, do, loop и т.д.
как парсер видит такие ключевые слова как while, wend, for, next, он запускает соответствующие функции/процедуры, которые проверяют синтаксис, выражения, типы данных,а затем генерируют код.
нам нужна одна функция и одна процедура.
фрагменты кода:
- Код:
case FB_TK_WHILE
CHECK_CODEMASK( FB_TK_WHILE, FB_TK_WEND )
cWhileStmtBegin()
function = TRUE
case ...
...
...
case FB_TK_WEND
function = cWhileStmtEnd( )
вот что нам нужно:
cWhileStmtBegin
cWhileStmtEnd
закрываем файл parser-compound.bas и открываем файл parser-compound-while.bas.
продолжение следует.
electrik- Сообщения : 391
Дата регистрации : 2008-09-02
Возраст : 43
Откуда : галактика Млечный путь, система Солнечная, планета Земля, страна россия, город Санкт Петербург
Re: ковыряем компилятор
на этом файле остановимся подробнее. возможно, я не все правильно понял. для этого мы и находимся здесь, чтоб разобраться и понять компилятор.
напишем простой код:
a функция cWhileStmtEnd следующий код:
вот мы кое как, со скрипом, имеем малое представление о маленькой части компилятора.
давайте думать. если я один буду, думаю, не доживете до того времени, когда я разберусь с компилятором.
как бы хотелось оптимизировать цикл while...wend:
переместить сравнение в конец цикла, а в начале перед телом цикла добавить прыжок на сравнение.
так мы избавимся от лишнего jmp в теле цикла
для начала будет достаточно файл parser-compound-do.bas.
там реализованы циклы do...loop.
- Код:
'':::::
''WhileStmtBegin = WHILE выражение .
''
sub cWhileStmtBegin()
dim as ASTNODE ptr expr = any ' узел expr абстрактного синтаксического дерева, туда будем читать выражение. объявлен в файле ast.bi
dim as FBSYMBOL ptr il = any, el = any ' метки начала и конца цикла while...wend. тип объявлен в файле symb.bi
dim as FB_CMPSTMTSTK ptr stk = any ' пока не понял, но вроде что-то внутреннего стека. тип объявлен в файле parser.bi
'' WHILE
lexSkipToken( ) ' процедура находится в файле lex.bas
'' add ini and end labels ' добавление меток начала и конца цикла
il = symbAddLabel( NULL ) ' процедура находится в файле symb-label.bas
el = symbAddLabel( NULL, FB_SYMBOPT_NONE ) ' FB_SYMBOPT_NONE объявлено в файле symb.bi, enum FB_SYMBOPT
'' emit ini label
astAdd( astNewLABEL( il ) ) ' добавляем в синтаксическое дерево новую метку начала цикла - новый узел. процедура astAdd находится в файле ast-node-proc.bas
'' Expression - выражение
expr = cExpression( ) ' парсим выражение
if( expr = NULL ) then
errReport( FB_ERRMSG_EXPECTEDEXPRESSION ) ' если нет выражения, ошибка, ожидается выражение
'' error recovery: fake an expr
expr = astNewCONSTi( 0, FB_DATATYPE_INTEGER ) ' функция находится в файле ast-node-const.bas
end if
'' branch
expr = astUpdComp2Branch( expr, el, FALSE ) ' функция находится в файле ast-misc.bas
if( expr = NULL ) then
errReport( FB_ERRMSG_INVALIDDATATYPES )
else
astAdd( expr ) ' добавляем в синтаксическое дерево выражение
end if
'' push to stmt stack ' сохраняется во внутренний стек
stk = cCompStmtPush( FB_TK_WHILE ) ' функция находится в файле parser-compound.bas
stk->scopenode = astScopeBegin( ) ' функция находится в файле ast-node-scope.bas
stk->while.cmplabel = il
stk->while.endlabel = el
end sub
'':::::
''WhileStmtEnd = WEND
''
function cWhileStmtEnd as integer
dim as FB_CMPSTMTSTK ptr stk = any
function = FALSE
stk = cCompStmtGetTOS( FB_TK_WHILE ) ' функция находится в файле parser-compound.bas
if( stk = NULL ) then
exit function
end if
'' WEND
lexSkipToken( )
if( stk->scopenode <> NULL ) then
astScopeEnd( stk->scopenode )
end if
astAdd( astNewBRANCH( AST_OP_JMP, stk->while.cmplabel ) ) ' добавляем в синтаксическое дерево скачок на начало цикла, где идет проверка условия
'' end label (loop exit)
astAdd( astNewLABEL( stk->while.endlabel ) )
'' pop from stmt stack
cCompStmtPop( stk )
function = TRUE
end function
напишем простой код:
- Код:
dim a as integer = 10
while (a > 0)
wend
- Код:
.Lt_0004:
cmp dword ptr [ebp-8], 0
jle .Lt_0005
a функция cWhileStmtEnd следующий код:
- Код:
jmp .Lt_0004
.Lt_0005:
вот мы кое как, со скрипом, имеем малое представление о маленькой части компилятора.
давайте думать. если я один буду, думаю, не доживете до того времени, когда я разберусь с компилятором.
как бы хотелось оптимизировать цикл while...wend:
переместить сравнение в конец цикла, а в начале перед телом цикла добавить прыжок на сравнение.
так мы избавимся от лишнего jmp в теле цикла
- Код:
jmp .Lt_0005 ' прыжок на метку сравнения
.Lt_0004: метка начала цикла
' тело цикла
.Lt_0005: ' метка с которой начинается сравнение
cmp dword ptr [ebp-8], 0
jg .Lt_0005 ' если условие истино, идем на метку начала цикла
.Lt_0006:
для начала будет достаточно файл parser-compound-do.bas.
там реализованы циклы do...loop.
electrik- Сообщения : 391
Дата регистрации : 2008-09-02
Возраст : 43
Откуда : галактика Млечный путь, система Солнечная, планета Земля, страна россия, город Санкт Петербург
FreeBasic :: Программирование :: Общее
Страница 1 из 1
Права доступа к этому форуму:
Вы не можете отвечать на сообщения
|
|