зеркало из https://github.com/stride3d/CppNet.git
initial commit
This commit is contained in:
Родитель
31a5f5a408
Коммит
c4dd3abb55
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Anarres C Preprocessor
|
||||
* Copyright (c) 2007-2008, Shevek
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace CppNet {
|
||||
/**
|
||||
* A macro argument.
|
||||
*
|
||||
* This encapsulates a raw and preprocessed token stream.
|
||||
*/
|
||||
internal class Argument : List<Token> {
|
||||
public const int NO_ARGS = -1;
|
||||
|
||||
private List<Token> _expansion;
|
||||
|
||||
public Argument() {
|
||||
this._expansion = null;
|
||||
}
|
||||
|
||||
public void addToken(Token tok) {
|
||||
Add(tok);
|
||||
}
|
||||
|
||||
internal void expand(Preprocessor p) {
|
||||
/* Cache expansion. */
|
||||
if(_expansion == null) {
|
||||
this._expansion = p.expand(this);
|
||||
// System.out.println("Expanded arg " + this);
|
||||
}
|
||||
}
|
||||
|
||||
public Iterator<Token> expansion()
|
||||
{
|
||||
return _expansion.iterator();
|
||||
}
|
||||
|
||||
override public String ToString() {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.Append("Argument(");
|
||||
// buf.Append(super.toString());
|
||||
buf.Append("raw=[ ");
|
||||
for (int i = 0; i < this.Count; i++)
|
||||
buf.Append(this[i].getText());
|
||||
buf.Append(" ];expansion=[ ");
|
||||
if(_expansion == null)
|
||||
buf.Append("null");
|
||||
else
|
||||
for(int i = 0; i < _expansion.Count; i++)
|
||||
buf.Append(_expansion[i].getText());
|
||||
buf.Append(" ])");
|
||||
return buf.ToString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{C2FD9262-69F8-4B75-9AB1-FF359C9143E9}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>CppNet</RootNamespace>
|
||||
<AssemblyName>CppNet</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Argument.cs" />
|
||||
<Compile Include="Feature.cs" />
|
||||
<Compile Include="FileLexerSource.cs" />
|
||||
<Compile Include="FixedTokenSource.cs" />
|
||||
<Compile Include="JavaCompat\JavaCompat.cs" />
|
||||
<Compile Include="JavaFile.cs" />
|
||||
<Compile Include="JavaFileSystem.cs" />
|
||||
<Compile Include="JoinReader.cs" />
|
||||
<Compile Include="LexerException.cs" />
|
||||
<Compile Include="LexerSource.cs" />
|
||||
<Compile Include="Macro.cs" />
|
||||
<Compile Include="MacroTokenSource.cs" />
|
||||
<Compile Include="Preprocessor.cs" />
|
||||
<Compile Include="PreprocessorListener.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Source.cs" />
|
||||
<Compile Include="SourceIterator.cs" />
|
||||
<Compile Include="State.cs" />
|
||||
<Compile Include="StringLexerSource.cs" />
|
||||
<Compile Include="Token.cs" />
|
||||
<Compile Include="VirtualFile.cs" />
|
||||
<Compile Include="VirtualFileSystem.cs" />
|
||||
<Compile Include="Warning.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* Anarres C Preprocessor
|
||||
* Copyright (c) 2007-2008, Shevek
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package org.anarres.cpp;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
|
||||
import static org.anarres.cpp.Token.*;
|
||||
|
||||
/**
|
||||
* A Reader wrapper around the Preprocessor.
|
||||
*
|
||||
* This is a utility class to provide a transparent {@link Reader}
|
||||
* which preprocesses the input text.
|
||||
*
|
||||
* @see Preprocessor
|
||||
* @see Reader
|
||||
*/
|
||||
public class CppReader extends Reader {
|
||||
|
||||
private Preprocessor cpp;
|
||||
private String token;
|
||||
private int idx;
|
||||
|
||||
public CppReader(final Reader r) {
|
||||
cpp = new Preprocessor(new LexerSource(r, true) {
|
||||
@Override
|
||||
public String getName() {
|
||||
return "<CppReader Input@" +
|
||||
System.identityHashCode(r) + ">";
|
||||
}
|
||||
});
|
||||
token = "";
|
||||
idx = 0;
|
||||
}
|
||||
|
||||
public CppReader(Preprocessor p) {
|
||||
cpp = p;
|
||||
token = "";
|
||||
idx = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Preprocessor used by this CppReader.
|
||||
*/
|
||||
public Preprocessor getPreprocessor() {
|
||||
return cpp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the given name as a macro.
|
||||
*
|
||||
* This is a convnience method.
|
||||
*/
|
||||
public void addMacro(String name)
|
||||
throws LexerException {
|
||||
cpp.addMacro(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the given name as a macro.
|
||||
*
|
||||
* This is a convnience method.
|
||||
*/
|
||||
public void addMacro(String name, String value)
|
||||
throws LexerException {
|
||||
cpp.addMacro(name, value);
|
||||
}
|
||||
|
||||
private boolean refill()
|
||||
throws IOException {
|
||||
try {
|
||||
assert cpp != null : "cpp is null : was it closed?";
|
||||
if (token == null)
|
||||
return false;
|
||||
while (idx >= token.length()) {
|
||||
Token tok = cpp.token();
|
||||
switch (tok.getType()) {
|
||||
case EOF:
|
||||
token = null;
|
||||
return false;
|
||||
case CCOMMENT:
|
||||
case CPPCOMMENT:
|
||||
if (!cpp.getFeature(Feature.KEEPCOMMENTS)) {
|
||||
token = " ";
|
||||
break;
|
||||
}
|
||||
default:
|
||||
token = tok.getText();
|
||||
break;
|
||||
}
|
||||
idx = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch (LexerException e) {
|
||||
/* Never happens.
|
||||
if (e.getCause() instanceof IOException)
|
||||
throw (IOException)e.getCause();
|
||||
*/
|
||||
IOException ie = new IOException(String.valueOf(e));
|
||||
ie.initCause(e);
|
||||
throw ie;
|
||||
}
|
||||
}
|
||||
|
||||
public int read()
|
||||
throws IOException {
|
||||
if (!refill())
|
||||
return -1;
|
||||
return token.charAt(idx++);
|
||||
}
|
||||
|
||||
/* XXX Very slow and inefficient. */
|
||||
public int read(char cbuf[], int off, int len)
|
||||
throws IOException {
|
||||
if (token == null)
|
||||
return -1;
|
||||
for (int i = 0; i < len; i++) {
|
||||
int ch = read();
|
||||
if (ch == -1)
|
||||
return i;
|
||||
cbuf[off + i] = (char)ch;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
public void close()
|
||||
throws IOException {
|
||||
if (cpp != null) {
|
||||
cpp.close();
|
||||
cpp = null;
|
||||
}
|
||||
token = null;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* Anarres C Preprocessor
|
||||
* Copyright (c) 2007-2008, Shevek
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package org.anarres.cpp;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.tools.ant.BuildException;
|
||||
import org.apache.tools.ant.Task;
|
||||
|
||||
import org.anarres.cpp.LexerException;
|
||||
import org.anarres.cpp.Preprocessor;
|
||||
import org.anarres.cpp.Token;
|
||||
|
||||
/**
|
||||
* An ant task for jcpp.
|
||||
*/
|
||||
public class CppTask extends Task {
|
||||
|
||||
private static class Macro {
|
||||
private String name;
|
||||
private String value;
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
private File input;
|
||||
private File output;
|
||||
private Preprocessor cpp;
|
||||
|
||||
public CppTask() {
|
||||
super();
|
||||
cpp = new Preprocessor();
|
||||
}
|
||||
|
||||
public void setInput(File input) {
|
||||
this.input = input;
|
||||
}
|
||||
|
||||
public void setOutput(File output) {
|
||||
this.output = output;
|
||||
}
|
||||
|
||||
public void addMacro(Macro macro) {
|
||||
try {
|
||||
cpp.addMacro(macro.getName(), macro.getValue());
|
||||
}
|
||||
catch (LexerException e) {
|
||||
throw new BuildException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void execute() {
|
||||
FileWriter writer = null;
|
||||
try {
|
||||
if (input == null)
|
||||
throw new BuildException("Input not specified");
|
||||
if (output == null)
|
||||
throw new BuildException("Output not specified");
|
||||
cpp.addInput(this.input);
|
||||
writer = new FileWriter(this.output);
|
||||
for (;;) {
|
||||
Token tok = cpp.token();
|
||||
if (tok != null && tok.getType() == Token.EOF)
|
||||
break;
|
||||
writer.write(tok.getText());
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new BuildException(e);
|
||||
}
|
||||
finally {
|
||||
if (writer != null) {
|
||||
try {
|
||||
writer.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Anarres C Preprocessor
|
||||
* Copyright (c) 2007-2008, Shevek
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace CppNet
|
||||
{
|
||||
/**
|
||||
* Features of the Preprocessor, which may be enabled or disabled.
|
||||
*/
|
||||
[Flags]
|
||||
public enum Feature
|
||||
{
|
||||
NONE = 0,
|
||||
/** Supports ANSI digraphs. */
|
||||
DIGRAPHS = 1 << 0,
|
||||
/** Supports ANSI trigraphs. */
|
||||
TRIGRAPHS = 1 << 1,
|
||||
/** Outputs linemarker tokens. */
|
||||
LINEMARKERS = 1 << 2,
|
||||
/** Reports tokens of type INVALID as errors. */
|
||||
CSYNTAX = 1 << 3,
|
||||
/** Preserves comments in the lexed output. */
|
||||
KEEPCOMMENTS = 1 << 4,
|
||||
/** Preserves comments in the lexed output, even when inactive. */
|
||||
KEEPALLCOMMENTS = 1 << 5,
|
||||
VERBOSE = 1 << 6,
|
||||
DEBUG = 1 << 7,
|
||||
|
||||
/** Supports lexing of objective-C. */
|
||||
OBJCSYNTAX = 1 << 8,
|
||||
INCLUDENEXT = 1 << 9
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Anarres C Preprocessor
|
||||
* Copyright (c) 2007-2008, Shevek
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace CppNet {
|
||||
|
||||
/**
|
||||
* A {@link Source} which lexes a file.
|
||||
*
|
||||
* The input is buffered.
|
||||
*
|
||||
* @see Source
|
||||
*/
|
||||
public class FileLexerSource : LexerSource {
|
||||
// private File file;
|
||||
private String path;
|
||||
|
||||
/**
|
||||
* Creates a new Source for lexing the given File.
|
||||
*
|
||||
* Preprocessor directives are honoured within the file.
|
||||
*/
|
||||
public FileLexerSource(FileInfo file, String path) : base(new StreamReader(file.OpenRead()), true)
|
||||
{
|
||||
|
||||
// this.file = file;
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public FileLexerSource(FileInfo file) :
|
||||
this(file, file.FullName) {
|
||||
}
|
||||
|
||||
public FileLexerSource(String path) :
|
||||
this(new FileInfo(path)) {
|
||||
}
|
||||
|
||||
override internal String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
override internal String getName()
|
||||
{
|
||||
return getPath();
|
||||
}
|
||||
|
||||
override public string ToString() {
|
||||
return "file " + path;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Anarres C Preprocessor
|
||||
* Copyright (c) 2007-2008, Shevek
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace CppNet {
|
||||
|
||||
internal class FixedTokenSource : Source {
|
||||
private static readonly Token EOF =
|
||||
new Token(Token.EOF, "<ts-eof>");
|
||||
|
||||
private List<Token> tokens;
|
||||
private int idx;
|
||||
|
||||
internal FixedTokenSource(params Token[] tokens) {
|
||||
this.tokens = new List<Token>(tokens);
|
||||
this.idx = 0;
|
||||
}
|
||||
|
||||
internal FixedTokenSource(List<Token> tokens) {
|
||||
this.tokens = tokens;
|
||||
this.idx = 0;
|
||||
}
|
||||
|
||||
public override Token token() {
|
||||
if (idx >= tokens.Count)
|
||||
return EOF;
|
||||
return tokens[idx++];
|
||||
}
|
||||
|
||||
override public String ToString() {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.Append("constant token stream " + tokens);
|
||||
Source parent = getParent();
|
||||
if (parent != null)
|
||||
buf.Append(" in ").Append(parent);
|
||||
return buf.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Anarres C Preprocessor
|
||||
* Copyright (c) 2007-2008, Shevek
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package org.anarres.cpp;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.IOException;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Iterator;
|
||||
|
||||
import static org.anarres.cpp.Token.*;
|
||||
|
||||
/**
|
||||
* A {@link Source} which lexes a file.
|
||||
*
|
||||
* The input is buffered.
|
||||
*
|
||||
* @see Source
|
||||
*/
|
||||
public class InputLexerSource extends LexerSource {
|
||||
/**
|
||||
* Creates a new Source for lexing the given Reader.
|
||||
*
|
||||
* Preprocessor directives are honoured within the file.
|
||||
*/
|
||||
public InputLexerSource(InputStream input)
|
||||
throws IOException {
|
||||
super(
|
||||
new BufferedReader(
|
||||
new InputStreamReader(
|
||||
input
|
||||
)
|
||||
),
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
/* pp */ String getPath() {
|
||||
return "<standard-input>";
|
||||
}
|
||||
|
||||
@Override
|
||||
/* pp */ String getName() {
|
||||
return "standard input";
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return getPath();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using boolean = System.Boolean;
|
||||
//using Set = System.Collections.Generic.HashSet;
|
||||
//using ArrayList = System.Collections.Generic.List;
|
||||
//using Map = System.Collections.Generic.Dictionary;
|
||||
|
||||
namespace CppNet
|
||||
{
|
||||
static class JavaCompat
|
||||
{
|
||||
public static StringBuilder append(this StringBuilder bld, object value)
|
||||
{
|
||||
return bld.Append(value);
|
||||
}
|
||||
|
||||
public static int length(this string str)
|
||||
{
|
||||
return str.Length;
|
||||
}
|
||||
|
||||
public static char charAt(this string str, int i)
|
||||
{
|
||||
return str[i];
|
||||
}
|
||||
|
||||
public static T get<T>(this List<T> list, int i)
|
||||
{
|
||||
return list[i];
|
||||
}
|
||||
|
||||
public static Iterator<T> iterator<T>(this List<T> list)
|
||||
{
|
||||
return new ListIterator<T>(list);
|
||||
}
|
||||
|
||||
public static string toString(this object o)
|
||||
{
|
||||
return o.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
class ListIterator<T> : Iterator<T>
|
||||
{
|
||||
List<T> _list;
|
||||
int _index;
|
||||
|
||||
public ListIterator(List<T> list)
|
||||
{
|
||||
_list = list;
|
||||
}
|
||||
|
||||
public boolean hasNext()
|
||||
{
|
||||
return _index < _list.Count;
|
||||
}
|
||||
|
||||
public T next()
|
||||
{
|
||||
return _list[_index++];
|
||||
}
|
||||
|
||||
public void remove()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public interface Closeable
|
||||
{
|
||||
void close();
|
||||
}
|
||||
|
||||
public interface Iterable<T>
|
||||
{
|
||||
Iterator<T> iterator();
|
||||
}
|
||||
|
||||
public interface Iterator<T>
|
||||
{
|
||||
boolean hasNext();
|
||||
T next();
|
||||
void remove();
|
||||
}
|
||||
|
||||
public class IllegalStateException : Exception
|
||||
{
|
||||
public IllegalStateException(Exception ex) : base("Illegal State", ex) { }
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.IO;
|
||||
|
||||
namespace CppNet
|
||||
{
|
||||
public class JavaFile : VirtualFile
|
||||
{
|
||||
string _path;
|
||||
|
||||
public JavaFile(string path)
|
||||
{
|
||||
_path = Path.GetFullPath(path);
|
||||
}
|
||||
|
||||
public bool isFile()
|
||||
{
|
||||
return File.Exists(_path) && !File.GetAttributes(_path).HasFlag(FileAttributes.Directory);
|
||||
}
|
||||
|
||||
public string getPath()
|
||||
{
|
||||
return _path;
|
||||
}
|
||||
|
||||
public string getName()
|
||||
{
|
||||
return Path.GetFileName(_path);
|
||||
}
|
||||
|
||||
public VirtualFile getParentFile()
|
||||
{
|
||||
return new JavaFile(Path.GetDirectoryName(_path));
|
||||
}
|
||||
|
||||
public VirtualFile getChildFile(string name)
|
||||
{
|
||||
return new JavaFile(Path.Combine(_path, name));
|
||||
}
|
||||
|
||||
public Source getSource()
|
||||
{
|
||||
return new FileLexerSource(_path);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Anarres C Preprocessor
|
||||
* Copyright (c) 2007-2008, Shevek
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace CppNet
|
||||
{
|
||||
|
||||
/**
|
||||
* A virtual filesystem implementation using java.io.
|
||||
*/
|
||||
public class JavaFileSystem : VirtualFileSystem
|
||||
{
|
||||
|
||||
|
||||
public VirtualFile getFile(string path)
|
||||
{
|
||||
return new JavaFile(path);
|
||||
}
|
||||
|
||||
public VirtualFile getFile(string dir, string name)
|
||||
{
|
||||
return new JavaFile(Path.Combine(dir, name));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,221 @@
|
|||
/*
|
||||
* Anarres C Preprocessor
|
||||
* Copyright (c) 2007-2008, Shevek
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
|
||||
using System.IO;
|
||||
namespace CppNet
|
||||
{
|
||||
|
||||
internal class JoinReader /* extends Reader */ {
|
||||
private TextReader _in;
|
||||
|
||||
private PreprocessorListener listener;
|
||||
private LexerSource source;
|
||||
private bool trigraphs;
|
||||
private bool warnings;
|
||||
|
||||
private int newlines;
|
||||
private bool flushnl;
|
||||
private int[] unget;
|
||||
private int uptr;
|
||||
|
||||
public JoinReader(TextReader ain, bool trigraphs)
|
||||
{
|
||||
this._in = ain;
|
||||
this.trigraphs = trigraphs;
|
||||
this.newlines = 0;
|
||||
this.flushnl = false;
|
||||
this.unget = new int[2];
|
||||
this.uptr = 0;
|
||||
}
|
||||
|
||||
public JoinReader(TextReader ain) :
|
||||
this(ain, false)
|
||||
{
|
||||
}
|
||||
|
||||
public void setTrigraphs(bool enable, bool warnings)
|
||||
{
|
||||
this.trigraphs = enable;
|
||||
this.warnings = warnings;
|
||||
}
|
||||
|
||||
internal void init(Preprocessor pp, LexerSource s)
|
||||
{
|
||||
this.listener = pp.getListener();
|
||||
this.source = s;
|
||||
setTrigraphs(pp.getFeature(Feature.TRIGRAPHS),
|
||||
pp.getWarning(Warning.TRIGRAPHS));
|
||||
}
|
||||
|
||||
private int __read()
|
||||
{
|
||||
if(uptr > 0)
|
||||
return unget[--uptr];
|
||||
return _in.Read();
|
||||
}
|
||||
|
||||
private void _unread(int c)
|
||||
{
|
||||
if(c != -1)
|
||||
unget[uptr++] = c;
|
||||
System.Diagnostics.Debug.Assert(uptr <= unget.Length,
|
||||
"JoinReader ungets too many characters");
|
||||
}
|
||||
|
||||
protected void warning(String msg)
|
||||
{
|
||||
if(source != null)
|
||||
source.warning(msg);
|
||||
else
|
||||
throw new LexerException(msg);
|
||||
}
|
||||
|
||||
private char trigraph(char raw, char repl)
|
||||
{
|
||||
if(trigraphs) {
|
||||
if(warnings)
|
||||
warning("trigraph ??" + raw + " converted to " + repl);
|
||||
return repl;
|
||||
} else {
|
||||
if(warnings)
|
||||
warning("trigraph ??" + raw + " ignored");
|
||||
_unread(raw);
|
||||
_unread('?');
|
||||
return '?';
|
||||
}
|
||||
}
|
||||
|
||||
private int _read()
|
||||
{
|
||||
int c = __read();
|
||||
if(c == '?' && (trigraphs || warnings)) {
|
||||
int d = __read();
|
||||
if(d == '?') {
|
||||
int e = __read();
|
||||
switch(e) {
|
||||
case '(': return trigraph('(', '[');
|
||||
case ')': return trigraph(')', ']');
|
||||
case '<': return trigraph('<', '{');
|
||||
case '>': return trigraph('>', '}');
|
||||
case '=': return trigraph('=', '#');
|
||||
case '/': return trigraph('/', '\\');
|
||||
case '\'': return trigraph('\'', '^');
|
||||
case '!': return trigraph('!', '|');
|
||||
case '-': return trigraph('-', '~');
|
||||
}
|
||||
_unread(e);
|
||||
}
|
||||
_unread(d);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
public int read()
|
||||
{
|
||||
if(flushnl) {
|
||||
if(newlines > 0) {
|
||||
newlines--;
|
||||
return '\n';
|
||||
}
|
||||
flushnl = false;
|
||||
}
|
||||
|
||||
for(; ; ) {
|
||||
int c = _read();
|
||||
switch(c) {
|
||||
case '\\':
|
||||
int d = _read();
|
||||
switch(d) {
|
||||
case '\n':
|
||||
newlines++;
|
||||
continue;
|
||||
case '\r':
|
||||
newlines++;
|
||||
int e = _read();
|
||||
if(e != '\n')
|
||||
_unread(e);
|
||||
continue;
|
||||
default:
|
||||
_unread(d);
|
||||
return c;
|
||||
}
|
||||
case '\r':
|
||||
case '\n':
|
||||
case '\u2028':
|
||||
case '\u2029':
|
||||
case '\u000B':
|
||||
case '\u000C':
|
||||
case '\u0085':
|
||||
flushnl = true;
|
||||
return c;
|
||||
case -1:
|
||||
if(newlines > 0) {
|
||||
newlines--;
|
||||
return '\n';
|
||||
}
|
||||
goto default;
|
||||
default:
|
||||
return c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int read(char[] cbuf, int off, int len)
|
||||
{
|
||||
for(int i = 0; i < len; i++) {
|
||||
int ch = read();
|
||||
if(ch == -1)
|
||||
return i;
|
||||
cbuf[off + i] = (char)ch;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
public void close()
|
||||
{
|
||||
if(_in == null) {
|
||||
return;
|
||||
}
|
||||
_in.Close();
|
||||
}
|
||||
|
||||
|
||||
|
||||
override public String ToString()
|
||||
{
|
||||
return "JoinReader(nl=" + newlines + ")";
|
||||
}
|
||||
|
||||
/*
|
||||
public static void main(String[] args) throws IOException {
|
||||
FileReader f = new FileReader(new File(args[0]));
|
||||
BufferedReader b = new BufferedReader(f);
|
||||
JoinReader r = new JoinReader(b);
|
||||
BufferedWriter w = new BufferedWriter(
|
||||
new java.io.OutputStreamWriter(System.out)
|
||||
);
|
||||
int c;
|
||||
while ((c = r.read()) != -1) {
|
||||
w.write((char)c);
|
||||
}
|
||||
w.close();
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Anarres C Preprocessor
|
||||
* Copyright (c) 2007-2008, Shevek
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace CppNet {
|
||||
/**
|
||||
* A preprocessor exception.
|
||||
*
|
||||
* Note to users: I don't really like the name of this class. S.
|
||||
*/
|
||||
public class LexerException : Exception {
|
||||
public LexerException(String msg) : base(msg) { }
|
||||
|
||||
public LexerException(Exception cause) : base(cause.Message, cause) {}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,809 @@
|
|||
/*
|
||||
* Anarres C Preprocessor
|
||||
* Copyright (c) 2007-2008, Shevek
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace CppNet {
|
||||
|
||||
/** Does not handle digraphs. */
|
||||
public class LexerSource : Source {
|
||||
static bool isJavaIdentifierStart(int c) {
|
||||
return char.IsLetter((char)c) || c == '$' || c == '_';
|
||||
}
|
||||
static bool isJavaIdentifierPart(int c)
|
||||
{
|
||||
return char.IsLetter((char)c) || c == '$' || c == '_' || char.IsDigit((char)c);
|
||||
}
|
||||
static bool isIdentifierIgnorable(int c) {
|
||||
return c >= 0 && c <= 8 ||
|
||||
c >= 0xE && c <= 0x1B ||
|
||||
c >= 0x7F && c <= 0x9F ||
|
||||
char.GetUnicodeCategory((char)c) == System.Globalization.UnicodeCategory.Format;
|
||||
}
|
||||
|
||||
static int digit(char ch, int radix)
|
||||
{
|
||||
try {
|
||||
return Convert.ToInt32(ch.ToString(), radix);
|
||||
} catch {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
private static readonly bool DEBUG = false;
|
||||
|
||||
private JoinReader reader;
|
||||
private bool ppvalid;
|
||||
private bool bol;
|
||||
private bool include;
|
||||
|
||||
private bool digraphs;
|
||||
|
||||
/* Unread. */
|
||||
private int u0, u1;
|
||||
private int ucount;
|
||||
|
||||
private int line;
|
||||
private int column;
|
||||
private int lastcolumn;
|
||||
private bool cr;
|
||||
|
||||
/* ppvalid is:
|
||||
* false in StringLexerSource,
|
||||
* true in FileLexerSource */
|
||||
public LexerSource(TextReader r, bool ppvalid) {
|
||||
this.reader = new JoinReader(r);
|
||||
this.ppvalid = ppvalid;
|
||||
this.bol = true;
|
||||
this.include = false;
|
||||
|
||||
this.digraphs = true;
|
||||
|
||||
this.ucount = 0;
|
||||
|
||||
this.line = 1;
|
||||
this.column = 0;
|
||||
this.lastcolumn = -1;
|
||||
this.cr = false;
|
||||
}
|
||||
|
||||
override internal void init(Preprocessor pp) {
|
||||
base.init(pp);
|
||||
this.digraphs = pp.getFeature(Feature.DIGRAPHS);
|
||||
this.reader.init(pp, this);
|
||||
}
|
||||
|
||||
|
||||
override public int getLine() {
|
||||
return line;
|
||||
}
|
||||
|
||||
|
||||
override public int getColumn() {
|
||||
return column;
|
||||
}
|
||||
|
||||
|
||||
override internal bool isNumbered() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Error handling. */
|
||||
|
||||
private void _error(String msg, bool error) {
|
||||
int _l = line;
|
||||
int _c = column;
|
||||
if (_c == 0) {
|
||||
_c = lastcolumn;
|
||||
_l--;
|
||||
}
|
||||
else {
|
||||
_c--;
|
||||
}
|
||||
if (error)
|
||||
base.error(_l, _c, msg);
|
||||
else
|
||||
base.warning(_l, _c, msg);
|
||||
}
|
||||
|
||||
/* Allow JoinReader to call this. */
|
||||
internal void error(String msg)
|
||||
{
|
||||
_error(msg, true);
|
||||
}
|
||||
|
||||
/* Allow JoinReader to call this. */
|
||||
internal void warning(String msg) {
|
||||
_error(msg, false);
|
||||
}
|
||||
|
||||
/* A flag for string handling. */
|
||||
|
||||
internal void setInclude(bool b)
|
||||
{
|
||||
this.include = b;
|
||||
}
|
||||
|
||||
/*
|
||||
private bool _isLineSeparator(int c) {
|
||||
return Character.getType(c) == Character.LINE_SEPARATOR
|
||||
|| c == -1;
|
||||
}
|
||||
*/
|
||||
|
||||
/* XXX Move to JoinReader and canonicalise newlines. */
|
||||
private static bool isLineSeparator(int c) {
|
||||
switch ((char)c) {
|
||||
case '\r':
|
||||
case '\n':
|
||||
case '\u2028':
|
||||
case '\u2029':
|
||||
case '\u000B':
|
||||
case '\u000C':
|
||||
case '\u0085':
|
||||
return true;
|
||||
default:
|
||||
return (c == -1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private int read() {
|
||||
System.Diagnostics.Debug.Assert(ucount <= 2, "Illegal ucount: " + ucount);
|
||||
switch (ucount) {
|
||||
case 2:
|
||||
ucount = 1;
|
||||
return u1;
|
||||
case 1:
|
||||
ucount = 0;
|
||||
return u0;
|
||||
}
|
||||
|
||||
if (reader == null)
|
||||
return -1;
|
||||
|
||||
int c = reader.read();
|
||||
switch (c) {
|
||||
case '\r':
|
||||
cr = true;
|
||||
line++;
|
||||
lastcolumn = column;
|
||||
column = 0;
|
||||
break;
|
||||
case '\n':
|
||||
if (cr) {
|
||||
cr = false;
|
||||
break;
|
||||
}
|
||||
goto case '\u2028';
|
||||
/* fallthrough */
|
||||
case '\u2028':
|
||||
case '\u2029':
|
||||
case '\u000B':
|
||||
case '\u000C':
|
||||
case '\u0085':
|
||||
cr = false;
|
||||
line++;
|
||||
lastcolumn = column;
|
||||
column = 0;
|
||||
break;
|
||||
default:
|
||||
cr = false;
|
||||
column++;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
if (isLineSeparator(c)) {
|
||||
line++;
|
||||
lastcolumn = column;
|
||||
column = 0;
|
||||
}
|
||||
else {
|
||||
column++;
|
||||
}
|
||||
*/
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/* You can unget AT MOST one newline. */
|
||||
private void unread(int c) {
|
||||
/* XXX Must unread newlines. */
|
||||
if (c != -1) {
|
||||
if (isLineSeparator(c)) {
|
||||
line--;
|
||||
column = lastcolumn;
|
||||
cr = false;
|
||||
}
|
||||
else {
|
||||
column--;
|
||||
}
|
||||
switch (ucount) {
|
||||
case 0:
|
||||
u0 = c;
|
||||
ucount = 1;
|
||||
break;
|
||||
case 1:
|
||||
u1 = c;
|
||||
ucount = 2;
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException(
|
||||
"Cannot unget another character!"
|
||||
);
|
||||
}
|
||||
// reader.unread(c);
|
||||
}
|
||||
}
|
||||
|
||||
/* Consumes the rest of the current line into an invalid. */
|
||||
private Token invalid(StringBuilder text, String reason) {
|
||||
int d = read();
|
||||
while (!isLineSeparator(d)) {
|
||||
text.Append((char)d);
|
||||
d = read();
|
||||
}
|
||||
unread(d);
|
||||
return new Token(Token.INVALID, text.ToString(), reason);
|
||||
}
|
||||
|
||||
private Token ccomment() {
|
||||
StringBuilder text = new StringBuilder("/*");
|
||||
int d;
|
||||
do {
|
||||
do {
|
||||
d = read();
|
||||
text.Append((char)d);
|
||||
} while (d != '*');
|
||||
do {
|
||||
d = read();
|
||||
text.Append((char)d);
|
||||
} while (d == '*');
|
||||
} while (d != '/');
|
||||
return new Token(Token.CCOMMENT, text.ToString());
|
||||
}
|
||||
|
||||
private Token cppcomment() {
|
||||
StringBuilder text = new StringBuilder("//");
|
||||
int d = read();
|
||||
while (!isLineSeparator(d)) {
|
||||
text.Append((char)d);
|
||||
d = read();
|
||||
}
|
||||
unread(d);
|
||||
return new Token(Token.CPPCOMMENT, text.ToString());
|
||||
}
|
||||
|
||||
private int escape(StringBuilder text) {
|
||||
int d = read();
|
||||
switch (d) {
|
||||
case 'a': text.Append('a'); return 0x07;
|
||||
case 'b': text.Append('b'); return '\b';
|
||||
case 'f': text.Append('f'); return '\f';
|
||||
case 'n': text.Append('n'); return '\n';
|
||||
case 'r': text.Append('r'); return '\r';
|
||||
case 't': text.Append('t'); return '\t';
|
||||
case 'v': text.Append('v'); return 0x0b;
|
||||
case '\\': text.Append('\\'); return '\\';
|
||||
|
||||
case '0': case '1': case '2': case '3':
|
||||
case '4': case '5': case '6': case '7':
|
||||
int len = 0;
|
||||
int val = 0;
|
||||
do {
|
||||
val = (val << 3) + digit((char)d, 8);
|
||||
text.Append((char)d);
|
||||
d = read();
|
||||
} while(++len < 3 && digit((char)d, 8) != -1);
|
||||
unread(d);
|
||||
return val;
|
||||
|
||||
case 'x':
|
||||
len = 0;
|
||||
val = 0;
|
||||
do {
|
||||
val = (val << 4) + digit((char)d, 16);
|
||||
text.Append((char)d);
|
||||
d = read();
|
||||
} while(++len < 2 && digit((char)d, 16) != -1);
|
||||
unread(d);
|
||||
return val;
|
||||
|
||||
/* Exclude two cases from the warning. */
|
||||
case '"': text.Append('"'); return '"';
|
||||
case '\'': text.Append('\''); return '\'';
|
||||
|
||||
default:
|
||||
warning("Unnecessary escape character " + (char)d);
|
||||
text.Append((char)d);
|
||||
return d;
|
||||
}
|
||||
}
|
||||
|
||||
private Token character() {
|
||||
StringBuilder text = new StringBuilder("'");
|
||||
int d = read();
|
||||
if (d == '\\') {
|
||||
text.Append('\\');
|
||||
d = escape(text);
|
||||
}
|
||||
else if (isLineSeparator(d)) {
|
||||
unread(d);
|
||||
return new Token(Token.INVALID, text.ToString(),
|
||||
"Unterminated character literal");
|
||||
}
|
||||
else if (d == '\'') {
|
||||
text.Append('\'');
|
||||
return new Token(Token.INVALID, text.ToString(),
|
||||
"Empty character literal");
|
||||
}
|
||||
else if (char.IsControl((char)d)) {
|
||||
text.Append('?');
|
||||
return invalid(text, "Illegal unicode character literal");
|
||||
}
|
||||
else {
|
||||
text.Append((char)d);
|
||||
}
|
||||
|
||||
int e = read();
|
||||
if (e != '\'') {
|
||||
// error("Illegal character constant");
|
||||
/* We consume up to the next ' or the rest of the line. */
|
||||
for (;;) {
|
||||
if (isLineSeparator(e)) {
|
||||
unread(e);
|
||||
break;
|
||||
}
|
||||
text.Append((char)e);
|
||||
if (e == '\'')
|
||||
break;
|
||||
e = read();
|
||||
}
|
||||
return new Token(Token.INVALID, text.ToString(),
|
||||
"Illegal character constant " + text);
|
||||
}
|
||||
text.Append('\'');
|
||||
/* XXX It this a bad cast? */
|
||||
return new Token(Token.CHARACTER,
|
||||
text.ToString(), (char)d);
|
||||
}
|
||||
|
||||
private Token String(char open, char close) {
|
||||
StringBuilder text = new StringBuilder();
|
||||
text.Append(open);
|
||||
|
||||
StringBuilder buf = new StringBuilder();
|
||||
|
||||
for (;;) {
|
||||
int c = read();
|
||||
if (c == close) {
|
||||
break;
|
||||
}
|
||||
else if (c == '\\') {
|
||||
text.Append('\\');
|
||||
if (!include) {
|
||||
char d = (char)escape(text);
|
||||
buf.Append(d);
|
||||
}
|
||||
}
|
||||
else if (c == -1) {
|
||||
unread(c);
|
||||
// error("End of file in string literal after " + buf);
|
||||
return new Token(Token.INVALID, text.ToString(),
|
||||
"End of file in string literal after " + buf);
|
||||
}
|
||||
else if (isLineSeparator(c)) {
|
||||
unread(c);
|
||||
// error("Unterminated string literal after " + buf);
|
||||
return new Token(Token.INVALID, text.ToString(),
|
||||
"Unterminated string literal after " + buf);
|
||||
}
|
||||
else {
|
||||
text.Append((char)c);
|
||||
buf.Append((char)c);
|
||||
}
|
||||
}
|
||||
text.Append(close);
|
||||
return new Token(close == '>' ? Token.HEADER : Token.STRING,
|
||||
text.ToString(), buf.ToString());
|
||||
}
|
||||
|
||||
private Token _number(StringBuilder text, long val, int d) {
|
||||
int bits = 0;
|
||||
for (;;) {
|
||||
/* XXX Error check duplicate bits. */
|
||||
if (d == 'U' || d == 'u') {
|
||||
bits |= 1;
|
||||
text.Append((char)d);
|
||||
d = read();
|
||||
}
|
||||
else if (d == 'L' || d == 'l') {
|
||||
if ((bits & 4) != 0)
|
||||
/* XXX warn */ ;
|
||||
bits |= 2;
|
||||
text.Append((char)d);
|
||||
d = read();
|
||||
}
|
||||
else if (d == 'I' || d == 'i') {
|
||||
if ((bits & 2) != 0)
|
||||
/* XXX warn */ ;
|
||||
bits |= 4;
|
||||
text.Append((char)d);
|
||||
d = read();
|
||||
}
|
||||
else if (char.IsLetter((char)d)) {
|
||||
unread(d);
|
||||
return new Token(Token.INVALID, text.ToString(),
|
||||
"Invalid suffix \"" + (char)d +
|
||||
"\" on numeric constant");
|
||||
}
|
||||
else {
|
||||
unread(d);
|
||||
return new Token(Token.INTEGER,
|
||||
text.ToString(), (long)val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* We already chewed a zero, so empty is fine. */
|
||||
private Token number_octal() {
|
||||
StringBuilder text = new StringBuilder("0");
|
||||
int d = read();
|
||||
long val = 0;
|
||||
while (digit((char)d, 8) != -1) {
|
||||
val = (val << 3) + digit((char)d, 8);
|
||||
text.Append((char)d);
|
||||
d = read();
|
||||
}
|
||||
return _number(text, val, d);
|
||||
}
|
||||
|
||||
/* We do not know whether know the first digit is valid. */
|
||||
private Token number_hex(char x) {
|
||||
StringBuilder text = new StringBuilder("0");
|
||||
text.Append(x);
|
||||
int d = read();
|
||||
if (digit((char)d, 16) == -1) {
|
||||
unread(d);
|
||||
// error("Illegal hexadecimal constant " + (char)d);
|
||||
return new Token(Token.INVALID, text.ToString(),
|
||||
"Illegal hexadecimal digit " + (char)d +
|
||||
" after "+ text);
|
||||
}
|
||||
long val = 0;
|
||||
do {
|
||||
val = (val << 4) + digit((char)d, 16);
|
||||
text.Append((char)d);
|
||||
d = read();
|
||||
} while (digit((char)d, 16) != -1);
|
||||
return _number(text, val, d);
|
||||
}
|
||||
|
||||
/* We know we have at least one valid digit, but empty is not
|
||||
* fine. */
|
||||
/* XXX This needs a complete rewrite. */
|
||||
private Token number_decimal(int c) {
|
||||
StringBuilder text = new StringBuilder((char)c);
|
||||
int d = c;
|
||||
long val = 0;
|
||||
do {
|
||||
val = val * 10 + digit((char)d, 10);
|
||||
text.Append((char)d);
|
||||
d = read();
|
||||
} while (digit((char)d, 10) != -1);
|
||||
return _number(text, val, d);
|
||||
}
|
||||
|
||||
private Token identifier(int c) {
|
||||
StringBuilder text = new StringBuilder();
|
||||
int d;
|
||||
text.Append((char)c);
|
||||
for (;;) {
|
||||
d = read();
|
||||
if (isIdentifierIgnorable(d))
|
||||
;
|
||||
else if (isJavaIdentifierPart(d))
|
||||
text.Append((char)d);
|
||||
else
|
||||
break;
|
||||
}
|
||||
unread(d);
|
||||
return new Token(Token.IDENTIFIER, text.ToString());
|
||||
}
|
||||
|
||||
private Token whitespace(int c) {
|
||||
StringBuilder text = new StringBuilder();
|
||||
int d;
|
||||
text.Append((char)c);
|
||||
for (;;) {
|
||||
d = read();
|
||||
if (ppvalid && isLineSeparator(d)) /* XXX Ugly. */
|
||||
break;
|
||||
if (char.IsWhiteSpace((char)d))
|
||||
text.Append((char)d);
|
||||
else
|
||||
break;
|
||||
}
|
||||
unread(d);
|
||||
return new Token(Token.WHITESPACE, text.ToString());
|
||||
}
|
||||
|
||||
/* No token processed by cond() contains a newline. */
|
||||
private Token cond(char c, int yes, int no) {
|
||||
int d = read();
|
||||
if (c == d)
|
||||
return new Token(yes);
|
||||
unread(d);
|
||||
return new Token(no);
|
||||
}
|
||||
|
||||
public override Token token() {
|
||||
Token tok = null;
|
||||
|
||||
int _l = line;
|
||||
int _c = column;
|
||||
|
||||
int c = read();
|
||||
int d;
|
||||
|
||||
switch (c) {
|
||||
case '\n':
|
||||
if (ppvalid) {
|
||||
bol = true;
|
||||
if (include) {
|
||||
tok = new Token(Token.NL, _l, _c, "\n");
|
||||
}
|
||||
else {
|
||||
int nls = 0;
|
||||
do {
|
||||
nls++;
|
||||
d = read();
|
||||
} while (d == '\n');
|
||||
unread(d);
|
||||
char[] text = new char[nls];
|
||||
for (int i = 0; i < text.Length; i++)
|
||||
text[i] = '\n';
|
||||
// Skip the bol = false below.
|
||||
tok = new Token(Token.NL, _l, _c, new String(text));
|
||||
}
|
||||
if (DEBUG)
|
||||
System.Console.Error.WriteLine("lx: Returning NL: " + tok);
|
||||
return tok;
|
||||
}
|
||||
/* Let it be handled as whitespace. */
|
||||
break;
|
||||
|
||||
case '!':
|
||||
tok = cond('=', Token.NE, '!');
|
||||
break;
|
||||
|
||||
case '#':
|
||||
if (bol)
|
||||
tok = new Token(Token.HASH);
|
||||
else
|
||||
tok = cond('#', Token.PASTE, '#');
|
||||
break;
|
||||
|
||||
case '+':
|
||||
d = read();
|
||||
if (d == '+')
|
||||
tok = new Token(Token.INC);
|
||||
else if (d == '=')
|
||||
tok = new Token(Token.PLUS_EQ);
|
||||
else
|
||||
unread(d);
|
||||
break;
|
||||
case '-':
|
||||
d = read();
|
||||
if (d == '-')
|
||||
tok = new Token(Token.DEC);
|
||||
else if (d == '=')
|
||||
tok = new Token(Token.SUB_EQ);
|
||||
else if (d == '>')
|
||||
tok = new Token(Token.ARROW);
|
||||
else
|
||||
unread(d);
|
||||
break;
|
||||
|
||||
case '*':
|
||||
tok = cond('=', Token.MULT_EQ, '*');
|
||||
break;
|
||||
case '/':
|
||||
d = read();
|
||||
if (d == '*')
|
||||
tok = ccomment();
|
||||
else if (d == '/')
|
||||
tok = cppcomment();
|
||||
else if (d == '=')
|
||||
tok = new Token(Token.DIV_EQ);
|
||||
else
|
||||
unread(d);
|
||||
break;
|
||||
|
||||
case '%':
|
||||
d = read();
|
||||
if (d == '=')
|
||||
tok = new Token(Token.MOD_EQ);
|
||||
else if (digraphs && d == '>')
|
||||
tok = new Token('}'); // digraph
|
||||
else if (digraphs && d == ':') {
|
||||
bool paste = true;
|
||||
d = read();
|
||||
if (d != '%') {
|
||||
unread(d);
|
||||
tok = new Token('#'); // digraph
|
||||
paste = false;
|
||||
}
|
||||
d = read();
|
||||
if (d != ':') {
|
||||
unread(d); // Unread 2 chars here.
|
||||
unread('%');
|
||||
tok = new Token('#'); // digraph
|
||||
paste = false;
|
||||
}
|
||||
if(paste) {
|
||||
tok = new Token(Token.PASTE); // digraph
|
||||
}
|
||||
}
|
||||
else
|
||||
unread(d);
|
||||
break;
|
||||
|
||||
case ':':
|
||||
/* :: */
|
||||
d = read();
|
||||
if (digraphs && d == '>')
|
||||
tok = new Token(']'); // digraph
|
||||
else
|
||||
unread(d);
|
||||
break;
|
||||
|
||||
case '<':
|
||||
if (include) {
|
||||
tok = String('<', '>');
|
||||
}
|
||||
else {
|
||||
d = read();
|
||||
if (d == '=')
|
||||
tok = new Token(Token.LE);
|
||||
else if (d == '<')
|
||||
tok = cond('=', Token.LSH_EQ, Token.LSH);
|
||||
else if (digraphs && d == ':')
|
||||
tok = new Token('['); // digraph
|
||||
else if (digraphs && d == '%')
|
||||
tok = new Token('{'); // digraph
|
||||
else
|
||||
unread(d);
|
||||
}
|
||||
break;
|
||||
|
||||
case '=':
|
||||
tok = cond('=', Token.EQ, '=');
|
||||
break;
|
||||
|
||||
case '>':
|
||||
d = read();
|
||||
if (d == '=')
|
||||
tok = new Token(Token.GE);
|
||||
else if (d == '>')
|
||||
tok = cond('=', Token.RSH_EQ, Token.RSH);
|
||||
else
|
||||
unread(d);
|
||||
break;
|
||||
|
||||
case '^':
|
||||
tok = cond('=', Token.XOR_EQ, '^');
|
||||
break;
|
||||
|
||||
case '|':
|
||||
d = read();
|
||||
if (d == '=')
|
||||
tok = new Token(Token.OR_EQ);
|
||||
else if (d == '|')
|
||||
tok = cond('=', Token.LOR_EQ, Token.LOR);
|
||||
else
|
||||
unread(d);
|
||||
break;
|
||||
case '&':
|
||||
d = read();
|
||||
if (d == '&')
|
||||
tok = cond('=', Token.LAND_EQ, Token.LAND);
|
||||
else if (d == '=')
|
||||
tok = new Token(Token.AND_EQ);
|
||||
else
|
||||
unread(d);
|
||||
break;
|
||||
|
||||
case '.':
|
||||
d = read();
|
||||
if (d == '.')
|
||||
tok = cond('.', Token.ELLIPSIS, Token.RANGE);
|
||||
else
|
||||
unread(d);
|
||||
/* XXX decimal fraction */
|
||||
break;
|
||||
|
||||
case '0':
|
||||
/* octal or hex */
|
||||
d = read();
|
||||
if (d == 'x' || d == 'X')
|
||||
tok = number_hex((char)d);
|
||||
else {
|
||||
unread(d);
|
||||
tok = number_octal();
|
||||
}
|
||||
break;
|
||||
|
||||
case '\'':
|
||||
tok = character();
|
||||
break;
|
||||
|
||||
case '"':
|
||||
tok = String('"', '"');
|
||||
break;
|
||||
|
||||
case -1:
|
||||
close();
|
||||
tok = new Token(Token.EOF, _l, _c, "<eof>");
|
||||
break;
|
||||
}
|
||||
|
||||
if (tok == null) {
|
||||
if (char.IsWhiteSpace((char)c)) {
|
||||
tok = whitespace(c);
|
||||
}
|
||||
else if (char.IsDigit((char)c)) {
|
||||
tok = number_decimal(c);
|
||||
}
|
||||
else if (isJavaIdentifierStart(c)) {
|
||||
tok = identifier(c);
|
||||
}
|
||||
else {
|
||||
tok = new Token(c);
|
||||
}
|
||||
}
|
||||
|
||||
if (bol) {
|
||||
switch (tok.getType()) {
|
||||
case Token.WHITESPACE:
|
||||
case Token.CCOMMENT:
|
||||
break;
|
||||
default:
|
||||
bol = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
tok.setLocation(_l, _c);
|
||||
if (DEBUG)
|
||||
System.Console.WriteLine("lx: Returning " + tok);
|
||||
// (new Exception("here")).printStackTrace(System.out);
|
||||
return tok;
|
||||
}
|
||||
|
||||
public override void close()
|
||||
{
|
||||
if(reader != null) {
|
||||
reader.close();
|
||||
reader = null;
|
||||
}
|
||||
base.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,208 @@
|
|||
/*
|
||||
* Anarres C Preprocessor
|
||||
* Copyright (c) 2007-2008, Shevek
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace CppNet
|
||||
{
|
||||
/**
|
||||
* A macro object.
|
||||
*
|
||||
* This encapsulates a name, an argument count, and a token stream
|
||||
* for replacement. The replacement token stream may contain the
|
||||
* extra tokens {@link Token#M_ARG} and {@link Token#M_STRING}.
|
||||
*/
|
||||
public class Macro
|
||||
{
|
||||
private Source source;
|
||||
private String name;
|
||||
/* It's an explicit decision to keep these around here. We don't
|
||||
* need to; the argument token type is M_ARG and the value
|
||||
* is the index. The strings themselves are only used in
|
||||
* stringification of the macro, for debugging. */
|
||||
private List<String> args;
|
||||
private bool variadic;
|
||||
private List<Token> tokens;
|
||||
|
||||
public Macro(Source source, String name)
|
||||
{
|
||||
this.source = source;
|
||||
this.name = name;
|
||||
this.args = null;
|
||||
this.variadic = false;
|
||||
this.tokens = new List<Token>();
|
||||
}
|
||||
|
||||
public Macro(String name)
|
||||
: this(null, name)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Source from which this macro was parsed.
|
||||
*/
|
||||
public void setSource(Source s)
|
||||
{
|
||||
this.source = s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Source from which this macro was parsed.
|
||||
*
|
||||
* This method may return null if the macro was not parsed
|
||||
* from a regular file.
|
||||
*/
|
||||
public Source getSource()
|
||||
{
|
||||
return source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this macro.
|
||||
*/
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the arguments to this macro.
|
||||
*/
|
||||
public void setArgs(List<String> args)
|
||||
{
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this is a function-like macro.
|
||||
*/
|
||||
public bool isFunctionLike()
|
||||
{
|
||||
return args != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of arguments to this macro.
|
||||
*/
|
||||
public int getArgs()
|
||||
{
|
||||
return args.Count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the variadic flag on this Macro.
|
||||
*/
|
||||
public void setVariadic(bool b)
|
||||
{
|
||||
this.variadic = b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this is a variadic function-like macro.
|
||||
*/
|
||||
public bool isVariadic()
|
||||
{
|
||||
return variadic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a token to the expansion of this macro.
|
||||
*/
|
||||
public void addToken(Token tok)
|
||||
{
|
||||
this.tokens.Add(tok);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a "paste" operator to the expansion of this macro.
|
||||
*
|
||||
* A paste operator causes the next token added to be pasted
|
||||
* to the previous token when the macro is expanded.
|
||||
* It is an error for a macro to end with a paste token.
|
||||
*/
|
||||
public void addPaste(Token tok)
|
||||
{
|
||||
/*
|
||||
* Given: tok0 ## tok1
|
||||
* We generate: M_PASTE, tok0, tok1
|
||||
* This extends as per a stack language:
|
||||
* tok0 ## tok1 ## tok2 ->
|
||||
* M_PASTE, tok0, M_PASTE, tok1, tok2
|
||||
*/
|
||||
this.tokens.Insert(tokens.Count - 1, tok);
|
||||
}
|
||||
|
||||
internal List<Token> getTokens()
|
||||
{
|
||||
return tokens;
|
||||
}
|
||||
|
||||
/* Paste tokens are inserted before the first of the two pasted
|
||||
* tokens, so it's a kind of bytecode notation. This method
|
||||
* swaps them around again. We know that there will never be two
|
||||
* sequential paste tokens, so a bool is sufficient. */
|
||||
public String getText() {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
bool paste = false;
|
||||
for (int i = 0; i < tokens.Count; i++) {
|
||||
Token tok = tokens[i];
|
||||
if (tok.getType() == Token.M_PASTE) {
|
||||
System.Diagnostics.Debug.Assert(paste == false, "Two sequential pastes.");
|
||||
paste = true;
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
buf.Append(tok.getText());
|
||||
}
|
||||
if (paste) {
|
||||
buf.Append(" #" + "# ");
|
||||
paste = false;
|
||||
}
|
||||
// buf.Append(tokens.get(i));
|
||||
}
|
||||
return buf.ToString();
|
||||
}
|
||||
|
||||
override public String ToString()
|
||||
{
|
||||
StringBuilder buf = new StringBuilder(name);
|
||||
if(args != null) {
|
||||
buf.Append('(');
|
||||
bool first = true;
|
||||
foreach(String str in args) {
|
||||
if(!first) {
|
||||
buf.Append(", ");
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
buf.Append(str);
|
||||
}
|
||||
if(isVariadic()) {
|
||||
buf.Append("...");
|
||||
}
|
||||
|
||||
buf.Append(')');
|
||||
}
|
||||
if(tokens.Count != 0) {
|
||||
buf.Append(" => ").Append(getText());
|
||||
}
|
||||
return buf.ToString();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,197 @@
|
|||
/*
|
||||
* Anarres C Preprocessor
|
||||
* Copyright (c) 2007-2008, Shevek
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
using boolean = System.Boolean;
|
||||
using Debug = System.Diagnostics.Debug;
|
||||
|
||||
namespace CppNet {
|
||||
|
||||
/* This source should always be active, since we don't expand macros
|
||||
* in any inactive context. */
|
||||
internal class MacroTokenSource : Source {
|
||||
private Macro macro;
|
||||
private Iterator<Token> tokens; /* Pointer into the macro. */
|
||||
private List<Argument> args; /* { unexpanded, expanded } */
|
||||
private Iterator<Token> arg; /* "current expansion" */
|
||||
|
||||
internal MacroTokenSource(Macro m, List<Argument> args) {
|
||||
this.macro = m;
|
||||
this.tokens = m.getTokens().iterator();
|
||||
this.args = args;
|
||||
this.arg = null;
|
||||
}
|
||||
|
||||
override internal boolean isExpanding(Macro m) {
|
||||
/* When we are expanding an arg, 'this' macro is not
|
||||
* being expanded, and thus we may re-expand it. */
|
||||
if (/* XXX this.arg == null && */ this.macro == m)
|
||||
return true;
|
||||
return base.isExpanding(m);
|
||||
}
|
||||
|
||||
/* XXX Called from Preprocessor [ugly]. */
|
||||
internal static void escape(StringBuilder buf, string cs) {
|
||||
for (int i = 0; i < cs.length(); i++) {
|
||||
char c = cs.charAt(i);
|
||||
switch (c) {
|
||||
case '\\':
|
||||
buf.append("\\\\");
|
||||
break;
|
||||
case '"':
|
||||
buf.append("\\\"");
|
||||
break;
|
||||
case '\n':
|
||||
buf.append("\\n");
|
||||
break;
|
||||
case '\r':
|
||||
buf.append("\\r");
|
||||
break;
|
||||
default:
|
||||
buf.append(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void concat(StringBuilder buf, Argument arg) {
|
||||
Iterator<Token> it = arg.iterator();
|
||||
while (it.hasNext()) {
|
||||
Token tok = it.next();
|
||||
buf.append(tok.getText());
|
||||
}
|
||||
}
|
||||
|
||||
private Token stringify(Token pos, Argument arg) {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
concat(buf, arg);
|
||||
// System.out.println("Concat: " + arg + " -> " + buf);
|
||||
StringBuilder str = new StringBuilder("\"");
|
||||
escape(str, buf.ToString());
|
||||
str.append("\"");
|
||||
// System.out.println("Escape: " + buf + " -> " + str);
|
||||
return new Token(Token.STRING,
|
||||
pos.getLine(), pos.getColumn(),
|
||||
str.toString(), buf.toString());
|
||||
}
|
||||
|
||||
|
||||
/* At this point, we have consumed the first M_PASTE.
|
||||
* @see Macro#addPaste(Token) */
|
||||
private void paste(Token ptok) {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
Token err = null;
|
||||
/* We know here that arg is null or expired,
|
||||
* since we cannot paste an expanded arg. */
|
||||
|
||||
int count = 2;
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (!tokens.hasNext()) {
|
||||
/* XXX This one really should throw. */
|
||||
error(ptok.getLine(), ptok.getColumn(),
|
||||
"Paste at end of expansion");
|
||||
buf.append(' ').append(ptok.getText());
|
||||
break;
|
||||
}
|
||||
Token tok = tokens.next();
|
||||
// System.out.println("Paste " + tok);
|
||||
switch (tok.getType()) {
|
||||
case Token.M_PASTE:
|
||||
/* One extra to paste, plus one because the
|
||||
* paste token didn't count. */
|
||||
count += 2;
|
||||
ptok = tok;
|
||||
break;
|
||||
case Token.M_ARG:
|
||||
int idx = (int)tok.getValue();
|
||||
concat(buf, args.get(idx));
|
||||
break;
|
||||
/* XXX Test this. */
|
||||
case Token.CCOMMENT:
|
||||
case Token.CPPCOMMENT:
|
||||
break;
|
||||
default:
|
||||
buf.append(tok.getText());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Push and re-lex. */
|
||||
/*
|
||||
StringBuilder src = new StringBuilder();
|
||||
escape(src, buf);
|
||||
StringLexerSource sl = new StringLexerSource(src.toString());
|
||||
*/
|
||||
StringLexerSource sl = new StringLexerSource(buf.toString());
|
||||
|
||||
/* XXX Check that concatenation produces a valid token. */
|
||||
|
||||
arg = new SourceIterator(sl);
|
||||
}
|
||||
|
||||
override public Token token() {
|
||||
for (;;) {
|
||||
/* Deal with lexed tokens first. */
|
||||
|
||||
if (arg != null) {
|
||||
if (arg.hasNext()) {
|
||||
Token tok2 = arg.next();
|
||||
/* XXX PASTE -> INVALID. */
|
||||
Debug.Assert(tok2.getType() != Token.M_PASTE,
|
||||
"Unexpected paste token");
|
||||
return tok2;
|
||||
}
|
||||
arg = null;
|
||||
}
|
||||
|
||||
if (!tokens.hasNext())
|
||||
return new Token(Token.EOF, -1, -1, ""); /* End of macro. */
|
||||
Token tok = tokens.next();
|
||||
int idx;
|
||||
switch (tok.getType()) {
|
||||
case Token.M_STRING:
|
||||
/* Use the nonexpanded arg. */
|
||||
idx = (int)tok.getValue();
|
||||
return stringify(tok, args.get(idx));
|
||||
case Token.M_ARG:
|
||||
/* Expand the arg. */
|
||||
idx = (int)tok.getValue();
|
||||
// System.out.println("Pushing arg " + args.get(idx));
|
||||
arg = args.get(idx).expansion();
|
||||
break;
|
||||
case Token.M_PASTE:
|
||||
paste(tok);
|
||||
break;
|
||||
default:
|
||||
return tok;
|
||||
}
|
||||
} /* for */
|
||||
}
|
||||
|
||||
|
||||
override public String ToString() {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.Append("expansion of ").Append(macro.getName());
|
||||
Source parent = getParent();
|
||||
if (parent != null)
|
||||
buf.Append(" in ").Append(parent);
|
||||
return buf.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* Anarres C Preprocessor
|
||||
* Copyright (c) 2007-2008, Shevek
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
|
||||
namespace CppNet {
|
||||
|
||||
/**
|
||||
* A handler for preprocessor events, primarily errors and warnings.
|
||||
*
|
||||
* If no PreprocessorListener is installed in a Preprocessor, all
|
||||
* error and warning events will throw an exception. Installing a
|
||||
* listener allows more intelligent handling of these events.
|
||||
*/
|
||||
public class PreprocessorListener {
|
||||
|
||||
private int errors;
|
||||
private int warnings;
|
||||
|
||||
public PreprocessorListener() {
|
||||
clear();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
errors = 0;
|
||||
warnings = 0;
|
||||
}
|
||||
|
||||
public int getErrors() {
|
||||
return errors;
|
||||
}
|
||||
|
||||
public int getWarnings() {
|
||||
return warnings;
|
||||
}
|
||||
|
||||
protected void print(String msg) {
|
||||
System.Console.Error.WriteLine(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a warning.
|
||||
*
|
||||
* The behaviour of this method is defined by the
|
||||
* implementation. It may simply record the error message, or
|
||||
* it may throw an exception.
|
||||
*/
|
||||
public void handleWarning(Source source, int line, int column,
|
||||
String msg) {
|
||||
warnings++;
|
||||
print(source.getName() + ":" + line + ":" + column +
|
||||
": warning: " + msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles an error.
|
||||
*
|
||||
* The behaviour of this method is defined by the
|
||||
* implementation. It may simply record the error message, or
|
||||
* it may throw an exception.
|
||||
*/
|
||||
public void handleError(Source source, int line, int column,
|
||||
String msg) {
|
||||
errors++;
|
||||
print(source.getName() + ":" + line + ":" + column +
|
||||
": error: " + msg);
|
||||
}
|
||||
|
||||
public void handleSourceChange(Source source, String ev) {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("CppNet")]
|
||||
[assembly: AssemblyProduct("CppNet")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("a972fb74-7a43-4c22-a381-2b8f0f5d7d2c")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
@ -0,0 +1,298 @@
|
|||
/*
|
||||
* Anarres C Preprocessor
|
||||
* Copyright (c) 2007-2008, Shevek
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using boolean = System.Boolean;
|
||||
|
||||
|
||||
namespace CppNet
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* An input to the Preprocessor.
|
||||
*
|
||||
* Inputs may come from Files, Strings or other sources. The
|
||||
* preprocessor maintains a stack of Sources. Operations such as
|
||||
* file inclusion or token pasting will push a new source onto
|
||||
* the Preprocessor stack. Sources pop from the stack when they
|
||||
* are exhausted; this may be transparent or explicit.
|
||||
*
|
||||
* BUG: Error messages are not handled properly.
|
||||
*/
|
||||
public abstract class Source : Iterable<Token>, Closeable
|
||||
{
|
||||
private Source parent;
|
||||
private boolean autopop;
|
||||
private PreprocessorListener listener;
|
||||
private boolean active;
|
||||
private boolean werror;
|
||||
|
||||
/* LineNumberReader */
|
||||
|
||||
/*
|
||||
// We can't do this, since we would lose the LexerException
|
||||
private class Itr implements Iterator {
|
||||
private Token next = null;
|
||||
private void advance() {
|
||||
try {
|
||||
if (next != null)
|
||||
next = token();
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Failed to advance token iterator: " +
|
||||
e.getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
public boolean hasNext() {
|
||||
return next.getType() != EOF;
|
||||
}
|
||||
public Token next() {
|
||||
advance();
|
||||
Token t = next;
|
||||
next = null;
|
||||
return t;
|
||||
}
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException(
|
||||
"Cannot remove tokens from a Source."
|
||||
);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
public Source()
|
||||
{
|
||||
this.parent = null;
|
||||
this.autopop = false;
|
||||
this.listener = null;
|
||||
this.active = true;
|
||||
this.werror = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the parent source of this source.
|
||||
*
|
||||
* Sources form a singly linked list.
|
||||
*/
|
||||
internal void setParent(Source parent, boolean autopop)
|
||||
{
|
||||
this.parent = parent;
|
||||
this.autopop = autopop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parent source of this source.
|
||||
*
|
||||
* Sources form a singly linked list.
|
||||
*/
|
||||
internal Source getParent()
|
||||
{
|
||||
return parent;
|
||||
}
|
||||
|
||||
// @OverrideMustInvoke
|
||||
internal virtual void init(Preprocessor pp)
|
||||
{
|
||||
setListener(pp.getListener());
|
||||
this.werror = pp.getWarnings().HasFlag(Warning.ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the listener for this Source.
|
||||
*
|
||||
* Normally this is set by the Preprocessor when a Source is
|
||||
* used, but if you are using a Source as a standalone object,
|
||||
* you may wish to call this.
|
||||
*/
|
||||
public void setListener(PreprocessorListener pl)
|
||||
{
|
||||
this.listener = pl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the File currently being lexed.
|
||||
*
|
||||
* If this Source is not a {@link FileLexerSource}, then
|
||||
* it will ask the parent Source, and so forth recursively.
|
||||
* If no Source on the stack is a FileLexerSource, returns null.
|
||||
*/
|
||||
internal virtual String getPath()
|
||||
{
|
||||
Source parent = getParent();
|
||||
if(parent != null)
|
||||
return parent.getPath();
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the human-readable name of the current Source.
|
||||
*/
|
||||
internal virtual String getName()
|
||||
{
|
||||
Source parent = getParent();
|
||||
if(parent != null)
|
||||
return parent.getName();
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current line number within this Source.
|
||||
*/
|
||||
public virtual int getLine()
|
||||
{
|
||||
Source parent = getParent();
|
||||
if(parent == null)
|
||||
return 0;
|
||||
return parent.getLine();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current column number within this Source.
|
||||
*/
|
||||
public virtual int getColumn()
|
||||
{
|
||||
Source parent = getParent();
|
||||
if(parent == null)
|
||||
return 0;
|
||||
return parent.getColumn();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this Source is expanding the given macro.
|
||||
*
|
||||
* This is used to prevent macro recursion.
|
||||
*/
|
||||
internal virtual boolean isExpanding(Macro m)
|
||||
{
|
||||
Source parent = getParent();
|
||||
if(parent != null)
|
||||
return parent.isExpanding(m);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this Source should be transparently popped
|
||||
* from the input stack.
|
||||
*
|
||||
* Examples of such sources are macro expansions.
|
||||
*/
|
||||
internal boolean isAutopop()
|
||||
{
|
||||
return autopop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this source has line numbers.
|
||||
*/
|
||||
internal virtual boolean isNumbered()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* This is an incredibly lazy way of disabling warnings when
|
||||
* the source is not active. */
|
||||
internal void setActive(boolean b)
|
||||
{
|
||||
this.active = b;
|
||||
}
|
||||
|
||||
internal boolean isActive()
|
||||
{
|
||||
return active;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next Token parsed from this input stream.
|
||||
*
|
||||
* @see Token
|
||||
*/
|
||||
public abstract Token token();
|
||||
|
||||
/**
|
||||
* Returns a token iterator for this Source.
|
||||
*/
|
||||
public Iterator<Token> iterator()
|
||||
{
|
||||
return new SourceIterator(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips tokens until the end of line.
|
||||
*
|
||||
* @param white true if only whitespace is permitted on the
|
||||
* remainder of the line.
|
||||
* @return the NL token.
|
||||
*/
|
||||
public Token skipline(boolean white)
|
||||
{
|
||||
for(; ; ) {
|
||||
Token tok = token();
|
||||
switch(tok.getType()) {
|
||||
case Token.EOF:
|
||||
/* There ought to be a newline before EOF.
|
||||
* At least, in any skipline context. */
|
||||
/* XXX Are we sure about this? */
|
||||
warning(tok.getLine(), tok.getColumn(),
|
||||
"No newline before end of file");
|
||||
return new Token(Token.NL,
|
||||
tok.getLine(), tok.getColumn(),
|
||||
"\n");
|
||||
// return tok;
|
||||
case Token.NL:
|
||||
/* This may contain one or more newlines. */
|
||||
return tok;
|
||||
case Token.CCOMMENT:
|
||||
case Token.CPPCOMMENT:
|
||||
case Token.WHITESPACE:
|
||||
break;
|
||||
default:
|
||||
/* XXX Check white, if required. */
|
||||
if(white)
|
||||
warning(tok.getLine(), tok.getColumn(),
|
||||
"Unexpected nonwhite token");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void error(int line, int column, String msg)
|
||||
{
|
||||
if(listener != null)
|
||||
listener.handleError(this, line, column, msg);
|
||||
else
|
||||
throw new LexerException("Error at " + line + ":" + column + ": " + msg);
|
||||
}
|
||||
|
||||
protected void warning(int line, int column, String msg)
|
||||
{
|
||||
if(werror)
|
||||
error(line, column, msg);
|
||||
else if(listener != null)
|
||||
listener.handleWarning(this, line, column, msg);
|
||||
else
|
||||
throw new LexerException("Warning at " + line + ":" + column + ": " + msg);
|
||||
}
|
||||
|
||||
public virtual void close()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Anarres C Preprocessor
|
||||
* Copyright (c) 2007-2008, Shevek
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
using boolean = System.Boolean;
|
||||
|
||||
namespace CppNet
|
||||
{
|
||||
|
||||
/**
|
||||
* An Iterator for {@link Source Sources},
|
||||
* returning {@link Token Tokens}.
|
||||
*/
|
||||
public class SourceIterator : Iterator<Token>
|
||||
{
|
||||
private Source source;
|
||||
private Token tok;
|
||||
|
||||
public SourceIterator(Source s)
|
||||
{
|
||||
this.source = s;
|
||||
this.tok = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rethrows IOException inside IllegalStateException.
|
||||
*/
|
||||
private void advance()
|
||||
{
|
||||
try {
|
||||
if(tok == null)
|
||||
tok = source.token();
|
||||
} catch(LexerException e) {
|
||||
throw new IllegalStateException(e);
|
||||
} catch(IOException e) {
|
||||
throw new ApplicationException("",e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the enclosed Source has more tokens.
|
||||
*
|
||||
* The EOF token is never returned by the iterator.
|
||||
* @throws IllegalStateException if the Source
|
||||
* throws a LexerException or IOException
|
||||
*/
|
||||
public boolean hasNext()
|
||||
{
|
||||
advance();
|
||||
return tok.getType() != Token.EOF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next token from the enclosed Source.
|
||||
*
|
||||
* The EOF token is never returned by the iterator.
|
||||
* @throws IllegalStateException if the Source
|
||||
* throws a LexerException or IOException
|
||||
*/
|
||||
public Token next()
|
||||
{
|
||||
if(!hasNext())
|
||||
throw new ArgumentOutOfRangeException();
|
||||
Token t = this.tok;
|
||||
this.tok = null;
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Not supported.
|
||||
*
|
||||
* @throws UnsupportedOperationException.
|
||||
*/
|
||||
public void remove()
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Anarres C Preprocessor
|
||||
* Copyright (c) 2007-2008, Shevek
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
|
||||
namespace CppNet
|
||||
{
|
||||
|
||||
/* pp */
|
||||
class State
|
||||
{
|
||||
bool _parent;
|
||||
bool _active;
|
||||
bool _sawElse;
|
||||
|
||||
/* pp */
|
||||
internal State()
|
||||
{
|
||||
this._parent = true;
|
||||
this._active = true;
|
||||
this._sawElse = false;
|
||||
}
|
||||
|
||||
/* pp */
|
||||
internal State(State parent)
|
||||
{
|
||||
this._parent = parent.isParentActive() && parent.isActive();
|
||||
this._active = true;
|
||||
this._sawElse = false;
|
||||
}
|
||||
|
||||
/* Required for #elif */
|
||||
/* pp */
|
||||
internal void setParentActive(bool b)
|
||||
{
|
||||
this._parent = b;
|
||||
}
|
||||
|
||||
/* pp */
|
||||
internal bool isParentActive()
|
||||
{
|
||||
return _parent;
|
||||
}
|
||||
|
||||
/* pp */
|
||||
internal void setActive(bool b)
|
||||
{
|
||||
this._active = b;
|
||||
}
|
||||
|
||||
/* pp */
|
||||
internal bool isActive()
|
||||
{
|
||||
return _active;
|
||||
}
|
||||
|
||||
/* pp */
|
||||
internal void setSawElse()
|
||||
{
|
||||
_sawElse = true;
|
||||
}
|
||||
|
||||
/* pp */
|
||||
internal bool sawElse()
|
||||
{
|
||||
return _sawElse;
|
||||
}
|
||||
|
||||
public override String ToString()
|
||||
{
|
||||
return "parent=" + _parent +
|
||||
", active=" + _active +
|
||||
", sawelse=" + _sawElse;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Anarres C Preprocessor
|
||||
* Copyright (c) 2007-2008, Shevek
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace CppNet {
|
||||
|
||||
/**
|
||||
* A Source for lexing a String.
|
||||
*
|
||||
* This class is used by token pasting, but can be used by user
|
||||
* code.
|
||||
*/
|
||||
public class StringLexerSource : LexerSource {
|
||||
|
||||
/**
|
||||
* Creates a new Source for lexing the given String.
|
||||
*
|
||||
* @param ppvalid true if preprocessor directives are to be
|
||||
* honoured within the string.
|
||||
*/
|
||||
public StringLexerSource(String str, bool ppvalid) :
|
||||
base(new StringReader(str), ppvalid) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Source for lexing the given String.
|
||||
*
|
||||
* By default, preprocessor directives are not honoured within
|
||||
* the string.
|
||||
*/
|
||||
public StringLexerSource(String str) :
|
||||
this(str, false) {
|
||||
}
|
||||
|
||||
override public String ToString() {
|
||||
return "string literal";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,353 @@
|
|||
/*
|
||||
* Anarres C Preprocessor
|
||||
* Copyright (c) 2007-2008, Shevek
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace CppNet {
|
||||
|
||||
/**
|
||||
* A Preprocessor token.
|
||||
*
|
||||
* @see Preprocessor
|
||||
*/
|
||||
public sealed class Token
|
||||
{
|
||||
// public const int EOF = -1;
|
||||
|
||||
private int type;
|
||||
private int line;
|
||||
private int column;
|
||||
private Object value;
|
||||
private String text;
|
||||
|
||||
public Token(int type, int line, int column,
|
||||
String text, Object value)
|
||||
{
|
||||
this.type = type;
|
||||
this.line = line;
|
||||
this.column = column;
|
||||
this.text = text;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public Token(int type, int line, int column, String text) :
|
||||
this(type, line, column, text, null)
|
||||
{
|
||||
}
|
||||
|
||||
/* pp */
|
||||
internal Token(int type, String text, Object value) :
|
||||
this(type, -1, -1, text, value)
|
||||
{
|
||||
}
|
||||
|
||||
/* pp */
|
||||
internal Token(int type, String text) :
|
||||
this(type, text, null)
|
||||
{
|
||||
}
|
||||
|
||||
/* pp */
|
||||
internal Token(int type) :
|
||||
this(type, type < _TOKENS ? texts[type] : "TOK" + type)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the semantic type of this token.
|
||||
*/
|
||||
public int getType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
internal void setLocation(int line, int column)
|
||||
{
|
||||
this.line = line;
|
||||
this.column = column;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the line at which this token started.
|
||||
*
|
||||
* Lines are numbered from zero.
|
||||
*/
|
||||
public int getLine()
|
||||
{
|
||||
return line;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the column at which this token started.
|
||||
*
|
||||
* Columns are numbered from zero.
|
||||
*/
|
||||
public int getColumn()
|
||||
{
|
||||
return column;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the original or generated text of this token.
|
||||
*
|
||||
* This is distinct from the semantic value of the token.
|
||||
*
|
||||
* @see #getValue()
|
||||
*/
|
||||
public String getText()
|
||||
{
|
||||
return text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the semantic value of this token.
|
||||
*
|
||||
* For strings, this is the parsed String.
|
||||
* For integers, this is an Integer object.
|
||||
* For other token types, as appropriate.
|
||||
*
|
||||
* @see #getText()
|
||||
*/
|
||||
public Object getValue()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a description of this token, for debugging purposes.
|
||||
*/
|
||||
public String ToString()
|
||||
{
|
||||
StringBuilder buf = new StringBuilder();
|
||||
|
||||
buf.Append('[').Append(getTokenName(type));
|
||||
if(line != -1) {
|
||||
buf.Append('@').Append(line);
|
||||
if(column != -1)
|
||||
buf.Append(',').Append(column);
|
||||
}
|
||||
buf.Append("]:");
|
||||
if(text != null)
|
||||
buf.Append('"').Append(text).Append('"');
|
||||
else if(type > 3 && type < 256)
|
||||
buf.Append((char)type);
|
||||
else
|
||||
buf.Append('<').Append(type).Append('>');
|
||||
if(value != null)
|
||||
buf.Append('=').Append(value);
|
||||
return buf.ToString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the descriptive name of the given token type.
|
||||
*
|
||||
* This is mostly used for stringification and debugging.
|
||||
*/
|
||||
public static String getTokenName(int type)
|
||||
{
|
||||
if(type < 0)
|
||||
return "Invalid" + type;
|
||||
if(type >= names.Length)
|
||||
return "Invalid" + type;
|
||||
if(names[type] == null)
|
||||
return "Unknown" + type;
|
||||
return names[type];
|
||||
}
|
||||
|
||||
/** The token type AND_EQ. */
|
||||
public const int AND_EQ = 257;
|
||||
/** The token type ARROW. */
|
||||
public const int ARROW = 258;
|
||||
/** The token type CHARACTER. */
|
||||
public const int CHARACTER = 259;
|
||||
/** The token type CCOMMENT. */
|
||||
public const int CCOMMENT = 260;
|
||||
/** The token type CPPCOMMENT. */
|
||||
public const int CPPCOMMENT = 261;
|
||||
/** The token type DEC. */
|
||||
public const int DEC = 262;
|
||||
/** The token type DIV_EQ. */
|
||||
public const int DIV_EQ = 263;
|
||||
/** The token type ELLIPSIS. */
|
||||
public const int ELLIPSIS = 264;
|
||||
/** The token type EOF. */
|
||||
public const int EOF = 265;
|
||||
/** The token type EQ. */
|
||||
public const int EQ = 266;
|
||||
/** The token type GE. */
|
||||
public const int GE = 267;
|
||||
/** The token type HASH. */
|
||||
public const int HASH = 268;
|
||||
/** The token type HEADER. */
|
||||
public const int HEADER = 269;
|
||||
/** The token type IDENTIFIER. */
|
||||
public const int IDENTIFIER = 270;
|
||||
/** The token type INC. */
|
||||
public const int INC = 271;
|
||||
/** The token type INTEGER. */
|
||||
public const int INTEGER = 272;
|
||||
/** The token type LAND. */
|
||||
public const int LAND = 273;
|
||||
/** The token type LAND_EQ. */
|
||||
public const int LAND_EQ = 274;
|
||||
/** The token type LE. */
|
||||
public const int LE = 275;
|
||||
/** The token type LITERAL. */
|
||||
public const int LITERAL = 276;
|
||||
/** The token type LOR. */
|
||||
public const int LOR = 277;
|
||||
/** The token type LOR_EQ. */
|
||||
public const int LOR_EQ = 278;
|
||||
/** The token type LSH. */
|
||||
public const int LSH = 279;
|
||||
/** The token type LSH_EQ. */
|
||||
public const int LSH_EQ = 280;
|
||||
/** The token type MOD_EQ. */
|
||||
public const int MOD_EQ = 281;
|
||||
/** The token type MULT_EQ. */
|
||||
public const int MULT_EQ = 282;
|
||||
/** The token type NE. */
|
||||
public const int NE = 283;
|
||||
/** The token type NL. */
|
||||
public const int NL = 284;
|
||||
/** The token type OR_EQ. */
|
||||
public const int OR_EQ = 285;
|
||||
/** The token type PASTE. */
|
||||
public const int PASTE = 286;
|
||||
/** The token type PLUS_EQ. */
|
||||
public const int PLUS_EQ = 287;
|
||||
/** The token type RANGE. */
|
||||
public const int RANGE = 288;
|
||||
/** The token type RSH. */
|
||||
public const int RSH = 289;
|
||||
/** The token type RSH_EQ. */
|
||||
public const int RSH_EQ = 290;
|
||||
/** The token type STRING. */
|
||||
public const int STRING = 291;
|
||||
/** The token type SUB_EQ. */
|
||||
public const int SUB_EQ = 292;
|
||||
/** The token type WHITESPACE. */
|
||||
public const int WHITESPACE = 293;
|
||||
/** The token type XOR_EQ. */
|
||||
public const int XOR_EQ = 294;
|
||||
/** The token type M_ARG. */
|
||||
public const int M_ARG = 295;
|
||||
/** The token type M_PASTE. */
|
||||
public const int M_PASTE = 296;
|
||||
/** The token type M_STRING. */
|
||||
public const int M_STRING = 297;
|
||||
/** The token type P_LINE. */
|
||||
public const int P_LINE = 298;
|
||||
/** The token type INVALID. */
|
||||
public const int INVALID = 299;
|
||||
/**
|
||||
* The number of possible semantic token types.
|
||||
*
|
||||
* Please note that not all token types below 255 are used.
|
||||
*/
|
||||
public const int _TOKENS = 300;
|
||||
|
||||
/** The position-less space token. */
|
||||
/* pp */
|
||||
public static readonly Token space = new Token(WHITESPACE, -1, -1, " ");
|
||||
|
||||
private static readonly String[] names = new String[_TOKENS];
|
||||
private static readonly String[] texts = new String[_TOKENS];
|
||||
static Token()
|
||||
{
|
||||
for(int i = 0; i < 255; i++) {
|
||||
texts[i] = ((char)i).ToString();
|
||||
names[i] = texts[i];
|
||||
}
|
||||
|
||||
texts[AND_EQ] = "&=";
|
||||
texts[ARROW] = "->";
|
||||
texts[DEC] = "--";
|
||||
texts[DIV_EQ] = "/=";
|
||||
texts[ELLIPSIS] = "...";
|
||||
texts[EQ] = "==";
|
||||
texts[GE] = ">=";
|
||||
texts[HASH] = "#";
|
||||
texts[INC] = "++";
|
||||
texts[LAND] = "&&";
|
||||
texts[LAND_EQ] = "&&=";
|
||||
texts[LE] = "<=";
|
||||
texts[LOR] = "||";
|
||||
texts[LOR_EQ] = "||=";
|
||||
texts[LSH] = "<<";
|
||||
texts[LSH_EQ] = "<<=";
|
||||
texts[MOD_EQ] = "%=";
|
||||
texts[MULT_EQ] = "*=";
|
||||
texts[NE] = "!=";
|
||||
texts[NL] = "\n";
|
||||
texts[OR_EQ] = "|=";
|
||||
/* We have to split the two hashes or Velocity eats them. */
|
||||
texts[PASTE] = "#" + "#";
|
||||
texts[PLUS_EQ] = "+=";
|
||||
texts[RANGE] = "..";
|
||||
texts[RSH] = ">>";
|
||||
texts[RSH_EQ] = ">>=";
|
||||
texts[SUB_EQ] = "-=";
|
||||
texts[XOR_EQ] = "^=";
|
||||
|
||||
names[AND_EQ] = "AND_EQ";
|
||||
names[ARROW] = "ARROW";
|
||||
names[CHARACTER] = "CHARACTER";
|
||||
names[CCOMMENT] = "CCOMMENT";
|
||||
names[CPPCOMMENT] = "CPPCOMMENT";
|
||||
names[DEC] = "DEC";
|
||||
names[DIV_EQ] = "DIV_EQ";
|
||||
names[ELLIPSIS] = "ELLIPSIS";
|
||||
names[EOF] = "EOF";
|
||||
names[EQ] = "EQ";
|
||||
names[GE] = "GE";
|
||||
names[HASH] = "HASH";
|
||||
names[HEADER] = "HEADER";
|
||||
names[IDENTIFIER] = "IDENTIFIER";
|
||||
names[INC] = "INC";
|
||||
names[INTEGER] = "INTEGER";
|
||||
names[LAND] = "LAND";
|
||||
names[LAND_EQ] = "LAND_EQ";
|
||||
names[LE] = "LE";
|
||||
names[LITERAL] = "LITERAL";
|
||||
names[LOR] = "LOR";
|
||||
names[LOR_EQ] = "LOR_EQ";
|
||||
names[LSH] = "LSH";
|
||||
names[LSH_EQ] = "LSH_EQ";
|
||||
names[MOD_EQ] = "MOD_EQ";
|
||||
names[MULT_EQ] = "MULT_EQ";
|
||||
names[NE] = "NE";
|
||||
names[NL] = "NL";
|
||||
names[OR_EQ] = "OR_EQ";
|
||||
names[PASTE] = "PASTE";
|
||||
names[PLUS_EQ] = "PLUS_EQ";
|
||||
names[RANGE] = "RANGE";
|
||||
names[RSH] = "RSH";
|
||||
names[RSH_EQ] = "RSH_EQ";
|
||||
names[STRING] = "STRING";
|
||||
names[SUB_EQ] = "SUB_EQ";
|
||||
names[WHITESPACE] = "WHITESPACE";
|
||||
names[XOR_EQ] = "XOR_EQ";
|
||||
names[M_ARG] = "M_ARG";
|
||||
names[M_PASTE] = "M_PASTE";
|
||||
names[M_STRING] = "M_STRING";
|
||||
names[P_LINE] = "P_LINE";
|
||||
names[INVALID] = "INVALID";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Anarres C Preprocessor
|
||||
* Copyright (c) 2007-2008, Shevek
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package org.anarres.cpp;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.PushbackReader;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Iterator;
|
||||
|
||||
import static org.anarres.cpp.Token.*;
|
||||
|
||||
@Deprecated
|
||||
/* pp */ class TokenSnifferSource extends Source {
|
||||
private List<Token> target;
|
||||
|
||||
/* pp */ TokenSnifferSource(List<Token> target) {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
public Token token()
|
||||
throws IOException,
|
||||
LexerException {
|
||||
Token tok = getParent().token();
|
||||
if (tok.getType() != EOF)
|
||||
target.add(tok);
|
||||
return tok;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return getParent().toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Anarres C Preprocessor
|
||||
* Copyright (c) 2007-2008, Shevek
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
namespace CppNet {
|
||||
|
||||
/**
|
||||
* An extremely lightweight virtual file interface.
|
||||
*/
|
||||
public interface VirtualFile {
|
||||
// public String getParent();
|
||||
bool isFile();
|
||||
string getPath();
|
||||
string getName();
|
||||
VirtualFile getParentFile();
|
||||
VirtualFile getChildFile(string name);
|
||||
Source getSource();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Anarres C Preprocessor
|
||||
* Copyright (c) 2007-2008, Shevek
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
|
||||
namespace CppNet
|
||||
{
|
||||
/**
|
||||
* An extremely lightweight virtual file system interface.
|
||||
*/
|
||||
public interface VirtualFileSystem
|
||||
{
|
||||
VirtualFile getFile(String path);
|
||||
VirtualFile getFile(String dir, String name);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Anarres C Preprocessor
|
||||
* Copyright (c) 2007-2008, Shevek
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
|
||||
namespace CppNet
|
||||
{
|
||||
/**
|
||||
* Warning classes which may optionally be emitted by the Preprocessor.
|
||||
*/
|
||||
[Flags]
|
||||
public enum Warning
|
||||
{
|
||||
NONE = 0,
|
||||
TRIGRAPHS = 1 << 0,
|
||||
// TRADITIONAL,
|
||||
IMPORT = 1 << 1,
|
||||
UNDEF = 1 << 2,
|
||||
UNUSED_MACROS = 1 << 3,
|
||||
ENDIF_LABELS = 1 << 4,
|
||||
ERROR = 1 << 5,
|
||||
// SYSTEM_HEADERS
|
||||
}
|
||||
|
||||
}
|
Загрузка…
Ссылка в новой задаче