<commit_before>//===- GenerateCode.cpp - Functions for generating executable files  ------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains functions for generating executable files once linking
// has finished.  This includes generating a shell script to run the JIT or
// a native executable derived from the bytecode.
//
//===----------------------------------------------------------------------===//

#include "gccld.h"
#include "llvm/Linker.h"
#include "llvm/Module.h"
#include "llvm/PassManager.h"
#include "llvm/Analysis/LoadValueNumbering.h"
#include "llvm/Analysis/Passes.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/Bytecode/WriteBytecodePass.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Support/SystemUtils.h"
#include "llvm/Support/CommandLine.h"
using namespace llvm;

namespace {
  cl::opt<bool>
  DisableInline("disable-inlining", cl::desc("Do not run the inliner pass"));

  cl::opt<bool>
  Verify("verify", cl::desc("Verify intermediate results of all passes"));

  cl::opt<bool>
  DisableOptimizations("disable-opt",
                       cl::desc("Do not run any optimization passes"));
}

/// CopyEnv - This function takes an array of environment variables and makes a
/// copy of it.  This copy can then be manipulated any way the caller likes
/// without affecting the process's real environment.
///
/// Inputs:
///  envp - An array of C strings containing an environment.
///
/// Return value:
///  NULL - An error occurred.
///
///  Otherwise, a pointer to a new array of C strings is returned.  Every string
///  in the array is a duplicate of the one in the original array (i.e. we do
///  not copy the char *'s from one array to another).
///
static char ** CopyEnv(char ** const envp) {
  // Count the number of entries in the old list;
  unsigned entries;   // The number of entries in the old environment list
  for (entries = 0; envp[entries] != NULL; entries++)
    /*empty*/;

  // Add one more entry for the NULL pointer that ends the list.
  ++entries;

  // If there are no entries at all, just return NULL.
  if (entries == 0)
    return NULL;

  // Allocate a new environment list.
  char **newenv = new char* [entries];
  if ((newenv = new char* [entries]) == NULL)
    return NULL;

  // Make a copy of the list.  Don't forget the NULL that ends the list.
  entries = 0;
  while (envp[entries] != NULL) {
    newenv[entries] = new char[strlen (envp[entries]) + 1];
    strcpy (newenv[entries], envp[entries]);
    ++entries;
  }
  newenv[entries] = NULL;

  return newenv;
}

/// RemoveEnv - Remove the specified environment variable from the environment
/// array.
///
/// Inputs:
///  name - The name of the variable to remove.  It cannot be NULL.
///  envp - The array of environment variables.  It cannot be NULL.
///
/// Notes:
///  This is mainly done because functions to remove items from the environment
///  are not available across all platforms.  In particular, Solaris does not
///  seem to have an unsetenv() function or a setenv() function (or they are
///  undocumented if they do exist).
///
static void RemoveEnv(const char * name, char ** const envp) {
  for (unsigned index=0; envp[index] != NULL; index++) {
    // Find the first equals sign in the array and make it an EOS character.
    char *p = strchr (envp[index], '=');
    if (p == NULL)
      continue;
    else
      *p = '\0';

    // Compare the two strings.  If they are equal, zap this string.
    // Otherwise, restore it.
    if (!strcmp(name, envp[index]))
      *envp[index] = '\0';
    else
      *p = '=';
  }

  return;
}

static inline void addPass(PassManager &PM, Pass *P) {
  // Add the pass to the pass manager...
  PM.add(P);

  // If we are verifying all of the intermediate steps, add the verifier...
  if (Verify) PM.add(createVerifierPass());
}

/// GenerateBytecode - generates a bytecode file from the specified module.
///
/// Inputs:
///  M           - The module for which bytecode should be generated.
///  StripLevel  - 2 if we should strip all symbols, 1 if we should strip
///                debug info.
///  Internalize - Flags whether all symbols should be marked internal.
///  Out         - Pointer to file stream to which to write the output.
///
/// Returns non-zero value on error.
///
int llvm::GenerateBytecode(Module *M, int StripLevel, bool Internalize,
                           std::ostream *Out) {
  // In addition to just linking the input from GCC, we also want to spiff it up
  // a little bit.  Do this now.
  PassManager Passes;

  if (Verify) Passes.add(createVerifierPass());

  // Add an appropriate TargetData instance for this module...
  addPass(Passes, new TargetData("gccld", M));

  // Often if the programmer does not specify proper prototypes for the
  // functions they are calling, they end up calling a vararg version of the
  // function that does not get a body filled in (the real function has typed
  // arguments).  This pass merges the two functions.
  addPass(Passes, createFunctionResolvingPass());

  if (!DisableOptimizations) {
    if (Internalize) {
      // Now that composite has been compiled, scan through the module, looking
      // for a main function.  If main is defined, mark all other functions
      // internal.
      addPass(Passes, createInternalizePass());
    }

    // Now that we internalized some globals, see if we can hack on them!
    addPass(Passes, createGlobalOptimizerPass());

    // Linking modules together can lead to duplicated global constants, only
    // keep one copy of each constant...
    addPass(Passes, createConstantMergePass());

    // Propagate constants at call sites into the functions they call.
    addPass(Passes, createIPConstantPropagationPass());

    // Remove unused arguments from functions...
    addPass(Passes, createDeadArgEliminationPass());

    if (!DisableInline)
      addPass(Passes, createFunctionInliningPass()); // Inline small functions

    addPass(Passes, createPruneEHPass());            // Remove dead EH info
    addPass(Passes, createGlobalOptimizerPass());    // Optimize globals again.
    addPass(Passes, createGlobalDCEPass());          // Remove dead functions

    // If we didn't decide to inline a function, check to see if we can
    // transform it to pass arguments by value instead of by reference.
    addPass(Passes, createArgumentPromotionPass());

    // The IPO passes may leave cruft around.  Clean up after them.
    addPass(Passes, createInstructionCombiningPass());

    addPass(Passes, createScalarReplAggregatesPass()); // Break up allocas

    // Run a few AA driven optimizations here and now, to cleanup the code.
    addPass(Passes, createGlobalsModRefPass());      // IP alias analysis

    addPass(Passes, createLICMPass());               // Hoist loop invariants
    addPass(Passes, createLoadValueNumberingPass()); // GVN for load instrs
    addPass(Passes, createGCSEPass());               // Remove common subexprs
    addPass(Passes, createDeadStoreEliminationPass()); // Nuke dead stores

    // Cleanup and simplify the code after the scalar optimizations.
    addPass(Passes, createInstructionCombiningPass());

    // Delete basic blocks, which optimization passes may have killed...
    addPass(Passes, createCFGSimplificationPass());

    // Now that we have optimized the program, discard unreachable functions...
    addPass(Passes, createGlobalDCEPass());
  }

  // If the -s or -S command line options were specified, strip the symbols out
  // of the resulting program to make it smaller.  -s and -S are GLD options
  // that we are supporting.
  if (StripLevel)
    addPass(Passes, createStripSymbolsPass(StripLevel == 1));

  // Make sure everything is still good.
  Passes.add(createVerifierPass());

  // Add the pass that writes bytecode to the output file...
  addPass(Passes, new WriteBytecodePass(Out));

  // Run our queue of passes all at once now, efficiently.
  Passes.run(*M);

  return 0;
}

/// GenerateAssembly - generates a native assembly language source file from the
/// specified bytecode file.
///
/// Inputs:
///  InputFilename  - The name of the output bytecode file.
///  OutputFilename - The name of the file to generate.
///  llc            - The pathname to use for LLC.
///  envp           - The environment to use when running LLC.
///
/// Return non-zero value on error.
///
int llvm::GenerateAssembly(const std::string &OutputFilename,
                           const std::string &InputFilename,
                           const std::string &llc,
                           char ** const envp) {
  // Run LLC to convert the bytecode file into assembly code.
  const char *cmd[6];
  cmd[0] = llc.c_str();
  cmd[1] = "-f";
  cmd[2] = "-o";
  cmd[3] = OutputFilename.c_str();
  cmd[4] = InputFilename.c_str();
  cmd[5] = 0;

  return ExecWait(cmd, envp);
}

/// GenerateAssembly - generates a native assembly language source file from the
/// specified bytecode file.
int llvm::GenerateCFile(const std::string &OutputFile,
                        const std::string &InputFile,
                        const std::string &llc, char ** const envp) {
  // Run LLC to convert the bytecode file into C.
  const char *cmd[7];

  cmd[0] = llc.c_str();
  cmd[1] = "-march=c";
  cmd[2] = "-f";
  cmd[3] = "-o";
  cmd[4] = OutputFile.c_str();
  cmd[5] = InputFile.c_str();
  cmd[6] = 0;
  return ExecWait(cmd, envp);
}

/// GenerateNative - generates a native assembly language source file from the
/// specified assembly source file.
///
/// Inputs:
///  InputFilename  - The name of the output bytecode file.
///  OutputFilename - The name of the file to generate.
///  Libraries      - The list of libraries with which to link.
///  LibPaths       - The list of directories in which to find libraries.
///  gcc            - The pathname to use for GGC.
///  envp           - A copy of the process's current environment.
///
/// Outputs:
///  None.
///
/// Returns non-zero value on error.
///
int llvm::GenerateNative(const std::string &OutputFilename,
                         const std::string &InputFilename,
                         const std::vector<std::string> &Libraries,
                         const std::vector<std::string> &LibPaths,
                         const std::string &gcc, char ** const envp) {
  // Remove these environment variables from the environment of the
  // programs that we will execute.  It appears that GCC sets these
  // environment variables so that the programs it uses can configure
  // themselves identically.
  //
  // However, when we invoke GCC below, we want it to use its normal
  // configuration.  Hence, we must sanitize its environment.
  char ** clean_env = CopyEnv(envp);
  if (clean_env == NULL)
    return 1;
  RemoveEnv("LIBRARY_PATH", clean_env);
  RemoveEnv("COLLECT_GCC_OPTIONS", clean_env);
  RemoveEnv("GCC_EXEC_PREFIX", clean_env);
  RemoveEnv("COMPILER_PATH", clean_env);
  RemoveEnv("COLLECT_GCC", clean_env);

  std::vector<const char *> cmd;

  // Run GCC to assemble and link the program into native code.
  //
  // Note:
  //  We can't just assemble and link the file with the system assembler
  //  and linker because we don't know where to put the _start symbol.
  //  GCC mysteriously knows how to do it.
  cmd.push_back(gcc.c_str());
  cmd.push_back("-fno-strict-aliasing");
  cmd.push_back("-O3");
  cmd.push_back("-o");
  cmd.push_back(OutputFilename.c_str());
  cmd.push_back(InputFilename.c_str());

  // Adding the library paths creates a problem for native generation.  If we
  // include the search paths from llvmgcc, then we'll be telling normal gcc
  // to look inside of llvmgcc's library directories for libraries.  This is
  // bad because those libraries hold only bytecode files (not native object
  // files).  In the end, we attempt to link the bytecode libgcc into a native
  // program.
#if 0
  // Add in the library path options.
  for (unsigned index=0; index < LibPaths.size(); index++) {
    cmd.push_back("-L");
    cmd.push_back(LibPaths[index].c_str());
  }
#endif

  // Add in the libraries to link.
  std::vector<std::string> Libs(Libraries);
  for (unsigned index = 0; index < Libs.size(); index++) {
    if (Libs[index] != "crtend") {
      Libs[index] = "-l" + Libs[index];
      cmd.push_back(Libs[index].c_str());
    }
  }
  cmd.push_back(NULL);

  // Run the compiler to assembly and link together the program.
  return ExecWait(&(cmd[0]), clean_env);
}

<commit_msg>Turn on ipsccp by default instead of simple IPCP<commit_after>//===- GenerateCode.cpp - Functions for generating executable files  ------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains functions for generating executable files once linking
// has finished.  This includes generating a shell script to run the JIT or
// a native executable derived from the bytecode.
//
//===----------------------------------------------------------------------===//

