跳转到内容

Futurebasic/FBtoC

来自维基教科书,开放世界中的开放书籍

什么是 FBtoC?

[编辑 | 编辑源代码]

FBtoC 是 FB 编译器 (FB Compiler.app) 的替代品。将代码翻译成 C 允许 Apple 的开发工具创建通用二进制文件。下面的图表说明了这个过程

FB 编译器FB 源代码遗留应用程序(仅限 PPC,CFM 格式,资源分支...)
FBtoCFB 源代码C 源代码带有 Carbon 通用二进制文件的 OS X 应用程序包,以 Mach-O 格式

FBtoC 翻译外观项目和独立文件,以及控制台类型的纯文本独立文件。PG 项目无法翻译。使用 FBtoC 通常不需要详细了解 C。

为什么当我用 BASIC 编程时要翻译成 C?

[编辑 | 编辑源代码]
  • 编译器 (gcc) 对速度的优化比 FB 编译器更强大。
  • 原生 Intel 代码在 Rosetta 下的运行速度比 PPC 代码快 ≈3 倍(或更多)。
  • 框架访问比 FB 中更容易(见后)。
  • FBtoC 可以自动将指定的文件夹复制到应用程序的资源中(见后)。
  • Apple 的现代开发工具适用于 FBtoC 生成的应用程序。工具包括 Xcode 调试器和性能分析器 Shark。
  • 应用程序可以构建得尽可能小,只有 64 KB。
    • (窗口 1 : 打印 "Hello, world!" : 执行 处理事件 : 直到 gFBQuit)
  • 在 Intel Mac 上,崩溃报告是可以解释的,不像遗留的 FB 应用程序那样。
  • 与 FB 不同,局部函数变量没有 32k 的限制。
  • 还有令人垂涎的通用二进制文件状态!

本节介绍 FutureBASIC 和 FBtoC 的安装。在继续之前,您需要获取以下内容

系统要求

[编辑 | 编辑源代码]

FBtoC 应该可以在 OS X 10.3.9 及更高版本上运行。大部分开发和测试是在 OS X 10.4 和 10.5 上完成的。在使用 FBtoC 之前,您应该已经安装了 Apple 的免费开发工具(也称为 Xcode 工具),这些工具来自您的 OS X 安装 CD 或 DVD。

要创建通用二进制文件,您必须拥有 OS X 10.4 或更高版本、gcc 4.0 或更高版本,并安装交叉开发 SDK。如果没有 /Developer/SDKs/MacOSX10.4u.sdk,则只能构建 Mac 本机的体系结构。安装后,Developer 文件夹的 Finder 视图(下面)将显示 SDK。交叉开发是 Xcode 工具安装(来自 OS X DVD 或 CD)的可选部分。

另请参阅 Apple 的文档:Apple 开发工具文档

安装 FBtoC

[编辑 | 编辑源代码]

只需拖放。包含 FBtoC.app 的文件夹还必须包含三个特殊文件夹:build_goodiesHeadersUser Libraries

build-goodies 文件夹包含运行时的预翻译部分。更改任何这些文件可能会破坏 FBtoC。

Headers 文件夹包含标准 FB 头文件的一部分。大多数文件都需要修改才能在 FBtoC 中使用。一般来说,现有的 FB 头文件如果简单地复制到此文件夹中,将无法使用。

User Libraries 与 FB 中的功能相同,只是 FBtoC 会忽略鲜为人知的特殊文件 UserFloatPrefs。

FutureBASIC 和 FBtoC 之间的差异

[编辑 | 编辑源代码]

不太好的消息

[编辑 | 编辑源代码]

FBtoC 中必须以不同的方式完成的一些事情

编译长 if用 #if.... 替换
enterproc标签必须与 enterproc 函数名匹配
autoXREFCurr&不同的语法;见后
DynamicRemoveItems不同的语法;见后
ControlButtonContentInfo用 '.u' 的不同语法;见后
HMHelpContent用 '.u' 的不同语法;见后
Hndl用 Handle 替换
proc不同的语法;此外,标签 *必须* 在 proc 出现的行之前
100#, 100!FBII 格式;都重写为 100.0

未实现的功能

[编辑 | 编辑源代码]

由于 FBtoC 的操作限制和其他更明显的限制(例如,Intel 不支持 PowerPC 汇编器 - 当然),一些遗留语法无法实现。但是,通常存在用于实现类似目标的现代等效项。将遗留源代码更新为现代等效项可以利用更新的功能,并有助于保持源代码的长期可用性。

1. 遗留语法和语言

[编辑 | 编辑源代码]
beginassem ... endassemFB 汇编器与 gcc 不兼容(即使在 PPC 上也不兼容)
tbalias稍后讨论
dim recordFBII 伪记录;使用真实记录
dim as int x;0, hi as byte, lo as byte别名变量会导致字节序错误
myLong&[0]会导致字节序错误

2. 目前未实现

[编辑 | 编辑源代码]

appleeventmessage$
def SomeAreButSomeAreNotAvailable
DynamicInsertItems
event&
event%
flushevents // 相反,使用 Toolbox:调用 FlushEvents( _everyEvent, 0 )
folder
get field
on appleevent
on break
on edit
on expr
on finderinfo
on lprint
on overflows
on stop
覆盖本地函数 SomeFunction,覆盖运行时 SomeRuntimeThing(但支持覆盖 _someConst = 1)
parentID
图片字段
syserror
计时器 [函数]

