在Vs2013中使用FsLex/Yacc

5
我想重启一个旧的f#解析器项目,之前已经在vs 2008中实现,现在想要在vs 2013中使用。它使用FsLexYacc。
我通过以下预构建步骤成功构建了它:
fslex --unicode "$(ProjectDir)XpathLexer.fsl"
fsyacc --module XpathParser "$(ProjectDir)XpathParser.fsy"

但这不是最理想的,因为它总是会执行,无论输入是否发生了变化。
然后我尝试只使用旧的MsBuild操作:
<FsYacc Include="XpathParser.fsy">
<FsLex Include="XpathLexer.fsl">

但在构建过程中,这些似乎被完全忽略了。是这样吗?这些构建任务已经被某种方式移除了吗?

然后我发现了一些在vs C++文档中记录的东西,我认为可能会起作用:

<CustomBuild Include="XpathParser.fsy">
  <Message>Calling FsYacc</Message>
  <Command>fsyacc --module XpathParser "$(ProjectDir)XpathParser.fsy"</Command>
  <Outputs>$(ProjectDir)XpathParser.fs</Outputs>
</CustomBuild>

并且

<PropertyGroup>
    <CustomBuildBeforeTargets>CoreCompile</CustomBuildBeforeTargets>
</PropertyGroup>

我检查了Microsoft.Fsharp.Targets文件,找到了“CoreCompile”目标。

然而,仍然没有成功。

有人能否解释一下是否真的可以将fslex/yacc正确地集成到vs 2013解决方案中,如果可以,如何实现呢?

3个回答

8
我认为那些工具不会默认随着Visual Studio一起安装 F#编译器,因此任务不存在。 我在 Visual Studio 2012 项目中执行了以下操作,但我希望在VS 2013中类似。 这是我必须遵循的步骤:
  1. 从Nuget安装FSharp.Powerpack。 这具有fslex和fsyacc工具以及构建任务和目标。
  2. 取消加载项目并编辑.fsproj文件。
  3. 添加FSharp.Powerpack.targets文件的导入语句。 这将添加CallFsLex和CallFsYacc构建目标。 我在 Microsoft.FSharp.targets 导入之后添加了这个:
    <Import Project="$(ProjectDir)\..\packages\FSPowerPack.Community.3.0.0.0\Tools\FSharp.PowerPack.targets" />

  4. 在文件顶部主PropertyGroup中添加三个属性: <FsYaccToolPath>..\packages\FSPowerPack.Community.3.0.0.0\Tools</FsYaccToolPath> <FsLexToolPath>..\packages\FSPowerPack.Community.3.0.0.0\Tools</FsLexToolPath> <FsLexUnicode>true</FsLexUnicode> 这告诉构建任务在哪里找到必要的工具,并设置fslex的unicode选项。

  5. 使用已导入的目标,需要使用FsLex和FsYacc项组定义要使用的输入文件。 您还需要为输出的.fs文件添加Compile项。 在ItemGroup部分中,您最终会得到以下类似的内容: <Compile Include="Sql.fs" />
    <FsYacc Include="SqlParser.fsp">
    <Module>SqlParser</Module>
    </FsYacc>
    <Compile Include="SqlParser.fsi" />
    <Compile Include="SqlParser.fs" />
    <FsLex Include="SqlLexer.fsl" />
    <Compile Include="SqlLexer.fs" />
你也可以通过引用FSharp.Powerpack.Build.Tasks.dll直接使用FsLex和FsYacc构建任务,但对我来说,这样更容易上手。

1
谢谢你的回复,Mike。可惜我还是没能让它起作用。编译过程完全忽略了lex/yacc输入。我尝试直接引用FSharp.Powerpack.Build.Tasks.dll,但还是没有成功。 - stephensong
这似乎符合我的经验。 - nicolas
@Mike z - 这个方法对我在VS2013上起作用了,但还需要添加一个步骤 - 我必须将FSharp.Core(4.3.0.0)从C:\ Program Files(x86)\ Reference Assemblies \ Microsoft \ FSharp \ .NETFramework \ v4.0 \ 4.3.0.0复制到fslex。我相信有更好的方法可以使用重定向和fslex.exe.config,但这个方法对我有效,我现在不会再去质疑它! - neil danson

1
这似乎起作用了 - 至少在我的经验中,如果您按照 此处 的详细说明使用单独的FsLexYacc NuGet包,然后将以下内容放入您的fsproj文件中(从github 示例中提取):
在所有其他导入旁边:
<Import Project="..\packages\FsLexYacc.6.0.4\bin\FsLexYacc.targets" />

等等,等等

然后是源文件:

<FsYacc Include="Parser.fsp">
  <OtherFlags>--module SqlParser</OtherFlags>
</FsYacc>
<FsLex Include="Lexer.fsl">
  <OtherFlags>--unicode</OtherFlags>