#include "gccld.h"
#include "llvm/Linker.h"
#include "llvm/Module.h"
#include "llvm/PassManager.h"
#include "llvm/Analysis/LoadValueNumbering.h"
#include "llvm/Analysis/Passes.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/Bytecode/WriteBytecodePass.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Support/SystemUtils.h"
#include "llvm/Support/CommandLine.h"
using namespace llvm;

namespace {
  cl::opt<bool>
  DisableInline("disable-inlining", cl::desc("Do not run the inliner pass"));

  cl::opt<bool>
  Verify("verify", cl::desc("Verify intermediate results of all passes"));

  cl::opt<bool>
  DisableOptimizations("disable-opt",
                       cl::desc("Do not run any optimization passes"));
}

/// CopyEnv - This function takes an array of environment variables and makes a
/// copy of it.  This copy can then be manipulated any way the caller likes
/// without affecting the process's real environment.
///
/// Inputs:
///  envp - An array of C strings containing an environment.
///
/// Return value:
///  NULL - An error occurred.
///
///  Otherwise, a pointer to a new array of C strings is returned.  Every string
///  in the array is a duplicate of the one in the original array (i.e. we do
///  not copy the char *'s from one array to another).
///
static char ** CopyEnv(char ** const envp) {
  // Count the number of entries in the old list;
  unsigned entries;   // The number of entries in the old environment list
  for (entries = 0; envp[entries] != NULL; entries++)
    /*empty*/;

  // Add one more entry for the NULL pointer that ends the list.
  ++entries;

  // If there are no entries at all, just return NULL.
  if (entries == 0)
    return NULL;

  // Allocate a new environment list.
  char **newenv = new char* [entries];
  if ((newenv = new char* [entries]) == NULL)
    return NULL;

  // Make a copy of the list.  Don't forget the NULL that ends the list.
  entries = 0;
  while (envp[entries] != NULL) {
    newenv[entries] = new char[strlen (envp[entries]) + 1];
    strcpy (newenv[entries], envp[entries]);
    ++entries;
  }
  newenv[entries] = NULL;

  return newenv;
}

/// RemoveEnv - Remove the specified environment variable from the environment
/// array.
///
/// Inputs:
///  name - The name of the variable to remove.  It cannot be NULL.
///  envp - The array of environment variables.  It cannot be NULL.
///
/// Notes:
///  This is mainly done because functions to remove items from the environment
///  are not available across all platforms.  In particular, Solaris does not
///  seem to have an unsetenv() function or a setenv() function (or they are
///  undocumented if they do exist).
///
static void RemoveEnv(const char * name, char ** const envp) {
  for (unsigned index=0; envp[index] != NULL; index++) {
    // Find the first equals sign in the array and make it an EOS character.
    char *p = strchr (envp[index], '=');
    if (p == NULL)
      continue;
    else
      *p = '\0';

    // Compare the two strings.  If they are equal, zap this string.
    // Otherwise, restore it.
    if (!strcmp(name, envp[index]))
      *envp[index] = '\0';
    else
      *p = '=';
  }

  return;
}

static inline void addPass(PassManager &PM, Pass *P) {
  // Add the pass to the pass manager...
  PM.add(P);

  // If we are verifying all of the intermediate steps, add the verifier...
  if (Verify) PM.add(createVerifierPass());
}

/// GenerateBytecode - generates a bytecode file from the specified module.
///
/// Inputs:
///  M           - The module for which bytecode should be generated.
///  StripLevel  - 2 if we should strip all symbols, 1 if we should strip
///                debug info.
///  Internalize - Flags whether all symbols should be marked internal.
///  Out         - Pointer to file stream to which to write the output.
///
/// Returns non-zero value on error.
///
int llvm::GenerateBytecode(Module *M, int StripLevel, bool Internalize,
                           std::ostream *Out) {
  // In addition to just linking the input from GCC, we also want to spiff it up
  // a little bit.  Do this now.
  PassManager Passes;

  if (Verify) Passes.add(createVerifierPass());

  // Add an appropriate TargetData instance for this module...
  addPass(Passes, new TargetData("gccld", M));

  // Often if the programmer does not specify proper prototypes for the
  // functions they are calling, they end up calling a vararg version of the
  // function that does not get a body filled in (the real function has typed
  // arguments).  This pass merges the two functions.
  addPass(Passes, createFunctionResolvingPass());

  if (!DisableOptimizations) {
    if (Internalize) {
      // Now that composite has been compiled, scan through the module, looking
      // for a main function.  If main is defined, mark all other functions
      // internal.
      addPass(Passes, createInternalizePass());
    }

    // Now that we internalized some globals, see if we can hack on them!
    addPass(Passes, createGlobalOptimizerPass());

    // Linking modules together can lead to duplicated global constants, only
    // keep one copy of each constant...
    addPass(Passes, createConstantMergePass());

    // Propagate constants at call sites into the functions they call.
    addPass(Passes, createIPSCCPPass());
    addPass(Passes, createCFGSimplificationPass());

    // Remove unused arguments from functions...
    addPass(Passes, createDeadArgEliminationPass());

    if (!DisableInline)
      addPass(Passes, createFunctionInliningPass()); // Inline small functions

    addPass(Passes, createPruneEHPass());            // Remove dead EH info
    addPass(Passes, createGlobalOptimizerPass());    // Optimize globals again.
    addPass(Passes, createGlobalDCEPass());          // Remove dead functions

    // If we didn't decide to inline a function, check to see if we can
    // transform it to pass arguments by value instead of by reference.
    addPass(Passes, createArgumentPromotionPass());

    // The IPO passes may leave cruft around.  Clean up after them.
    addPass(Passes, createInstructionCombiningPass());

    addPass(Passes, createScalarReplAggregatesPass()); // Break up allocas

    // Run a few AA driven optimizations here and now, to cleanup the code.
    addPass(Passes, createGlobalsModRefPass());      // IP alias analysis

    addPass(Passes, createLICMPass());               // Hoist loop invariants
    addPass(Passes, createLoadValueNumberingPass()); // GVN for load instrs
    addPass(Passes, createGCSEPass());               // Remove common subexprs
    addPass(Passes, createDeadStoreEliminationPass()); // Nuke dead stores

    // Cleanup and simplify the code after the scalar optimizations.
    addPass(Passes, createInstructionCombiningPass());

    // Delete basic blocks, which optimization passes may have killed...
    addPass(Passes, createCFGSimplificationPass());

    // Now that we have optimized the program, discard unreachable functions...
    addPass(Passes, createGlobalDCEPass());
  }

  // If the -s or -S command line options were specified, strip the symbols out
  // of the resulting program to make it smaller.  -s and -S are GLD options
  // that we are supporting.
  if (StripLevel)
    addPass(Passes, createStripSymbolsPass(StripLevel == 1));

  // Make sure everything is still good.
  Passes.add(createVerifierPass());

  // Add the pass that writes bytecode to the output file...
  addPass(Passes, new WriteBytecodePass(Out));

  // Run our queue of passes all at once now, efficiently.
  Passes.run(*M);

  return 0;
}

/// GenerateAssembly - generates a native assembly language source file from the
/// specified bytecode file.
///
/// Inputs:
///  InputFilename  - The name of the output bytecode file.
///  OutputFilename - The name of the file to generate.
///  llc            - The pathname to use for LLC.
///  envp           - The environment to use when running LLC.
///
/// Return non-zero value on error.
///
int llvm::GenerateAssembly(const std::string &OutputFilename,
                           const std::string &InputFilename,
                           const std::string &llc,
                           char ** const envp) {
  // Run LLC to convert the bytecode file into assembly code.
  const char *cmd[6];
  cmd[0] = llc.c_str();
  cmd[1] = "-f";
  cmd[2] = "-o";
  cmd[3] = OutputFilename.c_str();
  cmd[4] = InputFilename.c_str();
  cmd[5] = 0;

  return ExecWait(cmd, envp);
}

/// GenerateAssembly - generates a native assembly language source file from the
/// specified bytecode file.
int llvm::GenerateCFile(const std::string &OutputFile,
                        const std::string &InputFile,
                        const std::string &llc, char ** const envp) {
  // Run LLC to convert the bytecode file into C.
  const char *cmd[7];

  cmd[0] = llc.c_str();
  cmd[1] = "-march=c";
  cmd[2] = "-f";
  cmd[3] = "-o";
  cmd[4] = OutputFile.c_str();
  cmd[5] = InputFile.c_str();
  cmd[6] = 0;
  return ExecWait(cmd, envp);
}

/// GenerateNative - generates a native assembly language source file from the
/// specified assembly source file.
///
/// Inputs:
///  InputFilename  - The name of the output bytecode file.
///  OutputFilename - The name of the file to generate.
///  Libraries      - The list of libraries with which to link.
///  LibPaths       - The list of directories in which to find libraries.
///  gcc            - The pathname to use for GGC.
///  envp           - A copy of the process's current environment.
///
/// Outputs:
///  None.
///
/// Returns non-zero value on error.
///
int llvm::GenerateNative(const std::string &OutputFilename,
                         const std::string &InputFilename,
                         const std::vector<std::string> &Libraries,
                         const std::vector<std::string> &LibPaths,
                         const std::string &gcc, char ** const envp) {
  // Remove these environment variables from the environment of the
  // programs that we will execute.  It appears that GCC sets these
  // environment variables so that the programs it uses can configure
  // themselves identically.
  //
  // However, when we invoke GCC below, we want it to use its normal
  // configuration.  Hence, we must sanitize its environment.
  char ** clean_env = CopyEnv(envp);
  if (clean_env == NULL)
    return 1;
  RemoveEnv("LIBRARY_PATH", clean_env);
  RemoveEnv("COLLECT_GCC_OPTIONS", clean_env);
  RemoveEnv("GCC_EXEC_PREFIX", clean_env);
  RemoveEnv("COMPILER_PATH", clean_env);
  RemoveEnv("COLLECT_GCC", clean_env);

  std::vector<const char *> cmd;

  // Run GCC to assemble and link the program into native code.
  //
  // Note:
  //  We can't just assemble and link the file with the system assembler
  //  and linker because we don't know where to put the _start symbol.
  //  GCC mysteriously knows how to do it.
  cmd.push_back(gcc.c_str());
  cmd.push_back("-fno-strict-aliasing");
  cmd.push_back("-O3");
  cmd.push_back("-o");
  cmd.push_back(OutputFilename.c_str());
  cmd.push_back(InputFilename.c_str());

  // Adding the library paths creates a problem for native generation.  If we
  // include the search paths from llvmgcc, then we'll be telling normal gcc
  // to look inside of llvmgcc's library directories for libraries.  This is
  // bad because those libraries hold only bytecode files (not native object
  // files).  In the end, we attempt to link the bytecode libgcc into a native
  // program.
#if 0
  // Add in the library path options.
  for (unsigned index=0; index < LibPaths.size(); index++) {
    cmd.push_back("-L");
    cmd.push_back(LibPaths[index].c_str());
  }
#endif

  // Add in the libraries to link.
  std::vector<std::string> Libs(Libraries);
  for (unsigned index = 0; index < Libs.size(); index++) {
    if (Libs[index] != "crtend") {
      Libs[index] = "-l" + Libs[index];
      cmd.push_back(Libs[index].c_str());
    }
  }
  cmd.push_back(NULL);

  // Run the compiler to assembly and link together the program.
  return ExecWait(&(cmd[0]), clean_env);
}

<|endoftext|>


<commit_before>#include <cassert>
#include <fstream>
#include <iostream>
#include <strstream>

#include <util/PlatformUtils.hpp>

#include <PlatformSupport/DOMStringHelper.hpp>
#include <DOMSupport/DOMSupportDefault.hpp>

