Git の基礎概念 2

参考書籍

入門 Git

Gitとは

git はファイルの状態を管理するためのソフトウェア。

git で管理されているディレクトリ配下のファイル群のバージョン管理を行うことができる。

オブジェクト

git はオブジェクトという単位でデータを扱う。オブジェクトには下記の型がある。

  • blob オブジェクト
  • tree オブジェクト
  • commit オブジェクト
  • tag オブジェクト

オブジェクトはオブジェクトデータベース に保管されている。一意の名前で検索するので高速にアクセスできる。

オブジェクトは全て下記のような構造を持っている。

  • 名前
  • ヘッダ
  • ボディ

名前はヘッダとボディをまとめてハッシュ化した文字列が与えられる。これによって一意性を担保している。

ヘッダにはオブジェクトの型種別とサイズが入っている。

ボディにはデータの内容が入っている。項目は型によって異なる。

blob オブジェクト

git で管理するファイル一つ分のデータに対応する。

blob オブジェクトのボディ

ファイルの中身が格納されている。

tree オブジェクト

git で管理するディレクトリ一つ分のデータに対応する。

tree オブジェクトのボディ

対応するディレクトリ直下のファイルやディレクトリのオブジェクト名のリストが格納される。

これによりトップレベルの tree オブジェクトから git 管理対象のファイル群の全てを再現することができる。

commit オブジェクト

コミット一つ分に対応する。

commit オブジェクトのボディ

コミットのメッセージや作成時間や作者が格納される。

これによっていつ誰がどういう意図でそのコミットが作られたのかを確認することができる。

その他 tree や parent という項目が記録されることでディレクトリ構成やプロジェクトの歴史を辿ることができる。

コミットオブジェクトの内容は下記のように確認できる。

git cat-file -p 6fe9eb78ab891c36a6d3b6b659e0d9f2a89545ee
tree

トップレベルの tree オブジェクトの名前。

これによりそのコミット の時点で git 管理するファイル群全てを再現することができる。

parent

一つ前のコミットのオブジェクト名。

これによりコミット間で親子関係を表現することができ、過去のコミットの歴史を辿ることができるようになる。

その他キーワード

ブランチ

ブランチとは特定のコミットへのポインタのこと。

ブランチ -> コミット

HEAD

HEAD とは現在チェックアウトしているブランチへのポインタのこと。

HEAD -> ブランチ -> コミット

マージ

マージするとマージコミット が作成される場合とそうでない場合がある。

マージする側が対象のブランチが分岐した時点から変化していない場合はマージコミットが作成されない。その場合はマージする側のブランチが対象のブランチのコミットと同じものになるだけ。これをfast forwardという。

マージコミットは parent を二つ持つ。

apt の基本

apt の基本

apt とは

aptとは advanced packaging tool の略。

パッケージ管理のためのツールの一つ。

パッケージとはtmuxtreeなど便利なツールを実行ファイル・設定ファイル・ドキュメントなど一まとめにアーカイブしたファイルのこと。

リポジトリと呼ばれるパッケージを保管するためのサーバーで管理されている。

ディストリビューションごとに公式のリポジトリがあり、デフォルトのリポジトリとして設定されている。

公式以外のリポジトリもあり、設定を変えることでそれらからもパッケージを取得することができる。

apt の基本的な使い方

apt-get update、apt-get install、apt-get remove、apt-cache search、apt-cache show といった一部の人気コマンドが単に apt を経由して apt update、apt install、apt remove、apt search、apt show でもできるようになったということです。 apt ツールは apt-get と apt-cache の機能を統合し、デフォルトで小洒落た色付きの出力形式を採用して人間にとって使いやすくなっています。スクリプトでの利用や細かな処理には apt-get の方が好ましいあるいは必要となるでしょう。

aptapt-get/apt-cacheのラッパーぽい?

とりあえずはaptを使っておけば良さそう。

# 例
apt search nkf
sudo apt install nkf
sudo apt remove nkf

パッケージ更新の流れ

apt update と apt upgrade
apt update

apt が使うことのできるパッケージのリストを更新する。これは新しいパッケージのインストールは行わない。

apt upgrade

apt が管理しているリストを基にインストール済みのパッケージのより新しいバージョンを取得しインストールする。

パッケージの更新

実際にパッケージを新しくするためには update で新しいバージョンの情報を取得してから upgrade でそのバージョンのインストールを行う必要がある。

sudo apt update && sudo apt upgrade

標準以外のソフトをインストール

apt-add-repositorysources.listリポジトリを追加することができる。

$ sudo apt-add-repository non-free
$ cat /etc/apt/sources.list
# deb http://ftp.jp.debian.org/debian buster main

