在Vs2013中使用FsLex / Yacc

时间:2013-11-05 02:53:11

标签: msbuild f# fsyacc

我正在尝试恢复我在vs 2008中与vs 2013一起工作的旧f#解析器项目。它使用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 个答案:

答案 0 :(得分:7)

我不认为这些工具默认包含在随Visual Studio一起安装的F#编译器中,因此任务不存在。我使用Visual Studio 2012项目执行了以下操作,但我希望它在VS 2013中类似。以下是我必须遵循的步骤:

  1. 从nuget安装FSharp.Powerpack。这有fslex和fsyacc工具以及构建任务和目标。
  2. 卸载项目并编辑.fsproj文件。
  3. 为FSharp.Powerpack.target文件添加import语句。这将添加CallFsLexCallFsYacc构建目标。我在导入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" />
  6. 您可以通过引用FSharp.Powerpack.Build.Tasks.dll直接使用FsLex和FsYacc构建任务,但对我来说这更容易开始。

答案 1 :(得分: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(对于x64版本的Windows,省略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和构建的引用。

  6. 你应该得到一个与此类似的* .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>
    

    注意:如果你提供正确的FsYaccToolPath,你可以省略创建注册表项,如mike z的回答所述。

答案 2 :(得分:1)

这看起来很有效 - 至少,根据我的经验,如果你使用单独的FsLexYacc nuget包作为详细的here,然后将以下内容放在你的fsproj文件中(从github {{3}中提取) }):

在所有其他导入旁边:

<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软件包。