#include <XPath/XObjectFactoryDefault.hpp>
#include <XPath/XPathSupportDefault.hpp>
#include <XPath/XPathFactoryDefault.hpp>

#include <XSLT/StylesheetConstructionContextDefault.hpp>
#include <XSLT/StylesheetExecutionContextDefault.hpp>
#include <XSLT/StylesheetRoot.hpp>
#include <XSLT/XSLTEngineImpl.hpp>
#include <XSLT/XSLTInputSource.hpp>
#include <XSLT/XSLTProcessorEnvSupportDefault.hpp>
#include <XSLT/XSLTResultTarget.hpp>

#include <XercesParserLiaison/XercesParserLiaison.hpp>

#include <XercesPlatformSupport/TextFileOutputStream.hpp>
#include <XercesPlatformSupport/XercesDOMPrintWriter.hpp>

//This is here for the Windows threads.
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winbase.h>
#define THREADFUNCTIONRETURN DWORD WINAPI

#if !defined(XALAN_NO_NAMESPACES)
	using std::cerr;
	using std::cout;
	using std::endl;
	using std::ifstream;
	using std::ios_base;
	using std::ostrstream;
	using std::string;
#endif

// Used to hold compiled stylesheet, and XML source document.
StylesheetRoot* glbStylesheetRoot;
XSLTInputSource* glbSourceDoc;

// Print messages tracking the progress of each thread, and the
// beginning and end of the entire operation.
void outputMessage(DWORD id, char msg[])
{
		ostrstream threadMsg;

		threadMsg << "\n" << msg << " Thread: " << id << '\0';
		cout << threadMsg.str();
		threadMsg.freeze(false);
}

THREADFUNCTIONRETURN theThread(LPVOID	param)
{
// This routine uses a compiled stylesheet (glbStylesheetRoot),
// and a binary input source (glbSourceDoc) to perform the
// transformation.

	const int	number = reinterpret_cast<int>(param);
	const DWORD		theThreadID = GetCurrentThreadId();

	// Create the support objects that are necessary for running the processor...
	DOMSupportDefault				theDOMSupport;
	XercesParserLiaison				theParserLiaison(theDOMSupport);
	XPathSupportDefault				theXPathSupport(theDOMSupport);
	XSLTProcessorEnvSupportDefault	theXSLTProcessorEnvSupport;
	XObjectFactoryDefault			theXObjectFactory(theXSLTProcessorEnvSupport,
													  theXPathSupport);
	XPathFactoryDefault				theXPathFactory;

	// Create a processor...and output start message.
	XSLTEngineImpl	theProcessor(
					theParserLiaison,
					theXPathSupport,
					theXSLTProcessorEnvSupport,
					theXObjectFactory,
					theXPathFactory);
	outputMessage(theThreadID,"Starting ");

	// Connect the processor to the support object...
	theXSLTProcessorEnvSupport.setProcessor(&theProcessor);

	// The execution context uses the same factory support objects as
	// the processor, since those objects have the same lifetime as
	// other objects created as a result of the execution.
	StylesheetExecutionContextDefault	ssExecutionContext(
						theProcessor,
						theXSLTProcessorEnvSupport,
						theXPathSupport,
						theXObjectFactory);

	// Generate the output file name for this thread.
    ostrstream theFormatterOut;
    theFormatterOut << "birds" << number << ".out" << '\0';

	//Generate the XML output object.
	XSLTResultTarget	theResultTarget(theFormatterOut.str());

	// Unfreeze the ostrstream, so memory is returned...
	theFormatterOut.freeze(false);

	// Set the processor to use the compiled stylesheet. Then do the transform
  // with the process() method that uses the compiled stylesheet.
	// Report both the start of the transformation and the termination of the thread.
	theProcessor.setStylesheetRoot(glbStylesheetRoot);
	outputMessage(theThreadID,"Transforming");
  theProcessor.process(*glbSourceDoc,theResultTarget,ssExecutionContext);
	outputMessage(theThreadID,"Finishing");
	return (0);
}

// Create and run the threads...
// Print messages tracking the progress of each thread...
void doThreads(int x)
{
	DWORD dwStackSize = 4096;              	// initial thread stack size
	LPTHREAD_START_ROUTINE lpStartAddress = (LPTHREAD_START_ROUTINE)theThread;
	DWORD dwCreationFlags = 0;             	// creation flags
 	int nThreads = x;

	std::vector<HANDLE> hThreads;
	hThreads.reserve(nThreads);
 	int i=0;

	try
	{
		cout << endl << "Clock before starting threads: " << clock() << endl;

		for (i=0; i< nThreads; i++)
			{
				HANDLE hThread;
				DWORD  threadID;

				hThread = CreateThread(
					0, dwStackSize,
					lpStartAddress,					      // pointer to thread function
					reinterpret_cast<LPVOID>(i),	// argument for new thread
					dwCreationFlags,				      // creation flags
					&threadID);
				assert(hThread != 0);
				hThreads.push_back(hThread);
			}
		WaitForMultipleObjects(hThreads.size(), &hThreads[0], TRUE, INFINITE);

		cout << endl << "Clock after threads: " << clock() << endl;

		for (i=0; i< nThreads; i++)
			CloseHandle(hThreads[i]);
	}
	catch(...)
	{
		cerr << "Exception caught!!!"
			 << endl
			<< endl;
	}
}

int main(int argc, const char*	/* argv */[])
{

	if (argc != 1)
	{
		cerr << "Usage: ThreadTest"
			 << endl
			 << endl;
	}
	else
	{
		try
		{
			// Call the static initializers...
			XMLPlatformUtils::Initialize();
			XSLTEngineImpl::Initialize();

			// Create the support objects required to run the processor...
			DOMSupportDefault				        ssDOMSupport;
			XercesParserLiaison				      ssParserLiaison(ssDOMSupport);
			XPathSupportDefault				      ssXPathSupport(ssDOMSupport);
			XSLTProcessorEnvSupportDefault	ssXSLTProcessorEnvSupport;
			XObjectFactoryDefault			      ssXObjectFactory(ssXSLTProcessorEnvSupport,
															                         ssXPathSupport);
			XPathFactoryDefault				      ssXPathFactory;

			// Create a processor...
      // This processor is used to compile the stylesheet.
      // Each thread uses its own processor to perform a transformation.

			XSLTEngineImpl	ssProcessor(
      					  ssParserLiaison,
	      		    	ssXPathSupport,
		  	        	ssXSLTProcessorEnvSupport,
		    	  		  ssXObjectFactory,
        				  ssXPathFactory);

			// Create separate factory support objects so the stylesheet's
			// factory-created XObject and XPath instances are independent
			// from the processor's.
			XObjectFactoryDefault	ssStylesheetXObjectFactory(
									ssXSLTProcessorEnvSupport,
									ssXPathSupport);
			XPathFactoryDefault		ssStylesheetXPathFactory;

			// Create a stylesheet construction context, using the
			// stylesheet's factory support objects.
			StylesheetConstructionContextDefault	ssConstructionContext(
													ssProcessor,
													ssXSLTProcessorEnvSupport,
													ssStylesheetXObjectFactory,
													ssStylesheetXPathFactory);

			const XalanDOMString  theXSLFileName("birds.xsl");
			const XalanDOMString  theXMLFileName("birds.xml");

			// Our stylesheet input source...
			XSLTInputSource		ssStylesheetSourceXSL(c_wstr(theXSLFileName));

			// Use the processor to create a StylesheetRoot for the specified
			// input XSL.  This is the compiled stylesheet.  We don't have to
			// delete it, since it is owned by the StylesheetConstructionContext
			// instance.
			glbStylesheetRoot = ssProcessor.processStylesheet(ssStylesheetSourceXSL,
													   ssConstructionContext);
			assert(glbStylesheetRoot != 0);

			// Compile the XML source document as well. All threads will use
      // this binary representation of the source tree.
			glbSourceDoc = new XSLTInputSource(c_wstr(theXMLFileName));
      assert(glbSourceDoc != 0);

      // Create and run the threads...
      // Every thread uses the same XML input object
      // XSL stylesheet object to perform a transformation.
			doThreads(10);
		}
		catch(...)
		{
			cerr << "Exception caught!!!"
				 << endl
				 << endl;
		}
	}

	return 0;
}
<commit_msg>Changed input source global variable to a XalanNode.<commit_after>#include <cassert>
#include <fstream>
#include <iostream>
#include <strstream>

#include <util/PlatformUtils.hpp>

#include <PlatformSupport/DOMStringHelper.hpp>
#include <DOMSupport/DOMSupportDefault.hpp>

#include <XPath/XObjectFactoryDefault.hpp>
#include <XPath/XPathSupportDefault.hpp>
#include <XPath/XPathFactoryDefault.hpp>

#include <XSLT/StylesheetConstructionContextDefault.hpp>
#include <XSLT/StylesheetExecutionContextDefault.hpp>
#include <XSLT/StylesheetRoot.hpp>
#include <XSLT/XSLTEngineImpl.hpp>
#include <XSLT/XSLTInputSource.hpp>
#include <XSLT/XSLTProcessorEnvSupportDefault.hpp>
#include <XSLT/XSLTResultTarget.hpp>

#include <XercesParserLiaison/XercesParserLiaison.hpp>

#include <XercesPlatformSupport/TextFileOutputStream.hpp>
#include <XercesPlatformSupport/XercesDOMPrintWriter.hpp>

//This is here for the Windows threads.
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winbase.h>
#define THREADFUNCTIONRETURN DWORD WINAPI

#if !defined(XALAN_NO_NAMESPACES)
	using std::cerr;
	using std::cout;
	using std::endl;
	using std::ifstream;
	using std::ios_base;
	using std::ostrstream;
	using std::string;
#endif

// Used to hold compiled stylesheet and XML source document.
StylesheetRoot* glbStylesheetRoot;
XalanNode* glbDocSource;

// Print messages tracking the progress of each thread, and the
// beginning and end of the entire operation.
void outputMessage(DWORD id, char msg[])
{
		ostrstream threadMsg;

		threadMsg << "\n" << msg << " Thread: " << id << '\0';
		cout << threadMsg.str();
		threadMsg.freeze(false);
}

THREADFUNCTIONRETURN theThread(LPVOID	param)
{
// This routine uses a compiled stylesheet (glbStylesheetRoot),
// and a binary source tree (glbSourceDoc) to perform the
// transformation.

	const int	number = reinterpret_cast<int>(param);
	const DWORD		theThreadID = GetCurrentThreadId();

	// Create the support objects that are necessary for running the processor...
	DOMSupportDefault				theDOMSupport;
	XercesParserLiaison				theParserLiaison(theDOMSupport);
	XPathSupportDefault				theXPathSupport(theDOMSupport);
	XSLTProcessorEnvSupportDefault	theXSLTProcessorEnvSupport;
	XObjectFactoryDefault			theXObjectFactory(theXSLTProcessorEnvSupport,
													  theXPathSupport);
	XPathFactoryDefault				theXPathFactory;

	// Create a processor...and output the start message.
	XSLTEngineImpl	theProcessor(
					theParserLiaison,
					theXPathSupport,
					theXSLTProcessorEnvSupport,
					theXObjectFactory,
					theXPathFactory);
	outputMessage(theThreadID,"Starting ");

	// Connect the processor to the support object...
	theXSLTProcessorEnvSupport.setProcessor(&theProcessor);

	// The execution context uses the same factory support objects as
	// the processor, since those objects have the same lifetime as
	// other objects created as a result of the execution.
	StylesheetExecutionContextDefault	ssExecutionContext(
						theProcessor,
						theXSLTProcessorEnvSupport,
						theXPathSupport,
						theXObjectFactory);

  // Set the XSLTInputSource...
  XSLTInputSource xslIn(glbDocSource);

	// Generate the output file name for this thread.
    ostrstream theFormatterOut;
    theFormatterOut << "birds" << number << ".out" << '\0';

	//Generate the XML output object.
	XSLTResultTarget	theResultTarget(theFormatterOut.str());

	// Unfreeze the ostrstream, so memory is returned...
	theFormatterOut.freeze(false);

	// Set the processor to use the compiled stylesheet. Then do the transform
  // with the process() method that uses the compiled stylesheet.
	// Report the start of the transformation and the termination of the thread.
	theProcessor.setStylesheetRoot(glbStylesheetRoot);
	outputMessage(theThreadID,"Transforming");
  theProcessor.process(xslIn,theResultTarget,ssExecutionContext);
	outputMessage(theThreadID,"Finishing");
	return (0);
}