deb http://ftp.jp.debian.org/debian buster main non-free
deb-src http://ftp.jp.debian.org/debian buster main non-free

deb http://security.debian.org/debian-security buster/updates main non-free
deb-src http://security.debian.org/debian-security buster/updates main non-free

CSSで余白を作る時に親要素のpaddingにすべきか子要素のmarginにすべきかで迷う

前提(親子の位置関係)

  • 要素の中身や指定がない場合、親要素のheightは子要素のそれと等しくなる。
  • 要素の中身や指定がない場合、子ブロック要素のwidthは親要素のそれと等しくなる。幅の指定のある先祖がいない場合は window 幅になる。
  • 親要素が要素の中身や border の実体を持っていなくて padding が指定されていない場合は子要素は親要素から見てtop: 0; left: 0の位置に配置される。

子要素のmarginとして余白を作る

親要素が要素の中身や border の実体を持っていない場合

  • 子要素の上下に margin が指定されていたとしてもtop: 0の位置は変わらない。
  • 子要素の左右に margin が指定されている場合はそれが反映される。
  • 親要素にoverflow: hidden;が設定された場合は子要素の margin は親要素との境界に対して適用される。ただし margin を適用させる目的でこれを行うべきではない。

親要素が要素の中身や border の実体を持っている場合

親要素が要素の中身や border の実体を持っている場合には子要素の margin はそれらに対して適用される。結果的に子要素の上下にmarginが適応される。

親要素のpaddingとして余白を作る場合

親要素に padding が指定されている場合は子要素常には padding の内側に配置される。

結論

子要素にmarginをつけて親要素との余白をとろうとすると条件によって適用のされ方に違いが出るので親要素にpaddingを設けた方が実装がシンプルになる場合が多い。

CSS のボックスモデルについて

CSS のボックスモデルについて

参考資料

ボックスモデルとは

CSS では要素の持つ領域についてボックスモデルと呼ばれる考え方が適用されている。

ボックスモデルとは html の要素がそれぞれボックス型の領域を持っていて CSS でその領域の大きさや他の要素(の境界)との距離を操作することができるというモデルである。

CSSセレクタを指定して操作できるのはそのセレクタの属する領域についてである。

用語について

ボックスモデルでは要素の持つ領域がパーツに分けられている。

それぞれのパーツとその外側に名前がついているのでまとめる。

要素

要素は html の開始タグから終了タグまでの部分のこと。

この領域のことをcontent-boxと呼ぶと思われる。

heightwidthで指定できるのは要素そのものの値となる。

インライン要素のheightwidthは固定されているため指定することができない。

要素そのものの大きさ(長さ)はその要素が持つ領域を超えることもできる。超えた部分の要素は他の要素の領域にも干渉する。

領域を超えた部分の扱いについてはoverflowプロパティで指定することができる

padding

paddingは要素に属する領域(border-box)のうち要素そのもの(content-box)の外側の部分のこと。

border

borderは要素に属する領域とその外側の境界線のこと。

margin

margin によって要素に属している領域の外側の部分の余白(他の要素の境界との距離)を指定することができる。

margin 自体はその要素に属していないのでこの余白の指定は他の要素の指定に相殺されることがある。

box-sizing

box-sizingプロパティを指定することによって widthheightで設定できる範囲を変更することができる。

上記の要素の説明は初期値であるbox-sizing: content-box;に即している。

box-sizing: border-box;とすればpaddingborderが含まれる領域についてwidthheightを指定できるようになる。

CSS の基本

CSS の基本

参考資料

スタイルシートの基本

CSS とは

CSS とは Cascading Style Sheet の略。

CSSスタイルシートの一つ。スタイルシートは文章の見た目を定義するための仕様のこと。

スタイルシートは HTML の誕生の前から存在していた。

HTML に適用することができるスタイルシートCSS だけではない。

ただし一般的なブラウザに実装されているのは CSS であるため普通はこれを使用する。

CSS の書き方

p タグの文字列を青で表示する CSS

p {
  color: blue;
}

セレクタ

pの部分({}の前)のことをセレクタと呼ぶ。

スタイルを適用させたい対象をここに書く。

ここではp要素を指定している。

宣言

{}で括られた中身の部分のことを宣言と呼ぶ。

なかにプロパティと値を書く。

宣言は;で区切って複数書く事ができる。

プロパティ

{}内の:の左側のcolorの部分。

適用させたい表現の種類をここに書く。

ここではセレクタの文字列の色を指定しようとしている。

プロパティは定義されているものの中から選ぶ。

{}内の:の右側のblueの部分。

