Example #1
0
 /**
  * @param args
  * @throws IOException
  */
 public static void main(String[] args) throws IOException {
   Lex lex = new Lex("input3.txt");
   TopDown topDown = new TopDown(lex.getTokens(), lex.getSymbolTable());
   topDown.parse();
   System.out.println("输出符号表");
   for (Symbol symbol : topDown.symbolTable.values()) System.out.println(symbol);
 }
  @Test
  public void createLexYaccBuildRules() throws IOException {
    BuildRuleResolver resolver = new BuildRuleResolver();

    // Setup our C++ buck config with the paths to the lex/yacc binaries.
    FakeProjectFilesystem filesystem = new FakeProjectFilesystem();
    Path lexPath = Paths.get("lex");
    filesystem.touch(lexPath);
    Path yaccPath = Paths.get("yacc");
    filesystem.touch(yaccPath);
    BuckConfig buckConfig =
        FakeBuckConfig.builder()
            .setSections(
                ImmutableMap.of(
                    "cxx",
                    ImmutableMap.of(
                        "lex", lexPath.toString(),
                        "yacc", yaccPath.toString())))
            .setFilesystem(filesystem)
            .build();
    CxxPlatform cxxBuckConfig = DefaultCxxPlatforms.build(new CxxBuckConfig(buckConfig));

    // Setup the target name and build params.
    UnflavoredBuildTarget target =
        BuildTargetFactory.newInstance("//:test").getUnflavoredBuildTarget();
    BuildRuleParams params = new FakeBuildRuleParamsBuilder(BuildTarget.of(target)).build();

    // Setup a genrule that generates our lex source.
    String lexSourceName = "test.ll";
    BuildTarget genruleTarget = BuildTargetFactory.newInstance("//:genrule_lex");
    Genrule genrule =
        (Genrule)
            GenruleBuilder.newGenruleBuilder(genruleTarget).setOut(lexSourceName).build(resolver);
    SourcePath lexSource = new BuildTargetSourcePath(genrule.getBuildTarget());

    // Use a regular path for our yacc source.
    String yaccSourceName = "test.yy";
    SourcePath yaccSource = new TestSourcePath(yaccSourceName);

    // Build the rules.
    CxxHeaderSourceSpec actual =
        CxxDescriptionEnhancer.createLexYaccBuildRules(
            params,
            resolver,
            cxxBuckConfig,
            ImmutableList.<String>of(),
            ImmutableMap.of(lexSourceName, lexSource),
            ImmutableList.<String>of(),
            ImmutableMap.of(yaccSourceName, yaccSource));

    // Grab the generated lex rule and verify it has the genrule as a dep.
    Lex lex =
        (Lex) resolver.getRule(CxxDescriptionEnhancer.createLexBuildTarget(target, lexSourceName));
    assertNotNull(lex);
    assertEquals(ImmutableSortedSet.<BuildRule>of(genrule), lex.getDeps());

    // Grab the generated yacc rule and verify it has no deps.
    Yacc yacc =
        (Yacc)
            resolver.getRule(CxxDescriptionEnhancer.createYaccBuildTarget(target, yaccSourceName));
    assertNotNull(yacc);
    assertEquals(ImmutableSortedSet.<BuildRule>of(), yacc.getDeps());

    // Check the header/source spec is correct.
    Path lexOutputSource = CxxDescriptionEnhancer.getLexSourceOutputPath(target, lexSourceName);
    Path lexOutputHeader = CxxDescriptionEnhancer.getLexHeaderOutputPath(target, lexSourceName);
    Path yaccOutputPrefix =
        CxxDescriptionEnhancer.getYaccOutputPrefix(
            target, Files.getNameWithoutExtension(yaccSourceName));
    Path yaccOutputSource = Yacc.getSourceOutputPath(yaccOutputPrefix);
    Path yaccOutputHeader = Yacc.getHeaderOutputPath(yaccOutputPrefix);
    CxxHeaderSourceSpec expected =
        CxxHeaderSourceSpec.of(
            ImmutableMap.<Path, SourcePath>of(
                target.getBasePath().resolve(lexSourceName + ".h"),
                new BuildTargetSourcePath(lex.getBuildTarget(), lexOutputHeader),
                target.getBasePath().resolve(yaccSourceName + ".h"),
                new BuildTargetSourcePath(yacc.getBuildTarget(), yaccOutputHeader)),
            ImmutableMap.of(
                lexSourceName + ".cc",
                CxxSource.of(
                    CxxSource.Type.CXX,
                    new BuildTargetSourcePath(lex.getBuildTarget(), lexOutputSource),
                    ImmutableList.<String>of()),
                yaccSourceName + ".cc",
                CxxSource.of(
                    CxxSource.Type.CXX,
                    new BuildTargetSourcePath(yacc.getBuildTarget(), yaccOutputSource),
                    ImmutableList.<String>of())));
    assertEquals(expected, actual);
  }
  /**
   * Generate {@link Lex} and {@link Yacc} rules generating C/C++ sources from the given lex/yacc
   * sources.
   *
   * @return {@link CxxHeaderSourceSpec} containing the generated headers/sources
   */
  public static CxxHeaderSourceSpec createLexYaccBuildRules(
      BuildRuleParams params,
      BuildRuleResolver resolver,
      CxxPlatform cxxPlatform,
      ImmutableList<String> lexFlags,
      ImmutableMap<String, SourcePath> lexSrcs,
      ImmutableList<String> yaccFlags,
      ImmutableMap<String, SourcePath> yaccSrcs) {
    if (!lexSrcs.isEmpty() && !cxxPlatform.getLex().isPresent()) {
      throw new HumanReadableException(
          "Platform %s must support lex to compile srcs %s", cxxPlatform, lexSrcs);
    }

    if (!yaccSrcs.isEmpty() && !cxxPlatform.getYacc().isPresent()) {
      throw new HumanReadableException(
          "Platform %s must support yacc to compile srcs %s", cxxPlatform, yaccSrcs);
    }

    SourcePathResolver pathResolver = new SourcePathResolver(resolver);

    ImmutableMap.Builder<String, CxxSource> lexYaccCxxSourcesBuilder = ImmutableMap.builder();
    ImmutableMap.Builder<Path, SourcePath> lexYaccHeadersBuilder = ImmutableMap.builder();

    // Loop over all lex sources, generating build rule for each one and adding the sources
    // and headers it generates to our bookkeeping maps.
    UnflavoredBuildTarget unflavoredBuildTarget =
        params.getBuildTarget().getUnflavoredBuildTarget();
    for (ImmutableMap.Entry<String, SourcePath> ent : lexSrcs.entrySet()) {
      final String name = ent.getKey();
      final SourcePath source = ent.getValue();

      BuildTarget target = createLexBuildTarget(unflavoredBuildTarget, name);
      Path outputSource = getLexSourceOutputPath(unflavoredBuildTarget, name);
      Path outputHeader = getLexHeaderOutputPath(unflavoredBuildTarget, name);

      // Create the build rule to run lex on this source and add it to the resolver.
      Lex lex =
          new Lex(
              params.copyWithChanges(
                  target,
                  Suppliers.ofInstance(
                      ImmutableSortedSet.copyOf(
                          pathResolver.filterBuildRuleInputs(ImmutableList.of(source)))),
                  Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of())),
              pathResolver,
              cxxPlatform.getLex().get(),
              ImmutableList.<String>builder()
                  .addAll(cxxPlatform.getLexFlags())
                  .addAll(lexFlags)
                  .build(),
              outputSource,
              outputHeader,
              source);
      resolver.addToIndex(lex);

      // Record the output source and header as {@link BuildRuleSourcePath} objects.
      lexYaccCxxSourcesBuilder.put(
          name + ".cc",
          CxxSource.of(
              CxxSource.Type.CXX,
              new BuildTargetSourcePath(lex.getBuildTarget(), outputSource),
              ImmutableList.<String>of()));
      lexYaccHeadersBuilder.put(
          params.getBuildTarget().getBasePath().resolve(name + ".h"),
          new BuildTargetSourcePath(lex.getBuildTarget(), outputHeader));
    }

    // Loop over all yaccc sources, generating build rule for each one and adding the sources
    // and headers it generates to our bookkeeping maps.
    for (ImmutableMap.Entry<String, SourcePath> ent : yaccSrcs.entrySet()) {
      final String name = ent.getKey();
      final SourcePath source = ent.getValue();

      BuildTarget target = createYaccBuildTarget(unflavoredBuildTarget, name);
      Path outputPrefix =
          getYaccOutputPrefix(unflavoredBuildTarget, Files.getNameWithoutExtension(name));

      // Create the build rule to run yacc on this source and add it to the resolver.
      Yacc yacc =
          new Yacc(
              params.copyWithChanges(
                  target,
                  Suppliers.ofInstance(
                      ImmutableSortedSet.copyOf(
                          pathResolver.filterBuildRuleInputs(ImmutableList.of(source)))),
                  Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of())),
              pathResolver,
              cxxPlatform.getYacc().get(),
              ImmutableList.<String>builder()
                  .addAll(cxxPlatform.getYaccFlags())
                  .addAll(yaccFlags)
                  .build(),
              outputPrefix,
              source);
      resolver.addToIndex(yacc);

      // Record the output source and header as {@link BuildRuleSourcePath} objects.
      lexYaccCxxSourcesBuilder.put(
          name + ".cc",
          CxxSource.of(
              CxxSource.Type.CXX,
              new BuildTargetSourcePath(
                  yacc.getBuildTarget(), Yacc.getSourceOutputPath(outputPrefix)),
              ImmutableList.<String>of()));

      lexYaccHeadersBuilder.put(
          params.getBuildTarget().getBasePath().resolve(name + ".h"),
          new BuildTargetSourcePath(yacc.getBuildTarget(), Yacc.getHeaderOutputPath(outputPrefix)));
    }

    return CxxHeaderSourceSpec.of(lexYaccHeadersBuilder.build(), lexYaccCxxSourcesBuilder.build());
  }