// Create and run the threads...
// Print messages tracking the progress of each thread and of the
// overall operation...
void doThreads(int x)
{
	DWORD dwStackSize = 4096;              	// initial thread stack size
	LPTHREAD_START_ROUTINE lpStartAddress = (LPTHREAD_START_ROUTINE)theThread;
	DWORD dwCreationFlags = 0;             	// creation flags
 	int nThreads = x;

	std::vector<HANDLE> hThreads;
	hThreads.reserve(nThreads);
 	int i=0;

	try
	{
		cout << endl << "Clock before starting threads: " << clock() << endl;

		for (i=0; i< nThreads; i++)
			{
				HANDLE hThread;
				DWORD  threadID;

				hThread = CreateThread(
					0, dwStackSize,
					lpStartAddress,					      // pointer to thread function
					reinterpret_cast<LPVOID>(i),	// argument for new thread
					dwCreationFlags,				      // creation flags
					&threadID);
				assert(hThread != 0);
				hThreads.push_back(hThread);
			}
		WaitForMultipleObjects(hThreads.size(), &hThreads[0], TRUE, INFINITE);

		cout << endl << "Clock after threads: " << clock() << endl;

		for (i=0; i< nThreads; i++)
			CloseHandle(hThreads[i]);
	}
	catch(...)
	{
		cerr << "Exception caught!!!"
			 << endl
			<< endl;
	}
}

int main(int argc, const char*	/* argv */[])
{

	if (argc != 1)
	{
		cerr << "Usage: ThreadTest"
			 << endl
			 << endl;
	}
	else
	{
		try
		{
			// Call the static initializers...
			XMLPlatformUtils::Initialize();
			XSLTEngineImpl::Initialize();

			// Create the support objects required to run the processor...
			DOMSupportDefault				        ssDOMSupport;
			XercesParserLiaison				      ssParserLiaison(ssDOMSupport);
			XPathSupportDefault				      ssXPathSupport(ssDOMSupport);
			XSLTProcessorEnvSupportDefault	ssXSLTProcessorEnvSupport;
			XObjectFactoryDefault			      ssXObjectFactory(ssXSLTProcessorEnvSupport,
															                         ssXPathSupport);
			XPathFactoryDefault				      ssXPathFactory;

			// Create a processor...
      // This processor is used to compile the stylesheet and the source document.
      // Each thread uses its own processor to perform a transformation.

			XSLTEngineImpl	ssProcessor(
      					  ssParserLiaison,
	      		    	ssXPathSupport,
		  	        	ssXSLTProcessorEnvSupport,
		    	  		  ssXObjectFactory,
        				  ssXPathFactory);

			// Create separate factory support objects so the stylesheet's
			// factory-created XObject and XPath instances are independent
			// from the processor's.
			XObjectFactoryDefault	ssStylesheetXObjectFactory(
									ssXSLTProcessorEnvSupport,
									ssXPathSupport);
			XPathFactoryDefault		ssStylesheetXPathFactory;

			// Create a stylesheet construction context, using the
			// stylesheet's factory support objects.
			StylesheetConstructionContextDefault	ssConstructionContext(
													ssProcessor,
													ssXSLTProcessorEnvSupport,
													ssStylesheetXObjectFactory,
													ssStylesheetXPathFactory);

			const XalanDOMString  theXSLFileName("birds.xsl");
			const XalanDOMString  theXMLFileName("birds.xml");

			// Our stylesheet XML input document and XSL stylesheet
      XSLTInputSource   xmlDocSource(c_wstr(theXMLFileName));
			XSLTInputSource		xslStylesheetSource(c_wstr(theXSLFileName));

			// Use the processor to create a StylesheetRoot for the specified
			// input XSL.  This is the compiled stylesheet.  We don't have to
			// delete it, since it is owned by the StylesheetConstructionContext
			// instance.
			glbStylesheetRoot = ssProcessor.processStylesheet(xslStylesheetSource,
													   ssConstructionContext);
			assert(glbStylesheetRoot != 0);

			// Compile the XML source document as well. All threads will use
      // this binary representation of the source tree.
			glbDocSource = ssProcessor.getSourceTreeFromInput(xmlDocSource);
      assert(glbSourceDoc != 0);

      // Create and run the threads...
      // Each thread uses the same XalanNode and
      // StylesheetRoot to perform a transformation.
			doThreads(10);
		}
		catch(...)
		{
			cerr << "Exception caught!!!"
				 << endl
				 << endl;
		}
	}

	return 0;
}
<|endoftext|>


<commit_before>#include "core.h"
#include "main_core.h"
#include "tile.h"
#include "network.h"
#include "syscall_model.h"
#include "sync_client.h"
#include "network_types.h"
#include "memory_manager.h"
#include "pin_memory_manager.h"
#include "clock_skew_minimization_object.h"
#include "core_model.h"
#include "simulator.h"
#include "log.h"

using namespace std;

Core::Core(Tile *tile, core_type_t core_type)
   : m_tile(tile)
   , m_core_id((core_id_t) {tile->getId(), core_type})
   , m_core_state(IDLE)
   , m_pin_memory_manager(NULL)
{
   m_core_model = CoreModel::create(this);
   m_sync_client = new SyncClient(this);
   m_syscall_model = new SyscallMdl(tile->getNetwork());
   m_clock_skew_minimization_client =
      ClockSkewMinimizationClient::create(Sim()->getCfg()->getString("clock_skew_minimization/scheme","none"), this);

   m_network = m_tile->getNetwork();
   m_shmem_perf_model = m_tile->getShmemPerfModel();
   m_memory_manager = m_tile->getMemoryManager();

   if (Config::getSingleton()->isSimulatingSharedMemory())
      m_pin_memory_manager = new PinMemoryManager(this);
}

Core::~Core()
{
   LOG_PRINT("Deleting core on tile %d", m_core_id.tile_id);

   if (m_pin_memory_manager)
      delete m_pin_memory_manager;

   if (m_clock_skew_minimization_client)
      delete m_clock_skew_minimization_client;
   delete m_syscall_model;
   delete m_sync_client;
   delete m_core_model;
}

int Core::coreSendW(int sender, int receiver, char* buffer, int size, carbon_network_t net_type)
{
   PacketType pkt_type = getPktTypeFromUserNetType(net_type);

   core_id_t receiver_core = (core_id_t) {receiver, this->getCoreType()};

   SInt32 sent;
   if (receiver == CAPI_ENDPOINT_ALL)
      sent = m_tile->getNetwork()->netBroadcast(pkt_type, buffer, size);
   else
      sent = m_tile->getNetwork()->netSend(receiver_core, pkt_type, buffer, size);

   LOG_ASSERT_ERROR(sent == size, "Bytes Sent(%i), Message Size(%i)", sent, size);

   return sent == size ? 0 : -1;
}

int Core::coreRecvW(int sender, int receiver, char* buffer, int size, carbon_network_t net_type)
{
   PacketType pkt_type = getPktTypeFromUserNetType(net_type);

   core_id_t sender_core = (core_id_t) {sender, getCoreType()};

   NetPacket packet;
   if (sender == CAPI_ENDPOINT_ANY)
      packet = m_tile->getNetwork()->netRecvType(pkt_type, m_core_id);
   else
      packet = m_tile->getNetwork()->netRecv(sender_core, m_core_id, pkt_type);

   LOG_PRINT("Got packet: from {%i, %i}, to {%i, %i}, type %i, len %i", packet.sender.tile_id, packet.sender.core_type, packet.receiver.tile_id, packet.receiver.core_type, (SInt32)packet.type, packet.length);

   LOG_ASSERT_ERROR((unsigned)size == packet.length, "Tile: User thread requested packet of size: %d, got a packet from %d of size: %d", size, sender, packet.length);

   memcpy(buffer, packet.data, size);

   // De-allocate dynamic memory
   // Is this the best place to de-allocate packet.data ??
   delete [](Byte*)packet.data;

   return (unsigned)size == packet.length ? 0 : -1;
}

PacketType Core::getPktTypeFromUserNetType(carbon_network_t net_type)
{
   switch(net_type)
   {
      case CARBON_NET_USER_1:
         return USER_1;

      case CARBON_NET_USER_2:
         return USER_2;

      default:
         LOG_PRINT_ERROR("Unrecognized User Network(%u)", net_type);
         return (PacketType) -1;
   }
}

Core::State
Core::getState()
{
   ScopedLock scoped_lock(m_core_state_lock);
   return m_core_state;
}

void
Core::setState(State core_state)
{
   ScopedLock scoped_lock(m_core_state_lock);
   m_core_state = core_state;
}
<commit_msg>[core] Populate already created pointers before creating new objects<commit_after>#include "core.h"
#include "main_core.h"
#include "tile.h"
#include "network.h"
#include "syscall_model.h"
#include "sync_client.h"
#include "network_types.h"
#include "memory_manager.h"
#include "pin_memory_manager.h"
#include "clock_skew_minimization_object.h"
#include "core_model.h"
#include "simulator.h"
#include "log.h"

using namespace std;

Core::Core(Tile *tile, core_type_t core_type)
   : m_tile(tile)
   , m_core_id((core_id_t) {tile->getId(), core_type})
   , m_core_state(IDLE)
   , m_pin_memory_manager(NULL)
{
   m_network = m_tile->getNetwork();
   m_shmem_perf_model = m_tile->getShmemPerfModel();
   m_memory_manager = m_tile->getMemoryManager();

   m_core_model = CoreModel::create(this);
   m_sync_client = new SyncClient(this);
   m_syscall_model = new SyscallMdl(tile->getNetwork());
   m_clock_skew_minimization_client =
      ClockSkewMinimizationClient::create(Sim()->getCfg()->getString("clock_skew_minimization/scheme","none"), this);

   if (Config::getSingleton()->isSimulatingSharedMemory())
      m_pin_memory_manager = new PinMemoryManager(this);
}

Core::~Core()
{
   LOG_PRINT("Deleting core on tile %d", m_core_id.tile_id);

   if (m_pin_memory_manager)
      delete m_pin_memory_manager;

   if (m_clock_skew_minimization_client)
      delete m_clock_skew_minimization_client;
   delete m_syscall_model;
   delete m_sync_client;
   delete m_core_model;
}

int Core::coreSendW(int sender, int receiver, char* buffer, int size, carbon_network_t net_type)
{
   PacketType pkt_type = getPktTypeFromUserNetType(net_type);

   core_id_t receiver_core = (core_id_t) {receiver, this->getCoreType()};

   SInt32 sent;
   if (receiver == CAPI_ENDPOINT_ALL)
      sent = m_tile->getNetwork()->netBroadcast(pkt_type, buffer, size);
   else
      sent = m_tile->getNetwork()->netSend(receiver_core, pkt_type, buffer, size);

   LOG_ASSERT_ERROR(sent == size, "Bytes Sent(%i), Message Size(%i)", sent, size);

   return sent == size ? 0 : -1;
}

