Author: tkreuzer
Date: Wed Feb 11 14:37:25 2009
New Revision: 39558
URL:
http://svn.reactos.org/svn/reactos?rev=39558&view=rev
Log:
Implement hpp - the header preprocessor
It can parse headers and create new headers from them based on a simple prepreprocessing
language that's compatible with the C preprocessor, so the source file stays a valid
header. It works, but doesn't yet support different folders.
Added:
trunk/reactos/tools/hpp/ (with props)
trunk/reactos/tools/hpp/hpp.c (with props)
trunk/reactos/tools/hpp/hpp.rbuild (with props)
Propchange: trunk/reactos/tools/hpp/
------------------------------------------------------------------------------
svn:mergeinfo =
Added: trunk/reactos/tools/hpp/hpp.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/tools/hpp/hpp.c?rev=39558&…
==============================================================================
--- trunk/reactos/tools/hpp/hpp.c (added)
+++ trunk/reactos/tools/hpp/hpp.c [iso-8859-1] Wed Feb 11 14:37:25 2009
@@ -1,0 +1,509 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef DBG
+#define trace printf
+#else
+#define trace if (0) printf
+#endif
+
+typedef struct _DEFINE
+{
+ struct _DEFINE *pNext;
+ int len;
+ int val;
+ char szName[1];
+} DEFINE, *PDEFINE;
+
+DEFINE *gpDefines = 0;
+int iLine;
+const char *gpszCurFile;
+
+char*
+convert_path(const char* origpath)
+{
+ char* newpath;
+ int i;
+
+ newpath = strdup(origpath);
+
+ i = 0;
+ while (newpath[i] != 0)
+ {
+#ifdef UNIX_PATHS
+ if (newpath[i] == '\\')
+ {
+ newpath[i] = '/';
+ }
+#else
+#ifdef DOS_PATHS
+ if (newpath[i] == '/')
+ {
+ newpath[i] = '\\';
+ }
+#endif
+#endif
+ i++;
+ }
+ return(newpath);
+}
+
+char*
+GetFolder(const char* pszFullPath)
+{
+ return ".";
+}
+
+void*
+LoadFile(const char* pszFileName, size_t* pFileSize)
+{
+ FILE* file;
+ void* pFileData = NULL;
+
+ file = fopen(pszFileName, "rb");
+ if (file != NULL)
+ {
+ fseek(file, 0L, SEEK_END);
+ *pFileSize = ftell(file);
+ fseek(file, 0L, SEEK_SET);
+ pFileData = malloc(*pFileSize);
+ if (pFileData != NULL)
+ {
+ if (*pFileSize != fread(pFileData, 1, *pFileSize, file))
+ {
+ free(pFileData);
+ pFileData = NULL;
+ }
+ }
+ fclose(file);
+ }
+ return pFileData;
+}
+
+
+int
+error(char *format, ...)
+{
+ va_list valist;
+ int res;
+ va_start(valist, format);
+ res = vfprintf(stderr, format, valist);
+ va_end(valist);
+ return res;
+}
+
+char*
+GetNextChar(const char *psz)
+{
+ while (*psz == ' ' || *psz == '\t') psz++;
+ return (char*)psz;
+}
+
+char*
+GetNextLine(char *pszLine)
+{
+ /* Walk to the end of the line */
+ while (*pszLine != 13 && *pszLine != 10 && *pszLine != 0) pszLine++;
+
+ /* Skip one CR/LF */
+ if (pszLine[0] == 13 && pszLine[1] == 10)
+ pszLine += 2;
+ else if (pszLine[0] == 13 || pszLine[0] == 10)
+ pszLine++;
+
+ if (*pszLine == 0)
+ {
+ return 0;
+ }
+
+ return pszLine;
+}
+
+int
+strxlen(const char *psz)
+{
+ int len = 0;
+ while (isalnum(*psz) || *psz == '_')
+ {
+ psz++;
+ len++;
+ }
+ return len;
+}
+
+
+void
+WriteLine(char *pszLine, FILE *fileOut)
+{
+ char * pszEnd;
+
+ pszEnd = strchr(pszLine, '\n');
+ if (pszEnd)
+ {
+ int len = pszEnd - pszLine + 1;
+ fwrite(pszLine, 1, len, fileOut);
+ }
+}
+
+int
+EvaluateConstant(const char *p, char **pNext)
+{
+ PDEFINE pDefine;
+ int len;
+
+ len = strxlen(p);
+ if (pNext)
+ *pNext = (char*)p + len;
+
+ /* search for the define in the global list */
+ pDefine = gpDefines;
+ while (pDefine != 0)
+ {
+ trace("found a define: %s\n", pDefine->szName);
+ if (pDefine->len == len)
+ {
+ if (strncmp(p, pDefine->szName, len) == 0)
+ {
+ return pDefine->val;
+ }
+ }
+ pDefine = pDefine->pNext;
+ }
+ return 0;
+}
+
+int
+EvaluateExpression(char *pExpression, char **pNext)
+{
+ char *p, *pstart;
+ int inv, thisval, val = 0;
+
+ trace("evaluating expression\n");
+
+ pstart = GetNextChar(pExpression);
+ if (*pstart != '(')
+ {
+ error("Parse error: expected '(' \n");
+ return -1;
+ }
+
+ while (1)
+ {
+ /* Get the start of the real expression */
+ p = pstart;
+ if ((p[0] == '&' && p[1] == '&') ||
+ (p[0] == '|' && p[1] == '|'))
+ {
+ p++;
+ }
+ p = GetNextChar(p + 1);
+
+ /* Check for inversion modifier */
+ if (*p == '!')
+ {
+ inv = 1;
+ p = GetNextChar(p + 1);
+ }
+ else
+ inv = 0;
+
+ /* Beginning of a new subexpression? */
+ if (*p == '(')
+ {
+ /* Evaluate subexpression */
+ thisval = EvaluateExpression(p, &p);
+ }
+ else if (isdigit(*p))
+ {
+ thisval = strtod(p, &p);
+ trace("found a num: %d\n", thisval);
+ }
+ else if (isalpha(*p) || *p == '_')
+ {
+ thisval = EvaluateConstant(p, &p);
+ }
+ else
+ {
+ error("..Parse error, expected '(' or constant in line
%d\n",
+ iLine);
+ return -1;
+ }
+
+ if (inv)
+ thisval = !thisval;
+
+ /* Check how to combine the current value */
+ if (pstart[0] == '(')
+ {
+ val = thisval;
+ }
+ else if (pstart[0] == '&' && pstart[1] == '&')
+ {
+ val = val && thisval;
+ }
+ else if (pstart[0] == '&' && pstart[1] != '&')
+ {
+ val = val & thisval;
+ }
+ else if (pstart[0] == '|' && pstart[1] == '|')
+ {
+ trace("found || val = %d, thisval = %d\n", val, thisval);
+ val = val || thisval;
+ }
+ else if (pstart[0] == '|' && pstart[1] != '|')
+ {
+ val = val | thisval;
+ }
+ else if (pstart[0] == '+')
+ {
+ val = val + thisval;
+ }
+ else
+ {
+ error("+Parse error: expected '(' or operator in Line %d, got
%c\n",
+ iLine, pstart[0]);
+ return -1;
+ }
+
+ p = GetNextChar(p);
+
+ /* End of current subexpression? */
+ if (*p == ')')
+ {
+ if (pNext)
+ {
+ *pNext = p + 1;
+ }
+ return val;
+ }
+
+ /* Continue with a new start position */
+ pstart = p;
+ }
+
+ return val;
+}
+
+int
+ParseInputFile(const char *pszInFile, FILE *fileOut)
+{
+ char* pInputData, *pCurrentLine, *p1, *p2;
+ size_t cbInFileLenth, len;
+ int iIfLevel, iCopyLevel;
+
+ trace("parsing input file: %s\n", pszInFile);
+
+ /* Set the global file name */
+ gpszCurFile = pszInFile;
+
+ /* Load the input file into memory */
+ pInputData = LoadFile(pszInFile, &cbInFileLenth);
+ if (!pInputData)
+ {
+ error("Could not load input file %s\n", pszInFile);
+ return -1;
+ }
+
+ /* Zero terminate the file */
+ pInputData[cbInFileLenth] = 0;
+
+ pCurrentLine = pInputData;
+ iLine = 1;
+ iCopyLevel = iIfLevel = 0;
+
+ /* The main processing loop */
+ do
+ {
+ trace("line %d: ", iLine);
+
+ /* If this is a normal line ... */
+ if (pCurrentLine[0] != '$')
+ {
+ /* Check if we are to copy this line */
+ if (iCopyLevel == iIfLevel)
+ {
+ trace("copying\n");
+ WriteLine(pCurrentLine, fileOut);
+ }
+ else
+ trace("skipping\n");
+
+ /* Continue with next line */
+ continue;
+ }
+
+ /* Check for $endif */
+ if (strncmp(pCurrentLine, "$endif", 6) == 0)
+ {
+ trace("found $endif\n");
+ if (iIfLevel <= 0)
+ {
+ error("Parse error: $endif without $if in %s:%d\n", pszInFile,
iLine);
+ return -1;
+ }
+ if (iCopyLevel == iIfLevel)
+ {
+ iCopyLevel--;
+ }
+ iIfLevel--;
+
+ /* Continue with next line */
+ continue;
+ }
+
+ /* The rest is only parsed when we are in a true block */
+ if (iCopyLevel < iIfLevel)
+ {
+ trace("skipping\n");
+
+ /* Continue with next line */
+ continue;
+ }
+
+ /* Check for $define */
+ if (strncmp(pCurrentLine, "$define", 7) == 0)
+ {
+ PDEFINE pDefine;
+
+ trace("found $define\n");
+ p1 = GetNextChar(pCurrentLine + 7);
+ if (*p1 != '(')
+ {
+ error("Parse error: expected '(' at %s:%d\n",
+ pszInFile, iLine);
+ return -1;
+ }
+ p1 = GetNextChar(p1 + 1);
+ len = strxlen(p1);
+ p2 = p1 + len;
+ if (*p2 != ')')
+ {
+ error("Parse error: expected ')' at %s:%d\n",
+ pszInFile, iLine);
+ return -1;
+ }
+
+ /* Insert the new define into the global list */
+ pDefine = malloc(sizeof(DEFINE) + len);
+ strncpy(pDefine->szName, p1, len);
+ pDefine->szName[len] = 0;
+ pDefine->len = len;
+ pDefine->val = 1;
+ pDefine->pNext = gpDefines;
+ gpDefines = pDefine;
+ }
+
+ /* Check for $if */
+ else if (strncmp(pCurrentLine, "$if", 3) == 0)
+ {
+ int val;
+
+ trace("found $if\n");
+ /* Increase the if-level */
+ iIfLevel++;
+
+ /* Get beginning of the expression */
+ p1 = GetNextChar(pCurrentLine + 3);
+
+ /* evaluate the expression */
+ val = EvaluateExpression(p1, 0);
+
+ if (val)
+ {
+ iCopyLevel = iIfLevel;
+ }
+ else if (val == -1)
+ {
+ /* Parse error */
+ return -1;
+ }
+ }
+
+ /* Check for $include */
+ else if (strncmp(pCurrentLine, "$include", 8) == 0)
+ {
+ int ret;
+
+ trace("found $include\n");
+ p1 = GetNextChar(pCurrentLine + 8);
+ if (*p1 != '(')
+ {
+ error("Parse error: expected '(' at %s:%d, found
'%c'\n",
+ pszInFile, iLine, *p1);
+ return -1;
+ }
+ p1++;
+ p2 = strchr(p1, ')');
+ *p2 = 0;
+
+ /* Parse the included file */
+ ret = ParseInputFile(p1, fileOut);
+
+ /* Restore the global file name */
+ gpszCurFile = pszInFile;
+
+ if (ret == -1)
+ {
+ return -1;
+ }
+ }
+
+ /* Check for $$ comment */
+ else if (strncmp(pCurrentLine, "$$", 2) == 0)
+ {
+ trace("$$ ignored\n");
+ /* continue with next line */
+ continue;
+ }
+
+ else
+ {
+ trace("wot:%s\n", pCurrentLine);
+ }
+
+ /* Continue with next line */
+ }
+ while (pCurrentLine = GetNextLine(pCurrentLine),
+ iLine++,
+ pCurrentLine != 0);
+
+ /* Free the file data */
+ free(pInputData);
+
+ return 0;
+}
+
+
+int
+main(int argc, char* argv[])
+{
+ char *pszInFolder, *pszInFile, *pszOutFile;
+ FILE* fileOut;
+ int ret;
+
+ if (argc != 3)
+ {
+ error("Usage: hc <inputfile> <outputfile>\n");
+ exit(1);
+ }
+
+ pszInFile = convert_path(argv[1]);
+ pszOutFile = convert_path(argv[2]);
+ pszInFolder = GetFolder(pszInFile);
+
+ fileOut = fopen(pszOutFile, "wb");
+ if (fileOut == NULL)
+ {
+ error("Cannot open output file %s", pszOutFile);
+ exit(1);
+ }
+
+ ret = ParseInputFile(pszInFile, fileOut);
+
+ fclose(fileOut);
+
+ return ret;
+}
Propchange: trunk/reactos/tools/hpp/hpp.c
------------------------------------------------------------------------------
svn:eol-style = native
Added: trunk/reactos/tools/hpp/hpp.rbuild
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/tools/hpp/hpp.rbuild?rev=3…
==============================================================================
--- trunk/reactos/tools/hpp/hpp.rbuild (added)
+++ trunk/reactos/tools/hpp/hpp.rbuild [iso-8859-1] Wed Feb 11 14:37:25 2009
@@ -1,0 +1,6 @@
+<?xml version="1.0"?>
+<!DOCTYPE module SYSTEM "../../tools/rbuild/project.dtd">
+<module name="hpp" type="buildtool">
+ <include base="hpp">.</include>
+ <file>hpp.c</file>
+</module>
Propchange: trunk/reactos/tools/hpp/hpp.rbuild
------------------------------------------------------------------------------
svn:eol-style = native