</FsLex>

无需做任何其他操作,除了编辑fsproj文件并安装nuget包。

1
这是我使用的方法(Windows 7 x64,Visual Studio 2013 Ultimate RTM):
  1. 从CodePlex获取并安装“PowerPack for FSharp 3.0 + .NET 4.x + VS2012”(https://fsharppowerpack.codeplex.com/downloads/get/625449

  2. 创建以下注册表键:HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\AssemblyFolders\FSharp.PowerPack-1.9.9.9(对于Windows的x64版本,忽略32位版本的Wow6432Node),并将其(Default)值设置为F# PowerPack的安装目录(例如,“C:\Program Files (x86)\FSharpPowerPack-4.0.0.0\bin”)。[这与src/FSharp.PowerPack/CompilerLocationUtils.fs中的一个长期存在/回归性错误相关,基本上破坏了工具发现。]

  3. 在*.fsproj文件中导入PowerPack目标(在导入F#目标之后):<Import Project="$(MSBuildExtensionsPath32)\FSharp\1.0\FSharp.PowerPack.targets" />

  4. 将您的ItemGroup节点更新为类似以下内容(相应使用FsYacc):

    <ItemGroup>
      <None Include="App.config" />
      <FsLex Include="Lexer.fsl" />
      <Compile Include="Lexer.fs">
        <Visible>False</Visible>
      </Compile>
      <Compile Include="Program.fs" />
    </ItemGroup>
    
  5. 包含对FSharp.PowerPack.dll的引用并构建。

您应该最终得到一个类似于这样的 *.fsproj 文件:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <SchemaVersion>2.0</SchemaVersion>
    <ProjectGuid>8c565f99-d6bc-43a9-ace9-eadfe429c0f7</ProjectGuid>
    <OutputType>Exe</OutputType>
    <RootNamespace>FsYaccTest</RootNamespace>
    <AssemblyName>FsYaccTest</AssemblyName>
    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
    <TargetFSharpCoreVersion>4.3.1.0</TargetFSharpCoreVersion>
    <Name>FsYaccTest</Name>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
  <!-- Snip -->
  </PropertyGroup>
  <ItemGroup>
    <Reference Include="FSharp.PowerPack">
      <HintPath>C:\Program Files (x86)\FSharpPowerPack-4.0.0.0\bin\FSharp.PowerPack.dll</HintPath>
    </Reference>
    <Reference Include="mscorlib" />
    <Reference Include="FSharp.Core, Version=$(TargetFSharpCoreVersion), Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
      <Private>True</Private>
    </Reference>
    <Reference Include="System" />
    <Reference Include="System.Core" />
    <Reference Include="System.Numerics" />
  </ItemGroup>
  <PropertyGroup>
    <MinimumVisualStudioVersion Condition="'$(MinimumVisualStudioVersion)' == ''">11</MinimumVisualStudioVersion>
  </PropertyGroup>
  <Choose>
    <When Condition="'$(VisualStudioVersion)' == '11.0'">
      <PropertyGroup Condition="Exists('$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets')">
        <FSharpTargetsPath>$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets</FSharpTargetsPath>
      </PropertyGroup>
    </When>
    <Otherwise>
      <PropertyGroup Condition="Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets')">
        <FSharpTargetsPath>$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets</FSharpTargetsPath>
      </PropertyGroup>
    </Otherwise>
  </Choose>
  <Import Project="$(FSharpTargetsPath)" />  
  <Import Project="$(MSBuildExtensionsPath32)\FSharp\1.0\FSharp.PowerPack.targets" />  
  <PropertyGroup>
    <FsLexUnicode>true</FsLexUnicode>
  </PropertyGroup>
  <ItemGroup>
    <None Include="App.config" />
    <FsLex Include="Lexer.fsl" />
    <Compile Include="Lexer.fs">
      <Visible>False</Visible>
    </Compile>
    <Compile Include="Program.fs" />
  </ItemGroup>
</Project>

注意:如果您按照 Mike Z 的回答提供正确的 FsYaccToolPath,则可以省略创建注册表键。

1
谢谢。仅仅浏览你的回答就会让人意识到Fsharp.Powerpack为什么被放弃了 - 是吗?真的很古怪,甚至是奇怪的。我觉得F#因为这种愚蠢的问题而继续萎靡不振很令人悲哀。显然,微软并不认真对待F#。 - stephensong
F# PowerPack已从CodePlex移至GitHub(https://github.com/fsharp/powerpack),但即使在那里也没有太多活动。大部分功能现在都是在不同的项目中开发,而FsYacc和FsLex似乎已被放弃(尽管它们可能仍然用于F#编译器本身,显然仍在更新)。虽然我没有在任何地方找到官方声明,但微软目前似乎将更多精力投入到C++ / Win8而不是.NET总体上。 - JPW

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接