int Core::coreRecvW(int sender, int receiver, char* buffer, int size, carbon_network_t net_type)
{
   PacketType pkt_type = getPktTypeFromUserNetType(net_type);

   core_id_t sender_core = (core_id_t) {sender, getCoreType()};

   NetPacket packet;
   if (sender == CAPI_ENDPOINT_ANY)
      packet = m_tile->getNetwork()->netRecvType(pkt_type, m_core_id);
   else
      packet = m_tile->getNetwork()->netRecv(sender_core, m_core_id, pkt_type);

   LOG_PRINT("Got packet: from {%i, %i}, to {%i, %i}, type %i, len %i", packet.sender.tile_id, packet.sender.core_type, packet.receiver.tile_id, packet.receiver.core_type, (SInt32)packet.type, packet.length);

   LOG_ASSERT_ERROR((unsigned)size == packet.length, "Tile: User thread requested packet of size: %d, got a packet from %d of size: %d", size, sender, packet.length);

   memcpy(buffer, packet.data, size);

   // De-allocate dynamic memory
   // Is this the best place to de-allocate packet.data ??
   delete [](Byte*)packet.data;

   return (unsigned)size == packet.length ? 0 : -1;
}

PacketType Core::getPktTypeFromUserNetType(carbon_network_t net_type)
{
   switch(net_type)
   {
      case CARBON_NET_USER_1:
         return USER_1;

      case CARBON_NET_USER_2:
         return USER_2;

      default:
         LOG_PRINT_ERROR("Unrecognized User Network(%u)", net_type);
         return (PacketType) -1;
   }
}

Core::State
Core::getState()
{
   ScopedLock scoped_lock(m_core_state_lock);
   return m_core_state;
}

void
Core::setState(State core_state)
{
   ScopedLock scoped_lock(m_core_state_lock);
   m_core_state = core_state;
}
<|endoftext|>


<commit_before>/* ---------------------------------------------------------------------------
** This software is in the public domain, furnished "as is", without technical
** support, and with no warranty, express or implied, as to its usefulness for
** any purpose.
**
** HttpServerHandler.cpp
**
** -------------------------------------------------------------------------*/

#include <iostream>

#include "HttpServerRequestHandler.h"

class RequestHandler : public CivetHandler
{
  public:
	bool handle(CivetServer *server, struct mg_connection *conn)
	{
		bool ret = false;
		const struct mg_request_info *req_info = mg_get_request_info(conn);

		HttpServerRequestHandler* httpServer = (HttpServerRequestHandler*)server;

		httpFunction fct = httpServer->getFunction(req_info->request_uri);
		if (fct != NULL)
		{
			Json::Value  jmessage;

			// read input
			long long tlen = req_info->content_length;
			if (tlen > 0)
			{
				std::string body;
				long long nlen = 0;
				char buf[1024];
				while (nlen < tlen) {
					long long rlen = tlen - nlen;
					if (rlen > sizeof(buf)) {
						rlen = sizeof(buf);
					}
					rlen = mg_read(conn, buf, (size_t)rlen);
					if (rlen <= 0) {
						break;
					}
					body.append(buf, rlen);

					nlen += rlen;
				}
				std::cout << "body:" << body << std::endl;

				// parse in
				Json::Reader reader;
				if (!reader.parse(body, jmessage))
				{
					LOG(WARNING) << "Received unknown message:" << body;
				}
			}

			// invoke API implementation
			Json::Value out(fct(conn, jmessage));

			// fill out
			if (out.isNull() == false)
			{
				std::string answer(Json::StyledWriter().write(out));
				std::cout << "answer:" << answer << std::endl;

				mg_printf(conn,"HTTP/1.1 200 OK\r\n");
				mg_printf(conn,"Access-Control-Allow-Origin: *\r\n");
				mg_printf(conn,"Content-Type: text/plain\r\n");
				mg_printf(conn,"Content-Length: %zd\r\n", answer.size());
				mg_printf(conn,"Connection: close\r\n");
				mg_printf(conn,"\r\n");
				mg_printf(conn,answer.c_str());

				ret = true;
			}
		}

		return ret;
	}
	bool handleGet(CivetServer *server, struct mg_connection *conn)
	{
		return handle(server, conn);
	}
	bool handlePost(CivetServer *server, struct mg_connection *conn)
	{
		return handle(server, conn);
	}
};

/* ---------------------------------------------------------------------------
**  Constructor
** -------------------------------------------------------------------------*/
HttpServerRequestHandler::HttpServerRequestHandler(PeerConnectionManager* webRtcServer, const std::vector<std::string>& options)
	: CivetServer(options), m_webRtcServer(webRtcServer)
{
	// http api callbacks
	m_func["/getDeviceList"]         = [this](struct mg_connection *conn, const Json::Value & in) -> Json::Value {
		return m_webRtcServer->getDeviceList();
	};

	m_func["/getIceServers"]         = [this](struct mg_connection *conn, const Json::Value & in) -> Json::Value {
		return m_webRtcServer->getIceServers();
	};

	m_func["/call"]                  = [this](struct mg_connection *conn, const Json::Value & in) -> Json::Value {

		const struct mg_request_info *req_info = mg_get_request_info(conn);
		std::string peerid;
		CivetServer::getParam(req_info->query_string, "peerid", peerid);
		std::string connecturl;
		CivetServer::getParam(req_info->query_string, "url", connecturl);
		std::string url;
		CivetServer::urlDecode(connecturl, url);
		std::cout << "url:" << url<< std::endl;
		return m_webRtcServer->call(peerid, url, in);
	};

	m_func["/hangup"]                = [this](struct mg_connection *conn, const Json::Value & in) -> Json::Value {
		std::string peerid;
		CivetServer::getParam(conn, "peerid", peerid);
		Json::Value answer(m_webRtcServer->hangUp(peerid));
		return answer;
	};

	m_func["/createOffer"]           = [this](struct mg_connection *conn, const Json::Value & in) -> Json::Value {
		const struct mg_request_info *req_info = mg_get_request_info(conn);
		std::string peerid;
		CivetServer::getParam(req_info->query_string, "peerid", peerid);
		std::string connecturl;
		CivetServer::getParam(req_info->query_string, "url", connecturl);
		std::string url;
		CivetServer::urlDecode(connecturl, url);
		return m_webRtcServer->createOffer(peerid, url);
	};
	m_func["/setAnswer"]             = [this](struct mg_connection *conn, const Json::Value & in) -> Json::Value {
		const struct mg_request_info *req_info = mg_get_request_info(conn);
		std::string peerid;
		CivetServer::getParam(req_info->query_string, "peerid", peerid);
		m_webRtcServer->setAnswer(peerid, in);
		Json::Value answer(1);
		return answer;
	};

	m_func["/getIceCandidate"]       = [this](struct mg_connection *conn, const Json::Value & in) -> Json::Value {
		const struct mg_request_info *req_info = mg_get_request_info(conn);
		std::string peerid;
		CivetServer::getParam(conn, "peerid", peerid);
		return m_webRtcServer->getIceCandidateList(peerid);
	};

	m_func["/addIceCandidate"]       = [this](struct mg_connection *conn, const Json::Value & in) -> Json::Value {
		const struct mg_request_info *req_info = mg_get_request_info(conn);
		std::string peerid;
		CivetServer::getParam(req_info->query_string, "peerid", peerid);
		m_webRtcServer->addIceCandidate(peerid, in);
		Json::Value answer(1);
		return answer;
	};

	m_func["/getPeerConnectionList"] = [this](struct mg_connection *conn, const Json::Value & in) -> Json::Value {
		return m_webRtcServer->getPeerConnectionList();
	};

	m_func["/getStreamList"] = [this](struct mg_connection *conn, const Json::Value & in) -> Json::Value {
		return m_webRtcServer->getStreamList();
	};

	m_func["/delStream"] = [this](struct mg_connection *conn, const Json::Value & in) -> Json::Value {
		const struct mg_request_info *req_info = mg_get_request_info(conn);
		std::string connecturl;
		CivetServer::getParam(req_info->query_string, "url", connecturl);
		Json::Value answer(m_webRtcServer->delStream(connecturl));
		return answer;
	};

	m_func["/help"]                  = [this](struct mg_connection *conn, const Json::Value & in) -> Json::Value {
		Json::Value answer;
		for (auto it : m_func) {
			answer.append(it.first);
		}
		return answer;
	};

	// register handlers
	for (auto it : m_func) {
		this->addHandler(it.first, new RequestHandler());
	}
}

httpFunction HttpServerRequestHandler::getFunction(const std::string& uri)
{
	httpFunction fct = NULL;
	std::map<std::string,httpFunction>::iterator it = m_func.find(uri);
	if (it != m_func.end())
	{
		fct = it->second;
	}

	return fct;
}

<commit_msg>fix unused variable<commit_after>/* ---------------------------------------------------------------------------
** This software is in the public domain, furnished "as is", without technical
** support, and with no warranty, express or implied, as to its usefulness for
** any purpose.
**
** HttpServerHandler.cpp
**
** -------------------------------------------------------------------------*/

#include <iostream>

#include "HttpServerRequestHandler.h"

class RequestHandler : public CivetHandler
{
  public:
	bool handle(CivetServer *server, struct mg_connection *conn)
	{
		bool ret = false;
		const struct mg_request_info *req_info = mg_get_request_info(conn);

		HttpServerRequestHandler* httpServer = (HttpServerRequestHandler*)server;

		httpFunction fct = httpServer->getFunction(req_info->request_uri);
		if (fct != NULL)
		{
			Json::Value  jmessage;

			// read input
			long long tlen = req_info->content_length;
			if (tlen > 0)
			{
				std::string body;
				long long nlen = 0;
				char buf[1024];
				while (nlen < tlen) {
					long long rlen = tlen - nlen;
					if (rlen > sizeof(buf)) {
						rlen = sizeof(buf);
					}
					rlen = mg_read(conn, buf, (size_t)rlen);
					if (rlen <= 0) {
						break;
					}
					body.append(buf, rlen);

					nlen += rlen;
				}
				std::cout << "body:" << body << std::endl;

				// parse in
				Json::Reader reader;
				if (!reader.parse(body, jmessage))
				{
					LOG(WARNING) << "Received unknown message:" << body;
				}
			}

			// invoke API implementation
			Json::Value out(fct(conn, jmessage));

			// fill out
			if (out.isNull() == false)
			{
				std::string answer(Json::StyledWriter().write(out));
				std::cout << "answer:" << answer << std::endl;

				mg_printf(conn,"HTTP/1.1 200 OK\r\n");
				mg_printf(conn,"Access-Control-Allow-Origin: *\r\n");
				mg_printf(conn,"Content-Type: text/plain\r\n");
				mg_printf(conn,"Content-Length: %zd\r\n", answer.size());
				mg_printf(conn,"Connection: close\r\n");
				mg_printf(conn,"\r\n");
				mg_printf(conn,answer.c_str());

				ret = true;
			}
		}

		return ret;
	}
	bool handleGet(CivetServer *server, struct mg_connection *conn)
	{
		return handle(server, conn);
	}
	bool handlePost(CivetServer *server, struct mg_connection *conn)
	{
		return handle(server, conn);
	}
};