プロパティを具体的にどのようにしたいのかを書く。

ここではセレクタの文字列の色を青色にしようとしている。

CSS はどこに書くか

HTML に CSS を適用するためにはブラウザが認識できる場所にそれが書かれている必要がある。

HTML 要素の style 属性で定義する

要素の属性情報として直接指定する。

style 属性の値として CSS の記法で文字列を指定する。

まさにその要素のみに適用される。

<span style="color: blue;">青い文字</span>

HTML の style 要素で定義する

head 要素内に書く。

HTML 内の全ての要素に対して適用される。

<head>
  <style type="text/css">
    h1 {
      color: red;
    }
  </style>
</head>

外部ファイルからの読み込み

CSS が書かれた CSS ファイル(.css)を用意する。

適用したい HTML のhead要素内にlink要素で定義して対象の css ファイルを読み込む。

<head>
  <link rel="stylesheet" type="text/css" href="common.css" />
</head>

CSS の優先順位

CSS ではある HTML 要素に対して複数の方法でスタイルを指定することができそれらは共存することができる。

これらが競合する場合には優先順位順にスタイルが適用される。また、同じ優先順位の CSS が競合している場合は読み込みの順番が遅いものが優先される。

自作コンパイラ開発メモ(2020/12/13)

低レイヤを知りたい人のための C コンパイラ作成入門を読んでコンパイラ自作してる時の作業記録です。

対象箇所

for 文に対応するアセンブリを出力できるようにしました。

実装

  • 関数 foo が定義された c のプログラムを作成
  • 関数名を識別子としてトークナイズ
  • 関数としての node を生成できるようにした
  • 関数の node を消費してアセンブリで指定の関数(foo)を呼び出せるようにした
  • foo が定義されたプログラムを自分のコンパイラの出力とリンクできるようにした
  • 生成された実行ファイルで foo が実行されることを確認した

メモ

primary = num
        | ident ("(" ")")?
        | "(" expr ")"

ident が変数名なのか関数名なのかは直後の()の有無で判断する。

関数の node を消費してアセンブリで指定の関数(foo)を呼び出せるようにした

call foo

今回は擬似的に関数の呼び出しを確認するだけなので node を消費したときは引数なしのfoocallするようにした。

foo が定義されたプログラムを自分のコンパイラの出力とリンクできるようにした

./9cc "$input" > tmp.s
cc tmp.s foo.c -o tmp
./tmp

tmp という実行ファイルを作成している。

tmp.sは自分のコンパイラで出力したアセンブリfoo.cfoo()が定義されている c ファイルです。

ccの引数にこれらの二つのファイルを渡すことで互いにリンクさせることができる。

自作コンパイラ開発メモ(2020/11/22)

低レイヤを知りたい人のための C コンパイラ作成入門を読んでコンパイラ自作してる時の作業記録です。

対象箇所

for 文に対応するアセンブリを出力できるようにしました。

実装

  • {}を解析しトークン化できるようにした。
  • ブロック文のノードを構文木内に配置できるようにした。
  • ブロック文のノードを検知してアセンブリとして出力できるようにした。

メモ

ブロックとは

正式には「compound statement」と呼ばれるらしい。

「compound」は複合という意味。直訳すると複合文となる。
複数の文をまとめて一つの意味のある処理と捉えることができる。

関数の本体部分もブロックである。
制御構文の{}と関数の{}には違いがない。

実装

EBNFにブロックを取り入れると下記のようになる。

program = stmt*
stmt    = expr ";"
        | "{" stmt* "}"
        | "if" "(" expr ")" stmt ("else" stmt)?
        | "while" "(" expr ")" stmt
        | "for" "(" expr? ";" expr? ";" expr? ")" stmt
        | "return" expr ";"
        | ...
...

ブロックは"{" stmt* "}"の部分。

{を検出したら}が検出されるまでstmtを消費する。

stmtの一回以上の繰り返し(stmt*)はprogram = stmt*ですでに実装したので同じ方法で実装した。

if (consume("{"))
{
    int i = 0;
    node = new_node(ND_BLOCK, node, NULL);
    while (!consume("}"))
    {
        node->block[i++] = stmt();
    }
    node->block[i] = NULL;
}

Node構造体のメンバにblockとしてNodeのポインタの配列を宣言した。

Node *block[100];

ハマった箇所

最初Node *block[];のようにNodeのblockの要素の数を指定していなかった。

そしたら、node->kindを参照する箇所で想定しない値が入っていてバグになっていた。
その値は実行する度に違う値になっていたので意図しないアドレスをしているはずだと思い、配列の要素数を指定してみたところ想定する動きになった。