13-03.ファイル構成の設定と、関数定義
この項では、このソリューションで作成するざっとしたファイル群を作成し、
関数を実装できるようにします。
C言語は、その言語構造自体に
main関数は含まれません。
関数の定義方法と
関数の実行方法が決まっているだけで、一般的には
main関数から始まるというだけです。
ですから、例えば
Windowsアプリは
WinMain関数から始まります。C言語の技術書やマニュアルには
C言語はmain関数に始まって、main関数の終了がプログラムの終了であると記載されていますが、それは、一般論であって、言語を自作する場合、変更できます。
なので
C言語を作成する場合は、そのことは知っておく必要があります。
つまりは
main関数を定義し、実行するということと
funcという自作関数を定義し、実行するというメカニズムは、同じなのです。
この項で作成するプロジェクトでは、
関数の定義の最小なものが実装されます。そして、最初に
main関数を探して、見つかれば、それを
実行します。
このことだけを念頭に置いて、以下を記述しましょう。
CLangProject.l
まず
FlexBisonプロジェクトにある
CLangProject.lファイルです。以下のように書き換えます。計算の演算子
ADDやMULなどはいったん外してあります。
%{
#include <stdio.h>
#include "CLangProject.tab.h"
#define YY_SKIP_YYWRAP 1
int gLine = 1;
int yywrap(void){ return 1; }
%}
%s COMMENT
%s LINE_COMMENT
%%
<INITIAL>{
"(" return LP;
")" return RP;
"{" return LC;
"}" return RC;
";" return SEMICOLON;
"dump" return DMP;
"int" return INT_TYPE;
"/*" { BEGIN(COMMENT);}
[/][/]+ { BEGIN(LINE_COMMENT);}
[1-9][0-9]* {
return INT_LITERAL;
}
[A-Za-z_][A-Za-z_0-9]* {
return IDENTIFIER;
}
"\n" {gLine++;}
[ \t] ;
. { return 0;}
}
<COMMENT>{
"\n" {gLine++;}
"*/" {BEGIN(INITIAL);}
. ;
}
<LINE_COMMENT>{
"\n" { gLine++; BEGIN(INITIAL);}
. ;
}
%%
CLangProject.y
同じく
FlexBisonプロジェクトにある
CLangProject.yファイルです。
%{
#include "../CLangProject/proc.h"
#define YYDEBUG 1
extern int yylex(void);
extern char *yytext;
int yyerror(char const *str){
extern int gLine;
fprintf(stderr,"%s, line: %d, near %s\n",str, gLine, yytext);
return 0;
}
%}
%code requires {
#include "../CLangProject/proc.h"
}
%union {
clg::Expression* pExpression;
clg::Statement* pStatement;
clg::StatementList* pStatementList;
clg::Declaration* pDeclaration;
clg::DeclarationList* pDeclarationList;
clg::ParameterList* pParameterList;
clg::Root* pRoot;
}
%token IDENTIFIER INT_LITERAL DMP INT_TYPE SEMICOLON
%token LC RC LP RP
%type <pExpression> expression intliteral_expression identifier_expression postfix_expression
%type <pStatementList> statement_list
%type <pStatement> dump_statement expression_statement compound_statement statement
%type <pDeclaration> declaration
%type <pDeclarationList> declaration_list
%type <pRoot> root
%type <pParameterList> parameter_list
%%
root
: declaration_list
{
$$ = clg::StackMachine::get()->addRootDeclarationList($1);
}
;
declaration_list
: declaration
{
$$ = clg::StackMachine::get()->createDeclarationList($1);
}
| declaration_list declaration
{
$$ = clg::StackMachine::get()->createDeclarationList($1,$2);
}
;
declaration
: INT_TYPE identifier_expression LP parameter_list RP compound_statement
{
$$ = clg::StackMachine::get()->createIntFunctionDeclaration($2,$6);
}
;
parameter_list
: /*empty*/
{
$$ = clg::StackMachine::get()->createParameterList();
}
;
statement_list
: statement
{
$$ = clg::StackMachine::get()->createStatementList($1);
}
| statement_list statement
{
$$ = clg::StackMachine::get()->createStatementList($1,$2);
}
;
statement
: dump_statement
| compound_statement
| expression_statement
;
expression_statement
: expression SEMICOLON
{
$$ = clg::StackMachine::get()->createExpressionStm($1);
}
;
dump_statement
:DMP expression SEMICOLON
{
$$ = clg::StackMachine::get()->createDumpStm($2);
}
;
compound_statement
: LC RC
{
$$ = clg::StackMachine::get()->createCompoundStatement();
}
| LC statement_list RC
{
$$ = clg::StackMachine::get()->createCompoundStatement($2);
}
;
expression
:intliteral_expression
|identifier_expression
|postfix_expression
;
postfix_expression
: identifier_expression LP RP
{
$$ = clg::StackMachine::get()->createFunctionCallExp($1);
}
;
identifier_expression
: IDENTIFIER
{
$$ = clg::StackMachine::get()->createIdentifierExp(yytext);
}
;
intliteral_expression
: INT_LITERAL
{
$$ = clg::StackMachine::get()->createIntLiteralExp(yytext);
}
;
%%
ここからは
CLangProjectプロジェクトに実装します。
ファイルがない場合は追加してください。その際
.hファイルであれば
ヘッダー ファイルフィルタ、
.cppファイルであれば
ソース ファイルフィルタ内に追加しましょう。
まずは
.hファイルです。
common.h
#pragma once
namespace clg {
#define ORE_MAX_TOKEN_LEN 255
///stringを255文字に切り詰める
inline string clampToken(const char* ext) {
string str(ext);
if (str.size() > ORE_MAX_TOKEN_LEN) {
str.erase(ORE_MAX_TOKEN_LEN);
}
return str;
}
//--------------------------------------------------------------------------------------
/// Objectベース(基底クラス)
//--------------------------------------------------------------------------------------
class ObjBase {
protected:
ObjBase() {}
public:
virtual ~ObjBase() {}
};
}
//end namespace clg
declaration.h
#pragma once
namespace clg {
//--------------------------------------------------------------------------------------
/// パラメータリストクラス
//--------------------------------------------------------------------------------------
class ParameterList : public ObjBase {
const char* m_pIdent;
ParameterList* m_Next;
public:
ParameterList() :
m_pIdent(nullptr),
m_Next(nullptr)
{
}
ParameterList(const char* ident) :
m_pIdent(ident),
m_Next(nullptr)
{
}
virtual ~ParameterList() {}
const char* getIdent() const {
return m_pIdent;
}
ParameterList* getNext()const {
return m_Next;
}
void setNext(ParameterList* next) {
m_Next = next;
}
};
//--------------------------------------------------------------------------------------
/// 宣言クラス
//--------------------------------------------------------------------------------------
class Declaration : public ObjBase {
protected:
Declaration() {}
public:
virtual ~Declaration() {}
};
//--------------------------------------------------------------------------------------
/// int型関数定義
//--------------------------------------------------------------------------------------
class IntFunctionDeclaration : public Declaration {
const char* m_pIdent;
CompoundStatement* m_pCompoundStatement;
public:
IntFunctionDeclaration(IdentifierExp* pIdent, Statement* stm):
m_pIdent{ pIdent->getIdentity() }
{
m_pCompoundStatement = dynamic_cast<CompoundStatement*>(stm);
}
const char* getIdentity() const {
return m_pIdent;
}
void excute();
virtual ~IntFunctionDeclaration() {}
};
//--------------------------------------------------------------------------------------
/// 宣言リストクラス
//--------------------------------------------------------------------------------------
class DeclarationList : public ObjBase {
Declaration* m_Declaration;
DeclarationList* m_Next;
public:
DeclarationList(Declaration* decl) :
m_Declaration(decl),
m_Next(nullptr)
{
}
Declaration* getDecl() const {
return m_Declaration;
}
DeclarationList* getNext()const {
return m_Next;
}
void setNext(DeclarationList* next) {
m_Next = next;
}
virtual ~DeclarationList() {}
};
}
// end namespace clg
expression.h
#pragma once
namespace clg {
//--------------------------------------------------------------------------------------
/// 式クラス
//--------------------------------------------------------------------------------------
class Expression : public ObjBase {
protected:
Expression() {}
public:
virtual ~Expression() {}
virtual Value execute() {
return Value();
}
};
//--------------------------------------------------------------------------------------
/// intリテラル式クラス
//--------------------------------------------------------------------------------------
class IntLiteralExp : public Expression {
int m_intValue;
public:
IntLiteralExp(int i = 0) {
m_intValue = i;
}
virtual ~IntLiteralExp() {}
virtual Value execute() override;
};
//--------------------------------------------------------------------------------------
/// 識別子式クラス
//--------------------------------------------------------------------------------------
class IdentifierExp : public Expression {
const char* m_Identity;
public:
IdentifierExp(const char* ident):
m_Identity(ident)
{
}
const char* getIdentity() const {
return m_Identity;
}
virtual ~IdentifierExp() {}
virtual Value execute() override;
};
//--------------------------------------------------------------------------------------
/// 関数呼び出し式クラス
//--------------------------------------------------------------------------------------
class FunctionCallExp : public Expression {
const char* m_Identity;
public:
FunctionCallExp(const char* ident) :
m_Identity(ident) {
}
const char* getIdentity() const {
return m_Identity;
}
virtual ~FunctionCallExp() {}
virtual Value execute() override;
};
}
//end namespace clg
proc.h
#pragma once
#undef INT8_MIN
#undef INT16_MIN
#undef INT32_MIN
#undef INT8_MAX
#undef INT16_MAX
#undef INT32_MAX
#undef UINT8_MAX
#undef UINT16_MAX
#undef UINT32_MAX
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <fstream>
#include <string>
#include <set>
#include <map>
#include <vector>
#include <list>
#include <memory>
using namespace std;
#include "common.h"
#include "value.h"
#include "expression.h"
#include "statement.h"
#include "declaration.h"
#include "stackMachine.h"
stackMachine.h
#pragma once
namespace clg
{
//--------------------------------------------------------------------------------------
/// ルートクラス
//--------------------------------------------------------------------------------------
class Root : public ObjBase {
DeclarationList* m_pDeclarationList;
public:
Root() :
m_pDeclarationList(nullptr)
{}
virtual ~Root() {}
Value execute();
void setDeclList(DeclarationList* decl) {
m_pDeclarationList = decl;
}
DeclarationList* getDeclList()const {
return m_pDeclarationList;
}
};
//--------------------------------------------------------------------------------------
/// スタックマシンクラス
//--------------------------------------------------------------------------------------
class StackMachine {
//命令ポインタ
unsigned int m_ip = 0;
//ルートオブジェクト
Root* m_pRoot;
//オブジェクトのプール
vector<ObjBase*> m_objPool;
//文字列のプール
set<string> m_fixedStringPool;
const char* createFixedString(const char* ext);
StackMachine();
public:
virtual ~StackMachine();
int compile(FILE* fp);
void execute();
void destroy();
//インスタンス参照
static StackMachine* get();
Root* getRoot() {
return m_pRoot;
}
//式
/// INTリテラル
Expression* createIntLiteralExp(const char* ptr);
//識別子
Expression* createIdentifierExp(const char* ptr);
//関数呼び出し
Expression* createFunctionCallExp(Expression* pIdent);
//文
//デバッグ出力
Statement* createDumpStm(Expression* exp);
//式文
Statement* createExpressionStm(Expression* exp);
//Compound文
Statement* createCompoundStatement(StatementList* stml = nullptr);
//文リスト
StatementList* createStatementList(Statement* stm);
StatementList* createStatementList(StatementList* stml, Statement* stm);
//パラメータリスト
ParameterList* createParameterList();
//宣言
//int型関数定義
Declaration* createIntFunctionDeclaration(Expression* pExp, Statement* stm);
//宣言リスト
DeclarationList* createDeclarationList(Declaration* decl);
DeclarationList* createDeclarationList(DeclarationList* declList,Declaration* decl);
//ルートへのDeclarationListの追加
Root* addRootDeclarationList(DeclarationList* decl);
};
}
//end namespace clg
statement.h
#pragma once
namespace clg {
//--------------------------------------------------------------------------------------
/// 文クラス
//--------------------------------------------------------------------------------------
class Statement : public ObjBase {
protected:
Statement() {}
public:
virtual ~Statement() {}
//voidの実行関数
virtual Value execute() {
return Value();
}
};
//--------------------------------------------------------------------------------------
/// Dump文クラス
//--------------------------------------------------------------------------------------
class DumpStm : public Statement {
Expression* m_expression;
public:
DumpStm(Expression* exp) :
m_expression(exp)
{}
//実行関数
virtual Value execute() override;
virtual ~DumpStm() {}
};
//--------------------------------------------------------------------------------------
/// 式文クラス
//--------------------------------------------------------------------------------------
class ExpressionStm : public Statement {
Expression* m_expression;
public:
ExpressionStm(Expression* exp) :
m_expression(exp)
{}
//実行関数
virtual Value execute() override;
virtual ~ExpressionStm() {}
};
//--------------------------------------------------------------------------------------
/// 文リストクラス
//--------------------------------------------------------------------------------------
class StatementList : public ObjBase {
Statement* m_Statement;
StatementList* m_Next;
public:
StatementList(Statement* stm) :
m_Statement(stm),
m_Next(nullptr)
{
}
Statement* getStm() const {
return m_Statement;
}
StatementList* getNext()const {
return m_Next;
}
void setNext(StatementList* next) {
m_Next = next;
}
void execute();
virtual ~StatementList() {}
};
//--------------------------------------------------------------------------------------
/// Compoundステートメント
//--------------------------------------------------------------------------------------
class CompoundStatement : public Statement {
StatementList* m_pStatementList;
public:
CompoundStatement(StatementList* stml) :
m_pStatementList(stml)
{}
virtual ~CompoundStatement() {}
//実行関数
virtual Value execute() override;
};
}
//end namespace clg
value.h
#pragma once
namespace clg {
//--------------------------------------------------------------------------------------
/// 値タイプ
//--------------------------------------------------------------------------------------
enum class ValueType {
voidVal = 0,
boolVal,
intVal,
doubleVal,
};
//--------------------------------------------------------------------------------------
/// 値
//--------------------------------------------------------------------------------------
struct Value {
ValueType m_type;
union {
bool boolV;
int intV;
double doubleV;
};
explicit Value();
explicit Value(bool b);
explicit Value(int i);
explicit Value(double d);
Value(const Value& other);
Value& operator=(const Value& other);
~Value() {}
};
}
// end namespace clg
これより
cppファイルです。
CLangProjectプロジェクトの
ソース ファイルフィルタに設置します。
declaration.cpp
#include "proc.h"
namespace clg {
void IntFunctionDeclaration::excute() {
if (m_pCompoundStatement) {
m_pCompoundStatement->execute();
}
}
}
//end namespace clg
expression.cpp
#include "proc.h"
namespace clg {
Value IntLiteralExp::execute() {
return Value(m_intValue);
}
Value IdentifierExp::execute() {
return Value();
}
Value FunctionCallExp::execute() {
bool flg = false;
auto pRoot = StackMachine::get()->getRoot();
auto pos = pRoot->getDeclList();
do {
auto decl = pos->getDecl();
auto tgt = dynamic_cast<IntFunctionDeclaration*>(decl);
if (tgt) {
string str = tgt->getIdentity();
if (str == m_Identity) {
flg = true;
tgt->excute();
break;
}
}
pos = pos->getNext();
} while (pos);
if (!flg) {
cout << "関数が見つかりません。: " << m_Identity << endl;
exit(1);
}
return Value();
}
}
//end namespace clg
main.cpp
#include "proc.h"
class InputParser {
vector <string> m_tokens;
public:
InputParser(int& argc, char** argv) {
for (int i = 1; i < argc; ++i) {
m_tokens.push_back(string(argv[i]));
}
}
const string& getCmdOption(const string& option) const {
vector<string>::const_iterator itr;
itr = find(m_tokens.begin(), m_tokens.end(), option);
if (itr != m_tokens.end() && ++itr != m_tokens.end()) {
return *itr;
}
static const string empty_string("");
return empty_string;
}
bool cmdOptionExists(const string& option) const {
return find(m_tokens.begin(), m_tokens.end(), option)
!= m_tokens.end();
}
};
int main(int argc, char** argv) {
InputParser input(argc, argv);
const string& filename = input.getCmdOption("-f");
if (filename.empty()) {
cout << "スクリプトファイルが指定されていません。" << endl;
return 1;
}
errno_t err;
FILE* fp;
if ((err = fopen_s(&fp, filename.c_str(), "r")) != 0) {
cout << "スクリプトファイルの読み込みに失敗しました。" << endl;
return 1;
}
auto tntp = clg::StackMachine::get();
if (tntp->compile(fp)) {
return 1;
}
tntp->execute();
tntp->destroy();
return 0;
}
stackMachine.cpp
#include "proc.h"
namespace clg
{
Value Root::execute() {
// main関数を探して実行
FunctionCallExp* pFunc = new FunctionCallExp("main");
pFunc->execute();
return Value();
}
//唯一のスタックマシンのインスタンス
StackMachine* g_pSackMachine;
StackMachine::StackMachine()
{}
StackMachine::~StackMachine() {
for (size_t i = 0; i < m_objPool.size(); i++) {
delete m_objPool[i];
}
m_objPool.clear();
}
const char* StackMachine::createFixedString(const char* ext) {
//255文字に切り詰める。
auto str = clampToken(ext);
auto it = m_fixedStringPool.insert(str);
return it.first->c_str();
}
int StackMachine::compile(FILE* fp) {
m_pRoot = new Root();
extern int yyparse(void);
extern FILE* yyin;
yyin = fp;
if (yyparse()) {
return 1;
}
return 0;
}
void StackMachine::execute() {
if (m_pRoot) {
m_pRoot->execute();
}
}
void StackMachine::destroy() {
if (g_pSackMachine) {
delete g_pSackMachine;
g_pSackMachine = nullptr;
}
}
//インスタンス参照
StackMachine* StackMachine::get() {
if (!g_pSackMachine) {
g_pSackMachine = new StackMachine();
}
return g_pSackMachine;
}
/// INTリテラル
Expression* StackMachine::createIntLiteralExp(const char* ptr) {
string str = clampToken(ptr);
auto pObj = new IntLiteralExp(std::stoi(str));
m_objPool.push_back(pObj);
return pObj;
}
Expression* StackMachine::createIdentifierExp(const char* ptr) {
auto pStr = createFixedString(ptr);
auto pObj = new IdentifierExp(pStr);
m_objPool.push_back(pObj);
return pObj;
}
//関数呼び出し
Expression* StackMachine::createFunctionCallExp(Expression* pIdent) {
auto tgt = dynamic_cast<IdentifierExp*>(pIdent);
if (tgt) {
auto pObj = new FunctionCallExp(tgt->getIdentity());
m_objPool.push_back(pObj);
return pObj;
}
else {
cout << "関数呼び出しが間違っています" << endl;
exit(1);
}
return nullptr;
}
//出力
Statement* StackMachine::createDumpStm(Expression* exp) {
auto pObj = new DumpStm(exp);
m_objPool.push_back(pObj);
return pObj;
}
Statement* StackMachine::createExpressionStm(Expression* exp) {
auto pObj = new ExpressionStm(exp);
m_objPool.push_back(pObj);
return pObj;
}
//Compound文
Statement* StackMachine::createCompoundStatement(StatementList* stml) {
auto pObj = new CompoundStatement(stml);
m_objPool.push_back(pObj);
return pObj;
}
StatementList* StackMachine::createStatementList(Statement* stm) {
auto pObj = new StatementList(stm);
m_objPool.push_back(pObj);
return pObj;
}
StatementList* StackMachine::createStatementList(StatementList* stml, Statement* stm) {
StatementList* pos;
if (stml == nullptr)
return createStatementList(stm);
for (pos = stml; pos->getNext(); pos = pos->getNext())
;
pos->setNext(createStatementList(stm));
return stml;
}
//パラメータリスト
ParameterList* StackMachine::createParameterList() {
auto ptr = new ParameterList();
m_objPool.push_back(ptr);
return ptr;
}
//宣言
//int型関数定義
Declaration* StackMachine::createIntFunctionDeclaration(Expression* pExp, Statement* stm) {
IdentifierExp* pIdent = dynamic_cast<IdentifierExp*>(pExp);
CompoundStatement* pComp = dynamic_cast<CompoundStatement*>(stm);
if (pIdent && stm) {
auto pObj = new IntFunctionDeclaration(pIdent, stm);
m_objPool.push_back(pObj);
return pObj;
}
else {
cout << "関数定義が間違っています" << endl;
exit(1);
}
return nullptr;
}
DeclarationList* StackMachine::createDeclarationList(Declaration* decl) {
auto pObj = new DeclarationList(decl);
m_objPool.push_back(pObj);
return pObj;
}
DeclarationList* StackMachine::createDeclarationList(DeclarationList* declList, Declaration* decl) {
DeclarationList* pos;
if (declList == nullptr)
return createDeclarationList(decl);
for (pos = declList; pos->getNext(); pos = pos->getNext())
;
pos->setNext(createDeclarationList(decl));
return declList;
}
//ルートへのDeclarationListの追加
Root* StackMachine::addRootDeclarationList(DeclarationList* decl) {
if (m_pRoot) {
m_pRoot->setDeclList(decl);
}
return m_pRoot;
}
}
//end namespace clg
statement.cpp
#include "proc.h"
namespace clg
{
//--------------------------------------------------------------------------------------
/// Dump文クラス
//--------------------------------------------------------------------------------------
Value DumpStm::execute() {
if (m_expression) {
auto val = m_expression->execute();
switch (val.m_type) {
case ValueType::intVal:
cout << val.intV << endl;
break;
}
}
return Value();
}
//--------------------------------------------------------------------------------------
/// 式文クラス
//--------------------------------------------------------------------------------------
Value ExpressionStm::execute() {
if (m_expression) {
auto val = m_expression->execute();
}
return Value();
}
void StatementList::execute() {
auto pos = this;
do {
auto stm = pos->getStm();
stm->execute();
pos = pos->getNext();
} while (pos);
}
Value CompoundStatement::execute() {
if (m_pStatementList) {
m_pStatementList->execute();
}
return Value();
}
}
// end namespace clg
value.cpp
#include "proc.h"
namespace clg {
Value::Value()
{
m_type = ValueType::voidVal;
intV = 0;
}
Value::Value(bool b)
{
m_type = ValueType::boolVal;
boolV = b;
}
Value::Value(int i)
{
m_type = ValueType::intVal;
intV = i;
}
Value::Value(double d)
{
m_type = ValueType::doubleVal;
doubleV = d;
}
Value::Value(const Value& other)
{
*this = other;
}
Value& Value::operator=(const Value& other) {
if (this != &other) {
*this = other;
}
return *this;
}
}
//end namespace ore
警告を外す
ここまで記述すると
12-02.FlexとBisonで計算機(VS2019版)で設定した
CLangProjectに対する
4996という警告無視の設定を外すことができます。
CLangProjectプロジェクトの
プロパティを開いて
C/C++ー詳細設定メニューで
指定の警告を無効にするに記載されている
4996を削除します。削除したら
OKをクリックします。
スクリプトの編集
最後に、スクリプトファイルである
index.cです。
CLangProjectプロジェクトの
スクリプトファイルフィルタにあります。
index.c
int func() {
dump 30;
}
int main () {
dump 10;
dump 20;
func();
}
子こまっで記述したら
ビルド-ソリューションのリビルドを行い、エラーがなければ
デバッグ-デバッグなしで開始を行います。コンソールが開き
10
20
30
...\CLangProject.exe (プロセス 11884) は、コード 0 で終了しました。
このウィンドウを閉じるには、任意のキーを押してください...
がでたら成功です。もしビルド中にエラーが出るか、あるいは実行できなければ、上記のファイルのどこかに、作成漏れがあるか、記述漏れがあります。成功するまで、トライしましょう。
次項から、この項で作成したプロジェクトについて、できるだけ詳しく解説します。