/* ---------------------------------------------------------------------------
**  Constructor
** -------------------------------------------------------------------------*/
HttpServerRequestHandler::HttpServerRequestHandler(PeerConnectionManager* webRtcServer, const std::vector<std::string>& options)
	: CivetServer(options), m_webRtcServer(webRtcServer)
{
	// http api callbacks
	m_func["/getDeviceList"]         = [this](struct mg_connection *conn, const Json::Value & in) -> Json::Value {
		return m_webRtcServer->getDeviceList();
	};

	m_func["/getIceServers"]         = [this](struct mg_connection *conn, const Json::Value & in) -> Json::Value {
		return m_webRtcServer->getIceServers();
	};

	m_func["/call"]                  = [this](struct mg_connection *conn, const Json::Value & in) -> Json::Value {

		const struct mg_request_info *req_info = mg_get_request_info(conn);
		std::string peerid;
		CivetServer::getParam(req_info->query_string, "peerid", peerid);
		std::string connecturl;
		CivetServer::getParam(req_info->query_string, "url", connecturl);
		std::string url;
		CivetServer::urlDecode(connecturl, url);
		std::cout << "url:" << url<< std::endl;
		return m_webRtcServer->call(peerid, url, in);
	};

	m_func["/hangup"]                = [this](struct mg_connection *conn, const Json::Value & in) -> Json::Value {
		std::string peerid;
		CivetServer::getParam(conn, "peerid", peerid);
		Json::Value answer(m_webRtcServer->hangUp(peerid));
		return answer;
	};

	m_func["/createOffer"]           = [this](struct mg_connection *conn, const Json::Value & in) -> Json::Value {
		const struct mg_request_info *req_info = mg_get_request_info(conn);
		std::string peerid;
		CivetServer::getParam(req_info->query_string, "peerid", peerid);
		std::string connecturl;
		CivetServer::getParam(req_info->query_string, "url", connecturl);
		std::string url;
		CivetServer::urlDecode(connecturl, url);
		return m_webRtcServer->createOffer(peerid, url);
	};
	m_func["/setAnswer"]             = [this](struct mg_connection *conn, const Json::Value & in) -> Json::Value {
		const struct mg_request_info *req_info = mg_get_request_info(conn);
		std::string peerid;
		CivetServer::getParam(req_info->query_string, "peerid", peerid);
		m_webRtcServer->setAnswer(peerid, in);
		Json::Value answer(1);
		return answer;
	};

	m_func["/getIceCandidate"]       = [this](struct mg_connection *conn, const Json::Value & in) -> Json::Value {
		const struct mg_request_info *req_info = mg_get_request_info(conn);
		std::string peerid;
		CivetServer::getParam(req_info->query_string, "peerid", peerid);
		return m_webRtcServer->getIceCandidateList(peerid);
	};

	m_func["/addIceCandidate"]       = [this](struct mg_connection *conn, const Json::Value & in) -> Json::Value {
		const struct mg_request_info *req_info = mg_get_request_info(conn);
		std::string peerid;
		CivetServer::getParam(req_info->query_string, "peerid", peerid);
		m_webRtcServer->addIceCandidate(peerid, in);
		Json::Value answer(1);
		return answer;
	};

	m_func["/getPeerConnectionList"] = [this](struct mg_connection *conn, const Json::Value & in) -> Json::Value {
		return m_webRtcServer->getPeerConnectionList();
	};

	m_func["/getStreamList"] = [this](struct mg_connection *conn, const Json::Value & in) -> Json::Value {
		return m_webRtcServer->getStreamList();
	};

	m_func["/delStream"] = [this](struct mg_connection *conn, const Json::Value & in) -> Json::Value {
		const struct mg_request_info *req_info = mg_get_request_info(conn);
		std::string connecturl;
		CivetServer::getParam(req_info->query_string, "url", connecturl);
		Json::Value answer(m_webRtcServer->delStream(connecturl));
		return answer;
	};

	m_func["/help"]                  = [this](struct mg_connection *conn, const Json::Value & in) -> Json::Value {
		Json::Value answer;
		for (auto it : m_func) {
			answer.append(it.first);
		}
		return answer;
	};

	// register handlers
	for (auto it : m_func) {
		this->addHandler(it.first, new RequestHandler());
	}
}

httpFunction HttpServerRequestHandler::getFunction(const std::string& uri)
{
	httpFunction fct = NULL;
	std::map<std::string,httpFunction>::iterator it = m_func.find(uri);
	if (it != m_func.end())
	{
		fct = it->second;
	}

	return fct;
}

<|endoftext|>


<commit_before>/*
 * Scanner.cpp
 *
 * This file is part of the "XieXie 2.0 Project" (Copyright (c) 2014 by Lukas Hermanns)
 * See "LICENSE.txt" for license information.
 */

#include "Scanner.h"
#include "StringModifier.h"
#include "Keywords.h"

#include <cctype>

namespace SyntaxAnalyzer
{

bool Scanner::ScanSource(const SourceCodePtr& source, ErrorReporter& errorReporter)
{
    if (source)
    {
        source_ = source;
        errorReporter_ = &errorReporter;

        /* Take first character from source */
        TakeIt();

        return true;
    }
    return false;
}

TokenPtr Scanner::Next()
{
    /*
    Scan until a valid token has been found
    (infinite loop to catch exception, but continue scanning)
    */
    while (true)
    {
        try
        {
            /* Start scanning process */
            return Scan();
        }
        catch (const CompilerMessage& err)
        {
            /* Add to error and scan next token */
            errorReporter_->Add(err);
        }
    }
    return nullptr;
}

SourcePosition Scanner::Pos() const
{
    return source_ != nullptr ? source_->Pos() : SourcePosition::ignore;
}

/*
 * ======= Private: =======
 */

/* --- Error handling --- */

void Scanner::Error(const std::string& msg)
{
    throw SyntaxError(SourceArea(Pos()), msg);
}

void Scanner::ErrorUnexpected()
{
    auto chr = TakeIt();
    Error("unexpected character '" + ToStr(chr) + "'");
}

void Scanner::ErrorUnexpected(char expectedChar)
{
    auto chr = TakeIt();
    Error("unexpected character '" + ToStr(chr) + "' (expected '" + ToStr(expectedChar) + "')");
}

void Scanner::ErrorEOF()
{
    Error("unexpected end-of-file");
}

void Scanner::ErrorLetterInNumber()
{
    Error("letter '" + ToStr(chr_) + "' is not allowed within a number");
}

/* --- Scanning --- */

char Scanner::Take(char chr)
{
    if (chr_ != chr)
        ErrorUnexpected(chr);
    return TakeIt();
}

char Scanner::TakeIt()
{
    /* Get next character and return previous one */
    auto prevChr = chr_;
    chr_ = source_->Next();
    return prevChr;
}

void Scanner::Ignore(const std::function<bool (char)>& pred)
{
    while (pred(chr_))
        TakeIt();
}

void Scanner::IgnoreWhiteSpaces()
{
    Ignore([](char chr) { return std::isspace(static_cast<unsigned char>(chr)) != 0; });
}

void Scanner::IgnoreCommentLine()
{
    Ignore([](char chr) { return chr != '\n'; });
}

void Scanner::IgnoreCommentBlock()
{
    while (true)
    {
        if (Is(0))
            return;

        /* Scan comment block ending */
        if (Is('*'))
        {
            TakeIt();
            if (Is('/'))
            {
                TakeIt();
                return;
            }
        }

        TakeIt();
    }
}

TokenPtr Scanner::Make(const Tokens& type, bool takeChr)
{
    if (takeChr)
    {
        std::string spell;
        spell += TakeIt();
        return std::make_shared<Token>(Pos(), type, std::move(spell));
    }
    return std::make_shared<Token>(Pos(), type);
}

TokenPtr Scanner::Make(const Tokens& type, std::string& spell, bool takeChr)
{
    if (takeChr)
        spell += TakeIt();
    return std::make_shared<Token>(Pos(), type, std::move(spell));
}

TokenPtr Scanner::Make(const Tokens& type, std::string& spell, const SourceArea& area, bool takeChr)
{
    if (takeChr)
        spell += TakeIt();
    return std::make_shared<Token>(area, type, std::move(spell));
}

TokenPtr Scanner::Scan()
{
    /* Ignore white spaces and comments */
    bool comments = true;

    do
    {
        IgnoreWhiteSpaces();

        /* Check for end-of-file */
        if (Is(0))
            return Make(Tokens::EndOfFile);

        /* Scan commentaries */
        if (Is('/'))
        {
            auto prevChr = TakeIt();

            if (Is('/'))
                IgnoreCommentLine();
            else if (Is('*'))
                IgnoreCommentBlock();
            else
            {
                std::string spell;
                spell += prevChr;

                if (Is('='))
                {
                    spell += TakeIt();
                    return Make(Tokens::ModifyAssignOp, spell);
                }

                return Make(Tokens::DivOp, spell);
            }
        }
        else
            comments = false;
    }
    while (comments);

    /* Scan next token */
    return ScanToken();
}

TokenPtr Scanner::ScanToken()
{
    std::string spell;

    /* Scan string literal */
    if (Is('\"'))
        return ScanStringLiteral();

    /* Scan identifier */
    if (std::isalpha(UChr()) || Is('_'))
        return ScanIdentifier();

    /* Scan number */
    if (std::isdigit(UChr()))
        return ScanNumber();

    /* Scan special character and verbatim string literals */
    if (Is('@'))
    {
        spell += TakeIt();

        /* Scan verbatim string literal */
        if (Is('\"'))
            return ScanVerbatimStringLiteral();

        return Make(Tokens::At, spell);
    }

    /* Scan operators */
    if (Is(':'))
    {
        spell += TakeIt();

        if (Is('='))
        {
            spell += TakeIt();
            return Make(Tokens::CopyAssignOp, spell);
        }

        return Make(Tokens::Colon, spell);
    }

    if (Is('='))
        return Make(Tokens::EqualityOp, spell, true);

    if (Is('~'))
        return Make(Tokens::BitwiseNotOp, spell, true);

    if (Is('!'))
    {
        spell += TakeIt();

        if (Is('='))
        {
            spell += TakeIt();
            return Make(Tokens::EqualityOp, spell);
        }

        ErrorUnexpected();
    }

    if (Is('%'))
    {
        spell += TakeIt();

        if (Is('='))
        {
            spell += TakeIt();
            return Make(Tokens::ModifyAssignOp, spell);
        }

        return Make(Tokens::DivOp, spell);
    }

    if (Is('*'))
    {
        spell += TakeIt();

        if (Is('='))
        {
            spell += TakeIt();
            return Make(Tokens::ModifyAssignOp, spell);
        }

        return Make(Tokens::MulOp, spell);
    }

    if (Is('^'))
    {
        spell += TakeIt();

        if (Is('='))
        {
            spell += TakeIt();
            return Make(Tokens::ModifyAssignOp, spell);
        }

        return Make(Tokens::BitwiseXorOp, spell);
    }

    if (Is('+'))
        return ScanPlusOp();
    if (Is('-'))
        return ScanMinusOp();

    if (Is('<') || Is('>'))
        return ScanAssignShiftRelationOp(chr_);

    if (Is('&'))
    {
        spell += TakeIt();

        if (Is('='))
        {
            spell += TakeIt();
            return Make(Tokens::ModifyAssignOp, spell);
        }

        return Make(Tokens::BitwiseAndOp, spell);
    }

    if (Is('|'))
    {
        spell += TakeIt();

        if (Is('='))
        {
            spell += TakeIt();
            return Make(Tokens::ModifyAssignOp, spell);
        }

        return Make(Tokens::BitwiseOrOp, spell);
    }

    /* Scan special cases */
    if (Is('['))
    {
        spell += TakeIt();

        if (Is('['))
        {
            /* Push new state and return special case token */
            allowRDParenStack_.Push(true);
            return Make(Tokens::LDParen, spell, true);
        }

        /* Push new state and return special case token */
        allowRDParenStack_.Push(false);
        return Make(Tokens::LParen, spell);
    }

    if (Is(']'))
    {
        spell += TakeIt();

        if (Is(']') && allowRDParenStack_.Top())
        {
            /* Pop previous state and return special case token */
            allowRDParenStack_.Pop();
            return Make(Tokens::RDParen, spell, true);
        }

        allowRDParenStack_.Pop();
        return Make(Tokens::RParen, spell);
    }

    /* Scan punctuation, special characters and brackets */
    if (Is('.'))
    {
        spell += TakeIt();
        if (Is('.'))
            return Make(Tokens::RangeSep, spell, true);
        return Make(Tokens::Dot, spell);
    }

    switch (chr_)
    {
        case ';': return Make(Tokens::Semicolon, true); break;
        case ',': return Make(Tokens::Comma,     true); break;
        case '(': return Make(Tokens::LBracket,  true); break;
        case ')': return Make(Tokens::RBracket,  true); break;
        case '{': return Make(Tokens::LCurly,    true); break;
        case '}': return Make(Tokens::RCurly,    true); break;
    }

    ErrorUnexpected();

    return nullptr;
}

TokenPtr Scanner::ScanStringLiteral()
{
    std::string spell;
    SourceArea area { Pos() };

    while (true)
    {
        /* Take opening '\"' character */
        Take('\"');

        while (true)
        {
            /* Check for escape characters */
            while (Is('\\'))
            {
                TakeIt();

                if (IsEscapeChar())
                    spell += chr_;
                else
                {
                    auto chr = TakeIt();
                    Error("unexpected escape character '" + ToStr(chr) + "' in string literal");
                }

                TakeIt();
            }

            if (Is(0))
                ErrorEOF();

            /* Check for closing '\"' character */
            if (Is('\"'))
            {
                TakeIt();
                area.end = Pos();
                break;
            }

            /* Append character to string literal */
            spell += TakeIt();
        }

        /* Search for next string literal (which will be appended to this token) */
        IgnoreWhiteSpaces();

        if (!Is('\"'))
            break;

        spell += '\n';
    }

    /* Return final string literal token */
    return Make(Tokens::StringLiteral, spell, area);
}

TokenPtr Scanner::ScanVerbatimStringLiteral()
{
    std::string spell;
    SourceArea area { Pos() };

    while (true)
    {
        /* Take opening '\"' character */
        Take('\"');

        while (true)
        {
            /* Check for escape characters */
            while (Is('\\'))
            {
                TakeIt();
                spell += '\\';
            }

            if (Is(0))
                ErrorEOF();

            /* Check for closing '\"' character */
            if (Is('\"'))
            {
                TakeIt();

                /* Check for double quotes */
                if (!Is('\"'))
                {
                    area.end = Pos();
                    break;
                }
            }

            /* Append character to string literal */
            spell += TakeIt();
        }

        /* Search for next string literal (which will be appended to this token) */
        IgnoreWhiteSpaces();

        if (!Is('\"'))
            break;

        spell += '\n';
    }

    /* Return final string literal token */
    return Make(Tokens::StringLiteral, spell, area);
}

TokenPtr Scanner::ScanIdentifier()
{
    /* Scan identifier string */
    std::string spell;
    spell += TakeIt();

    while (std::isalnum(UChr()) || Is('_'))
        spell += TakeIt();

    /* Check for reserved internal names */
    if (spell.compare(0, 6, "__xx__") == 0)
        Error("reserved prefix \"__xx__\" used in identifier \"" + spell + "\"");

    /* Scan reserved words */
    auto it = Keywords().find(spell);
    if (it != Keywords().end())
    {
        if (it->second == Tokens::Reserved)
            Error("identifier \"" + spell + "\" is reserved for future use");
        return Make(it->second, spell);
    }

    /* Return as identifier */
    return Make(Tokens::Ident, spell);
}

TokenPtr Scanner::ScanAssignShiftRelationOp(const char chr)
{
    std::string spell;
    spell += TakeIt();

    if (Is(chr))
    {
        spell += TakeIt();

        if (Is('='))
        {
            spell += TakeIt();
            return Make(Tokens::ModifyAssignOp, spell);
        }

        return Make(Tokens::ShiftOp, spell);
    }

    if (Is('='))
        spell += TakeIt();

    return Make(Tokens::RelationOp, spell);
}

TokenPtr Scanner::ScanPlusOp()
{
    std::string spell;
    spell += TakeIt();

    if (Is('+'))
    {
        spell += TakeIt();
        return Make(Tokens::PostAssignOp, spell);
    }
    else if (Is('='))
    {
        spell += TakeIt();
        return Make(Tokens::ModifyAssignOp, spell);
    }

    return Make(Tokens::AddOp, spell);
}

TokenPtr Scanner::ScanMinusOp()
{
    std::string spell;
    spell += TakeIt();

    if (Is('-'))
    {
        spell += TakeIt();
        return Make(Tokens::PostAssignOp, spell);
    }
    else if (Is('='))
    {
        spell += TakeIt();
        return Make(Tokens::ModifyAssignOp, spell);
    }
    else if (Is('>'))
    {
        spell += TakeIt();
        return Make(Tokens::Arrow, spell);
    }

    return Make(Tokens::SubOp, spell);
}

TokenPtr Scanner::ScanNumber()
{
    if (!std::isdigit(UChr()))
        Error("expected digit");

    /* Take first number (literals like ".0" are not allowed) */
    std::string spell;

    const auto startChr = TakeIt();
    spell += startChr;

    /* Check for hex, octal, or binary number */
    if (startChr == '0')
    {
        switch (chr_)
        {
            case 'x':
                TakeIt();
                return ScanHexNumber();
            case 'o':
                TakeIt();
                return ScanOctNumber();
            case 'b':
                TakeIt();
                return ScanBinNumber();
        }
    }

    /* Scan integer or floating-point number */
    auto type = Tokens::IntLiteral;

    ScanDecimalLiteral(spell);

    if (Is('.'))
    {
        spell += TakeIt();

        if (std::isdigit(UChr()))
            ScanDecimalLiteral(spell);
        else
            Error("floating-point literals must have a decimal on both sides of the dot (e.g. '0.0' but not '0.' or '.0')");

        type = Tokens::FloatLiteral;
    }

    if (std::isalpha(UChr()) || Is('.'))
        ErrorLetterInNumber();

    /* Create number token */
    return Make(type, spell);
}

TokenPtr Scanner::ScanHexNumber()
{
    /* Scan hex literal */
    std::string spell;
    while (std::isxdigit(UChr()))
        spell += TakeIt();

    /* Check for wrong appendix */
    if ( ( std::isalpha(UChr()) && !std::isxdigit(UChr()) ) || Is('.') )
        ErrorLetterInNumber();

    /* Convert literal to decimal */
    spell = ToStr(HexToNum<int>(spell));
    return Make(Tokens::IntLiteral, spell);
}

TokenPtr Scanner::ScanOctNumber()
{
    /* Scan octal literal */
    std::string spell;
    while (chr_ >= '0' && chr_ <= '7')
        spell += TakeIt();

    /* Check for wrong appendix */
    if (std::isalpha(UChr()) || Is('.') )
        ErrorLetterInNumber();

    /* Convert literal to decimal */
    spell = ToStr(OctToNum<int>(spell));
    return Make(Tokens::IntLiteral, spell);
}

TokenPtr Scanner::ScanBinNumber()
{
    /* Scan binary literal */
    std::string spell;
    while (Is('1') || Is('0'))
        spell += TakeIt();

    /* Check for wrong appendix */
    if (std::isalpha(UChr()) || Is('.') )
        ErrorLetterInNumber();

    /* Convert literal to decimal */
    spell = ToStr(BinToNum<int>(spell));
    return Make(Tokens::IntLiteral, spell);
}

void Scanner::ScanDecimalLiteral(std::string& spell)
{
    while (std::isdigit(UChr()))
        spell += TakeIt();
}

bool Scanner::IsEscapeChar() const
{
    return
        ( chr_ >= '0' && chr_ <= '7') ||
        Is('\\') || Is('\"') || Is('\'') ||
        Is('\0') || Is( '?') || Is( 'a') ||
        Is( 'b') || Is( 'f') || Is( 'n') ||
        Is( 'r') || Is( 't') || Is( 'v') ||
        Is( 'x') || Is( 'u') || Is( 'U');
}

} // /namespace SyntaxAnalyzer