3. 不支持工具箱别名

[编辑 | 编辑源代码]

FB 中的 TBalias 语句允许保留旧的工具箱名称,并在 Apple 引入新函数时应用于新函数。这个想法应该是为了节省程序员更新函数名称的一两分钟时间,否则每隔几年就需要进行这项令人厌烦的任务。TBalias 功能现在被认为是有害的,FBtoC 将不支持它。您可能已经升级了您的项目,以便使用正确的(Apple 的官方)工具箱名称。如果没有,请做好准备,FBtoC 会显示错误消息,表明名称有问题。

•• Unknown statement in line 6 of untitled
  6:  RmveResource( resH )
                 ^

简单、推荐的且唯一的解决方法是在代码中用 RemoveResource 替换每个出现的 RmveResource。

下面列出了一些在旧 FB 代码中经常被别名的工具箱函数。

FB、FBtoC 和 C仅限 FB 的别名
GetIntlResourceIUGetIntl
MemErrorMemErr
DisposeHandleDisposHandle
DisposePtrDisposPtr
AppendResMenuAddResMenu
GetMenuHandleGetMHandle
CountMenuItemsCountMItems
EnableMenuItemEnableItem
DisableMenuItemDisableItem
GetControlValueGetCtlValue
GetControlReferenceGetCRefcon
PBReadSyncPBRead
PBCatMoveSyncCatMove
PBHCreateSyncHCreate
PBFlushVolSyncFlushVol
AEPutParamDescAEPutKeyDesc
SecondsToDateSecs2Date
LongSecondsToDateLongSecs2Date
RemoveResourceRmveResource

4. 缺少头文件

[编辑 | 编辑源代码]
include "Util_Dialogtests.incl"

•• Include file not found in line 1 of OopsMissingFunction.main
  1:  include "Util_Dialogtests.incl"
                                    ^

FBtoC 的 Headers 文件夹中还没有此文件。

5. 不完整的头文件

[编辑 | 编辑源代码]
include "Util_Files.incl"
dim as FSSpec   fs
dim as Boolean  found
found = usr FSFileExists( fs )

•• Unknown function in line 4 of OopsMissingFunction.main: FSFileExists
  4:  found = usr FSFileExists( fs )
                               ^

Util_Files.incl 存在于 FBtoC 的 Headers 文件夹中;错误出现是因为函数 usr FSFileExists 被某个小气的官员给有条件地移除了,希望只是暂时性的。[稍后添加的说明:现在实现了 FSFileExists]

FBtoC 的示例翻译

[编辑 | 编辑源代码]

在 FBtoC 运行时中保存的旧 FB 代码

CLEAR LOCAL
dim pBlk.128
LOCAL FN FBGetFolderName(DirID&,WDRefNum%,@StrPtr&)
 StrPtr&.Nil$ = ""
 pBlk.ioDirID&    = DirID&
 pBlk.ioVRefNum%  = WDRefNum%
 pBlk.ioNamePtr&  = StrPtr&
 pBlk.ioFDirIndex%= -1
 long if FN PBGetCatInfoSync(@pBlk)
  StrPtr&.Nil$ = "Error"
 end if
END FN
long FBGetFolderName( long  DirID, short  WDRefNum, long  StrPtr )
{
  char              pBlk[128] = {};
  PLstrcpy( ((StringPtr)StrPtr), "\p" );
  *(long*)(pBlk + 48) = DirID;
  *(short*)(pBlk + 22) = WDRefNum;
  *(long*)(pBlk + 18) = StrPtr;
  *(short*)(pBlk + 28) = -1;
  if ( PBGetCatInfoSync( (void*)&pBlk ) )
  {
  PLstrcpy( ((StringPtr)StrPtr), "\pError" );
  } // 'end if'
  return 0;
} 

FBtoC 的众多内部函数之一

local fn DefinePointRecord
 dim as VarInfo  varInfo
 BlockZero( varInfo, sizeof( varInfo ) )
 varInfo.varType = _shortVarType // for fields
 fn SuppressTypedefs
 fn StartRecordDefinition( "Point" )
 fn AddFieldToRecordDefinition( "v", "", varInfo )
 fn AddFieldToRecordDefinition( "h", "", varInfo )
 fn FinishRecordDefinition
 fn DontSuppressTypedefs
end fn
long DefinePointRecord()
{
  VarInfo           varInfo;
  BlockZero( &varInfo, sizeof( varInfo ) );
  varInfo.varType =  3;
  SuppressTypedefs();
  StartRecordDefinition( PLstrcpy( gFBStrStk[++gFBStk], "\pPoint" ) );
  AddFieldToRecordDefinition( PLstrcpy( gFBStrStk[++gFBStk], "\pv" ), PLstrcpy( gFBStrStk[++gFBStk], "\p" ), &varInfo );
  AddFieldToRecordDefinition( PLstrcpy( gFBStrStk[++gFBStk], "\ph" ), PLstrcpy( gFBStrStk[++gFBStk], "\p" ), &varInfo );
  FinishRecordDefinition();
  DontSuppressTypedefs();
  return 0;
} 
华夏公益教科书