// ================================================================================<commit_msg>Extended scanner for nested comment blocks.<commit_after>/*
 * Scanner.cpp
 *
 * This file is part of the "XieXie 2.0 Project" (Copyright (c) 2014 by Lukas Hermanns)
 * See "LICENSE.txt" for license information.
 */

#include "Scanner.h"
#include "StringModifier.h"
#include "Keywords.h"

#include <cctype>

namespace SyntaxAnalyzer
{

bool Scanner::ScanSource(const SourceCodePtr& source, ErrorReporter& errorReporter)
{
    if (source)
    {
        source_ = source;
        errorReporter_ = &errorReporter;

        /* Take first character from source */
        TakeIt();

        return true;
    }
    return false;
}

TokenPtr Scanner::Next()
{
    /*
    Scan until a valid token has been found
    (infinite loop to catch exception, but continue scanning)
    */
    while (true)
    {
        try
        {
            /* Start scanning process */
            return Scan();
        }
        catch (const CompilerMessage& err)
        {
            /* Add to error and scan next token */
            errorReporter_->Add(err);
        }
    }
    return nullptr;
}

SourcePosition Scanner::Pos() const
{
    return source_ != nullptr ? source_->Pos() : SourcePosition::ignore;
}

/*
 * ======= Private: =======
 */

/* --- Error handling --- */

void Scanner::Error(const std::string& msg)
{
    throw SyntaxError(SourceArea(Pos()), msg);
}

void Scanner::ErrorUnexpected()
{
    auto chr = TakeIt();
    Error("unexpected character '" + ToStr(chr) + "'");
}

void Scanner::ErrorUnexpected(char expectedChar)
{
    auto chr = TakeIt();
    Error("unexpected character '" + ToStr(chr) + "' (expected '" + ToStr(expectedChar) + "')");
}

void Scanner::ErrorEOF()
{
    Error("unexpected end-of-file");
}

void Scanner::ErrorLetterInNumber()
{
    Error("letter '" + ToStr(chr_) + "' is not allowed within a number");
}

/* --- Scanning --- */

char Scanner::Take(char chr)
{
    if (chr_ != chr)
        ErrorUnexpected(chr);
    return TakeIt();
}

char Scanner::TakeIt()
{
    /* Get next character and return previous one */
    auto prevChr = chr_;
    chr_ = source_->Next();
    return prevChr;
}

void Scanner::Ignore(const std::function<bool (char)>& pred)
{
    while (pred(chr_))
        TakeIt();
}

void Scanner::IgnoreWhiteSpaces()
{
    Ignore([](char chr) { return std::isspace(static_cast<unsigned char>(chr)) != 0; });
}

void Scanner::IgnoreCommentLine()
{
    Ignore([](char chr) { return chr != '\n'; });
}

void Scanner::IgnoreCommentBlock()
{
    Take('*');
    size_t blockCounter = 1;

    while (true)
    {
        if (Is(0))
            return;

        /* Scan comment block ending */
        if (Is('*'))
        {
            TakeIt();
            if (Is('/'))
            {
                TakeIt();
                --blockCounter;
                if (blockCounter == 0)
                    return;
            }
        }
        /* Scan nested comment block */
        else if (Is('/'))
        {
            TakeIt();
            if (Is('*'))
            {
                TakeIt();
                ++blockCounter;
            }
        }
        else
            TakeIt();
    }
}

TokenPtr Scanner::Make(const Tokens& type, bool takeChr)
{
    if (takeChr)
    {
        std::string spell;
        spell += TakeIt();
        return std::make_shared<Token>(Pos(), type, std::move(spell));
    }
    return std::make_shared<Token>(Pos(), type);
}

TokenPtr Scanner::Make(const Tokens& type, std::string& spell, bool takeChr)
{
    if (takeChr)
        spell += TakeIt();
    return std::make_shared<Token>(Pos(), type, std::move(spell));
}

TokenPtr Scanner::Make(const Tokens& type, std::string& spell, const SourceArea& area, bool takeChr)
{
    if (takeChr)
        spell += TakeIt();
    return std::make_shared<Token>(area, type, std::move(spell));
}

TokenPtr Scanner::Scan()
{
    /* Ignore white spaces and comments */
    bool comments = true;

    do
    {
        IgnoreWhiteSpaces();

        /* Check for end-of-file */
        if (Is(0))
            return Make(Tokens::EndOfFile);

        /* Scan commentaries */
        if (Is('/'))
        {
            auto prevChr = TakeIt();

            if (Is('/'))
                IgnoreCommentLine();
            else if (Is('*'))
                IgnoreCommentBlock();
            else
            {
                std::string spell;
                spell += prevChr;

                if (Is('='))
                {
                    spell += TakeIt();
                    return Make(Tokens::ModifyAssignOp, spell);
                }

                return Make(Tokens::DivOp, spell);
            }
        }
        else
            comments = false;
    }
    while (comments);

    /* Scan next token */
    return ScanToken();
}

TokenPtr Scanner::ScanToken()
{
    std::string spell;

    /* Scan string literal */
    if (Is('\"'))
        return ScanStringLiteral();

    /* Scan identifier */
    if (std::isalpha(UChr()) || Is('_'))
        return ScanIdentifier();

    /* Scan number */
    if (std::isdigit(UChr()))
        return ScanNumber();

    /* Scan special character and verbatim string literals */
    if (Is('@'))
    {
        spell += TakeIt();

        /* Scan verbatim string literal */
        if (Is('\"'))
            return ScanVerbatimStringLiteral();

        return Make(Tokens::At, spell);
    }

    /* Scan operators */
    if (Is(':'))
    {
        spell += TakeIt();

        if (Is('='))
        {
            spell += TakeIt();
            return Make(Tokens::CopyAssignOp, spell);
        }

        return Make(Tokens::Colon, spell);
    }

    if (Is('='))
        return Make(Tokens::EqualityOp, spell, true);

    if (Is('~'))
        return Make(Tokens::BitwiseNotOp, spell, true);

    if (Is('!'))
    {
        spell += TakeIt();

        if (Is('='))
        {
            spell += TakeIt();
            return Make(Tokens::EqualityOp, spell);
        }

        ErrorUnexpected();
    }

    if (Is('%'))
    {
        spell += TakeIt();

        if (Is('='))
        {
            spell += TakeIt();
            return Make(Tokens::ModifyAssignOp, spell);
        }

        return Make(Tokens::DivOp, spell);
    }

    if (Is('*'))
    {
        spell += TakeIt();

        if (Is('='))
        {
            spell += TakeIt();
            return Make(Tokens::ModifyAssignOp, spell);
        }

        return Make(Tokens::MulOp, spell);
    }

    if (Is('^'))
    {
        spell += TakeIt();

        if (Is('='))
        {
            spell += TakeIt();
            return Make(Tokens::ModifyAssignOp, spell);
        }

        return Make(Tokens::BitwiseXorOp, spell);
    }

    if (Is('+'))
        return ScanPlusOp();
    if (Is('-'))
        return ScanMinusOp();

    if (Is('<') || Is('>'))
        return ScanAssignShiftRelationOp(chr_);

    if (Is('&'))
    {
        spell += TakeIt();

        if (Is('='))
        {
            spell += TakeIt();
            return Make(Tokens::ModifyAssignOp, spell);
        }

        return Make(Tokens::BitwiseAndOp, spell);
    }

    if (Is('|'))
    {
        spell += TakeIt();

        if (Is('='))
        {
            spell += TakeIt();
            return Make(Tokens::ModifyAssignOp, spell);
        }

        return Make(Tokens::BitwiseOrOp, spell);
    }

    /* Scan special cases */
    if (Is('['))
    {
        spell += TakeIt();

        if (Is('['))
        {
            /* Push new state and return special case token */
            allowRDParenStack_.Push(true);
            return Make(Tokens::LDParen, spell, true);
        }

        /* Push new state and return special case token */
        allowRDParenStack_.Push(false);
        return Make(Tokens::LParen, spell);
    }

    if (Is(']'))
    {
        spell += TakeIt();

        if (Is(']') && allowRDParenStack_.Top())
        {
            /* Pop previous state and return special case token */
            allowRDParenStack_.Pop();
            return Make(Tokens::RDParen, spell, true);
        }

        allowRDParenStack_.Pop();
        return Make(Tokens::RParen, spell);
    }

    /* Scan punctuation, special characters and brackets */
    if (Is('.'))
    {
        spell += TakeIt();
        if (Is('.'))
            return Make(Tokens::RangeSep, spell, true);
        return Make(Tokens::Dot, spell);
    }

    switch (chr_)
    {
        case ';': return Make(Tokens::Semicolon, true); break;
        case ',': return Make(Tokens::Comma,     true); break;
        case '(': return Make(Tokens::LBracket,  true); break;
        case ')': return Make(Tokens::RBracket,  true); break;
        case '{': return Make(Tokens::LCurly,    true); break;
        case '}': return Make(Tokens::RCurly,    true); break;
    }

    ErrorUnexpected();

    return nullptr;
}

TokenPtr Scanner::ScanStringLiteral()
{
    std::string spell;
    SourceArea area { Pos() };

    while (true)
    {
        /* Take opening '\"' character */
        Take('\"');

        while (true)
        {
            /* Check for escape characters */
            while (Is('\\'))
            {
                TakeIt();

                if (IsEscapeChar())
                    spell += chr_;
                else
                {
                    auto chr = TakeIt();
                    Error("unexpected escape character '" + ToStr(chr) + "' in string literal");
                }

                TakeIt();
            }

            if (Is(0))
                ErrorEOF();

            /* Check for closing '\"' character */
            if (Is('\"'))
            {
                TakeIt();
                area.end = Pos();
                break;
            }

            /* Append character to string literal */
            spell += TakeIt();
        }

        /* Search for next string literal (which will be appended to this token) */
        IgnoreWhiteSpaces();

        if (!Is('\"'))
            break;

        spell += '\n';
    }

    /* Return final string literal token */
    return Make(Tokens::StringLiteral, spell, area);
}

TokenPtr Scanner::ScanVerbatimStringLiteral()
{
    std::string spell;
    SourceArea area { Pos() };

    while (true)
    {
        /* Take opening '\"' character */
        Take('\"');

        while (true)
        {
            /* Check for escape characters */
            while (Is('\\'))
            {
                TakeIt();
                spell += '\\';
            }

            if (Is(0))
                ErrorEOF();

            /* Check for closing '\"' character */
            if (Is('\"'))
            {
                TakeIt();

                /* Check for double quotes */
                if (!Is('\"'))
                {
                    area.end = Pos();
                    break;
                }
            }

            /* Append character to string literal */
            spell += TakeIt();
        }

        /* Search for next string literal (which will be appended to this token) */
        IgnoreWhiteSpaces();

        if (!Is('\"'))
            break;

        spell += '\n';
    }

    /* Return final string literal token */
    return Make(Tokens::StringLiteral, spell, area);
}

TokenPtr Scanner::ScanIdentifier()
{
    /* Scan identifier string */
    std::string spell;
    spell += TakeIt();

    while (std::isalnum(UChr()) || Is('_'))
        spell += TakeIt();

    /* Check for reserved internal names */
    if (spell.compare(0, 6, "__xx__") == 0)
        Error("reserved prefix \"__xx__\" used in identifier \"" + spell + "\"");

    /* Scan reserved words */
    auto it = Keywords().find(spell);
    if (it != Keywords().end())
    {
        if (it->second == Tokens::Reserved)
            Error("identifier \"" + spell + "\" is reserved for future use");
        return Make(it->second, spell);
    }

    /* Return as identifier */
    return Make(Tokens::Ident, spell);
}

TokenPtr Scanner::ScanAssignShiftRelationOp(const char chr)
{
    std::string spell;
    spell += TakeIt();

    if (Is(chr))
    {
        spell += TakeIt();

        if (Is('='))
        {
            spell += TakeIt();
            return Make(Tokens::ModifyAssignOp, spell);
        }

        return Make(Tokens::ShiftOp, spell);
    }

    if (Is('='))
        spell += TakeIt();

    return Make(Tokens::RelationOp, spell);
}

TokenPtr Scanner::ScanPlusOp()
{
    std::string spell;
    spell += TakeIt();

    if (Is('+'))
    {
        spell += TakeIt();
        return Make(Tokens::PostAssignOp, spell);
    }
    else if (Is('='))
    {
        spell += TakeIt();
        return Make(Tokens::ModifyAssignOp, spell);
    }

    return Make(Tokens::AddOp, spell);
}

TokenPtr Scanner::ScanMinusOp()
{
    std::string spell;
    spell += TakeIt();

    if (Is('-'))
    {
        spell += TakeIt();
        return Make(Tokens::PostAssignOp, spell);
    }
    else if (Is('='))
    {
        spell += TakeIt();
        return Make(Tokens::ModifyAssignOp, spell);
    }
    else if (Is('>'))
    {
        spell += TakeIt();
        return Make(Tokens::Arrow, spell);
    }

    return Make(Tokens::SubOp, spell);
}

TokenPtr Scanner::ScanNumber()
{
    if (!std::isdigit(UChr()))
        Error("expected digit");

    /* Take first number (literals like ".0" are not allowed) */
    std::string spell;

    const auto startChr = TakeIt();
    spell += startChr;

    /* Check for hex, octal, or binary number */
    if (startChr == '0')
    {
        switch (chr_)
        {
            case 'x':
                TakeIt();
                return ScanHexNumber();
            case 'o':
                TakeIt();
                return ScanOctNumber();
            case 'b':
                TakeIt();
                return ScanBinNumber();
        }
    }

    /* Scan integer or floating-point number */
    auto type = Tokens::IntLiteral;

    ScanDecimalLiteral(spell);

    if (Is('.'))
    {
        spell += TakeIt();

        if (std::isdigit(UChr()))
            ScanDecimalLiteral(spell);
        else
            Error("floating-point literals must have a decimal on both sides of the dot (e.g. '0.0' but not '0.' or '.0')");

        type = Tokens::FloatLiteral;
    }

    if (std::isalpha(UChr()) || Is('.'))
        ErrorLetterInNumber();

    /* Create number token */
    return Make(type, spell);
}

TokenPtr Scanner::ScanHexNumber()
{
    /* Scan hex literal */
    std::string spell;
    while (std::isxdigit(UChr()))
        spell += TakeIt();

    /* Check for wrong appendix */
    if ( ( std::isalpha(UChr()) && !std::isxdigit(UChr()) ) || Is('.') )
        ErrorLetterInNumber();

    /* Convert literal to decimal */
    spell = ToStr(HexToNum<int>(spell));
    return Make(Tokens::IntLiteral, spell);
}

TokenPtr Scanner::ScanOctNumber()
{
    /* Scan octal literal */
    std::string spell;
    while (chr_ >= '0' && chr_ <= '7')
        spell += TakeIt();

    /* Check for wrong appendix */
    if (std::isalpha(UChr()) || Is('.') )
        ErrorLetterInNumber();

    /* Convert literal to decimal */
    spell = ToStr(OctToNum<int>(spell));
    return Make(Tokens::IntLiteral, spell);
}

TokenPtr Scanner::ScanBinNumber()
{
    /* Scan binary literal */
    std::string spell;
    while (Is('1') || Is('0'))
        spell += TakeIt();

    /* Check for wrong appendix */
    if (std::isalpha(UChr()) || Is('.') )
        ErrorLetterInNumber();

    /* Convert literal to decimal */
    spell = ToStr(BinToNum<int>(spell));
    return Make(Tokens::IntLiteral, spell);
}

void Scanner::ScanDecimalLiteral(std::string& spell)
{
    while (std::isdigit(UChr()))
        spell += TakeIt();
}

bool Scanner::IsEscapeChar() const
{
    return
        ( chr_ >= '0' && chr_ <= '7') ||
        Is('\\') || Is('\"') || Is('\'') ||
        Is('\0') || Is( '?') || Is( 'a') ||
        Is( 'b') || Is( 'f') || Is( 'n') ||
        Is( 'r') || Is( 't') || Is( 'v') ||
        Is( 'x') || Is( 'u') || Is( 'U');
}

} // /namespace SyntaxAnalyzer

// ================================================================================<|endoftext|>