阿里云轻量应用服务器WordPress系统增添自定义站点

前提

在完成服务器购买、绑定域名并成功解析、能使用域名成功访问WordPress模板网站。

如果出于一些原因想使用同一个服务器或同一个域名部分,可以通过把网页文件直接上传到服务器上来实现上线访问。把我的实现步骤记录一下。

1.设置root密码,使用SecureCRT工具登录服务器

设置root密码:

SecureCRT工具登录:

填写IP地址

用户名root,密码就是刚刚设置好的

连接上了

 2.安装rz/sz命令

root下执行命令:

yum install lrzsz -y

rz命令上传文件到服务器,sz filename命令下载文件到本地,其他参数可以–help自行查看。

在选项->会话选项->Xmode/Zmode下可以设置默认上传下载目录

3.WordPress目录结构

在轻量应用服务器控制台->应用详情->应用程序安装信息里有写WordPress文件位置

cd /home/www/htdocs
ls -l

查看目录结构

wp-admin就是后台文件,登录后台仪表盘的页面文件,php后台文件等等

wp-content包含网站所有内容,插件、主题和上传的图片等内容

wp-includes包括持有的所有文件和库,是必要的WordPress管理,编辑和JavaScript库,CSS和图像文件

把想要上上传的网站代码用rz命令上传到 /home/www/htdocs目录下即可

比如我上传了leah这个文件夹

即可以在域名后加上/leah直接访问了(leah文件夹内首页命名为index.html)

比如我的网站域名为c2h4.ink,访问c2h4.ink/leah即为index.html的页面

4.遇到的问题及解决

4.1 root无法登录

提示Permission denied (publickey,gssapi-keyex,gssapi-with-mic).

打开sshd_config配置文件

vim /etc/ssh/sshd_config

修改

RSAAuthentication yes
PubkeyAuthentication yes #这两项为打开公钥模式
AuthorizedKeysFile .ssh/authorized_keys #配置公钥记录文件
PasswordAuthentication yes #打开密码验证模式

即可

4.2 网站无法访问

中间我不知道我操作了什么,突然无法访问了,排查步骤如下:

登录服务器后

netstat -an | grep 80

发现Web应用是没有开启并正常监听

执行一下命令

/etc/init.d/apachectl start
/etc/init.d/php-fpm start
/etc/init.d/mysqld start

开启后正常访问

使用LEX(flex)和YACC(bison)

背景

这周在做编译原理实验,任务是对一门给定语法的语言(S语言)进行词法分析和语法分析。按照理论,词法分析需要构造识别单词的有限自动机,完成NFAtoDFA和DFA最小化,语法分析需要求解first集、follow集和select集,构造递归下降语法分析等等。听起来内容好多好难好麻烦有没有!!作为一个头发较多逻辑较差代码能力较差的专职bug生产者,可以预料到完成这些我要想多久写多久。。遂决定走另一条路,使用工具lex和yacc来自动生成分析C源码。

LEXYACC介绍

Lex(Lexxical Analyzar)和Yacc(Yet Another Compiler)分别是词法解析器和语法解析器,用目标语言的正则表达式编写Lex代码,经过flex编译可以生成词法分析的C代码,用目标语言的BNF编写Yacc代码,经过bison编译可以生成语法分析的C代码,将词法分析和语法分析的C代码一起编译即可生成目标语言的编译器。

Lex和Yacc原本是Unix/Linux系统下的工具,UnxUtils将他们移植到了 Windows平台。具体安装配置步骤可以参考:lex和yacc安装配置 网上教程很多,也可以自己去找,不多赘述。

值得一提的是,yacc生成的C代码使用的是自顶向下LR分析算法,所以写完S语言的lex和yacc代码之后,实验二(词法分析)、实验三(递归下降语法分析)、实验五(LR语法分析)就算是一起做完了(笑)。

环境和工具

  • Windows
  • lex和yacc
  • gcc编译器
  • PowerShell/cmd或IDE+ParserGenerator (推荐直接使用命令行编译,我没用IDE配置过)

Lex使用

一个基本的lex.l程序

%{

#include

/*第一部分*/

%}

/*第二部分*/

%%

/*第三部分*/

%%

/*第四部分*/

void main()

{

printf("The first Lex program.\n");

}

int yywrap(void)

{

return 1;

}

保存为lex.l文件

在保存文件目录下打开命令行

flex lex.l

会编译生成lex.yy.c文件

编译lex.yy.c

gcc lex.yy.c

会编译生成a.exe可执行文件

运行a.exe文件即可看到输出

Lex语法规则

lex代码被我分为四个部分

  • 第一部分 – 定义

包含在

%{/*第一部分*/%}

,这个部分用来发需要用到的头文件、全局变量、函数说明等,这一部分内容会全部一模一样的拷贝到lex.yy.x文件中。

  • 第二部分 – 正规定义

这部分可以为一些词法规则进行简化定义,方便使用。

如:

letter [A-Za-z]

之后就可以直接用letter代替正则式[A-Za-z]出现

  • 第三部分-词法规则

这部分为Lex模式匹配,也是lex代码的重点书写部分。列出词法分析器所需要匹配的正则表达式(或其在第二部分定义的简称),及其在匹配到该正规式时需要进行的动作。

如:

[ \t]+ {printf("whitespace\n");}

[\n]+ {printf("linebreak\n");}

"int" {printf("INT\n")};

"=" {printf("colon\n");}

{letter} {printf("ID\n");}

每一行一条规则,规则前半部分时正规式或简称,注意若是匹配字符串则需要用双引号包含,若使用第二部分定义的简称需要用{}包含。后半部分用空格和前半部分用空格隔开,用{}包含,编写匹配到了该词法是程序需要执行的步骤,完全遵照C语言语法,例子中是匹配成功输出相应提示信息。

  • 第四部分 – 辅助函数段

这一部分也是用C语言语法,内容也会全部原原本本地拷贝lex.yy.c函数中。在使用中我定义了

int yywrap()

的函数,这是为了兼容flex版本>2.5.4,除了定义该函数,也可以在文件首行写

%option noyywrap

,否则编译lex.yy.c时会出现

undefined reference to `yywrap'

的错误。具体可参考:Undefined Reference To yywrap – stackoverflow

提示:编译复制粘贴的lex代码可能出现迷之报错,如果死活找不到哪儿语法错了,那就重新手写一遍,不要问我是怎么知道的= =

Yacc使用

一个基本的yacc.y程序

%{

#include

/*第一部分*/

%}

/*第二部分*/

%token ID

%%

/*第三部分*/

definition: INT ID

| ID

;

%%

/*第四部分*/
int yyerror(char * msg)
{

printf("\nerror:%s\n",msg);

}

编译yacc.y文件

bison yacc.y

生成yacc.tab.c文件

Yacc语法

要生成最终的语法编译器,需要词法分析器的配合,所以yacc的语法结合lex程序一起分析。

  • 第一部分

与lex相同

  • 第二部分

说明语法规则中需要用到的所有终结符和定义算符优先级和结合性等。

具体如下:

%start //语法开始符

%token //终结符

%left //左结合性

%right //右结合性

%nonassoc //无结合性

%type //非终结符语义类型

%union //语义值类型说明

%start 后接的是上下文无关文法的开始符号,它是一个特殊的非终结符,所有的推导都从这个非终结符开始。如果不说明%start,yacc自动将语法规则部分(第三部分)中第一条语法规则左部的非终结符作为语法开始符。

%token所接的是终结符,也就是词法分析器中匹配的元素,我们首先要在lex.l中的词法匹配中返回终结符的名称,才能在yacc.y中使用这个非终结符。

举个例子

在lex.l第三部分中:

%%

[A-Za-z]+ {printf("ID\n");return (ID);}

%%

返回名称为ID的终结符

在yacc.y第二部分中:

%token ID

如果有多个非终结符,可以换行,也可以写在同一行

%token ID NUM
%token ID

%token NUM

%left %right %nonassoc后接需要定义优先级的算符,定义在越后排优先级越高,%nonassoc需要对应%prec使用,%prec使用在语法规则中。

举个例子

/*第二部分*/

%token ID

%left '+' '-'

%left '*'

%nonassoc UMINUS

%%

/*第三部分*/

term: '-' term %prec

| term '*' ID

| term '+' ID

| term '-' ID

;

%%

就可以定义’*’优先级大于’+’和’-‘,但首项可以带符号’-‘,首项的符号优先级大于因子的算符。

比如1-2*3的计算是1-(2*3),但-1*2的计算是(-1)*2而不是-(1*2)。

区分左结合性和右结合性

文法1:

term : term+factor

|factor

文法2:

term : factor+term

|factor

文法1中‘+’是左结合的,文法2中‘+’是右结合的。

文法1中term = ( term + factor1) + factor2是符合的,其中factor1和前一个+号结合,所以该运算符‘+’是左结合的

文法2中term = factor1 + ( factor2 + term)是符合的,其中factor2和后一个+号结合,所以该运算符‘+’是右结合的

除了算符可以定义优先级,我们也可以利用优先级来定义语法的关键字。

比如在S语言中,有var, const, if, while等关键字,它们同样也符合变量的词法定义{A-Za-z}({A-Za-z}|{0-9})*,在语法分析中就会被识别成变量而导致分析错误,但如果把这些关键字的优先级设置为高于变量,这样在语法分析中就会优先被识别为关键字。注意它们应该都是右结合性,原因参考上面写的优先级判别。

如:

%right ID
%right CONST VAR IF ELSE THEN WHILE DO BEGIN END
  • 第三部分

这部分写语言的BNF范式,冒号:的左边即BNF范式的左边,冒号右边即BNF范式的右边,多个推导用|分隔,最后要用分号;结尾。每项推导后面也可以用{}包含C代码,作为匹配到该条语法规则后想要程序进行的动作。

  • 第四部分

与lex相同

值得注意的是yacc自带的一个函数yyerror

int yyerror(char * msg)
{
printf("\nerror:%s\n",msg);
}

可以输出编译测试代码的错误信息。

但是要清醒一点,输出的是测试代码的错误,而不是yacc代码的错误,yacc是语言编译器的编译器,以c语言举例,它编译生成的是gcc,使用gcc编译用c语言写的测试代码,输出的是测试代码的错误信息而不是gcc编译器源码的错误。有段时间我一直测试输出parse error,其实是进行测试的代码段不符合语言的语法,我非常脑子不清楚地改了半天源码= =

测试代码可以用txt文件储存

int main()
{
extern FILE *yyin;
yyin = fopen("test.txt","r");
yyparse();
return 0;
}

在主函数中读取并分析

生成语法分析器

lex.l需要引用yacc.tab.h头文件,所以还要用bison生成yacc.tab.h头文件

yacc -d yacc.y

加参数-d会生成yacc.tab.h和yacc.tab.c文件

然后编译lex.l文件生成lex.yy.c文件

flex lex.l

编译lex.yy.c和yacc.tab.c文件

gcc lex.yy.c yacc.tab.c

默认生成的可执行文件是a.exe,这个可执行文件就是我们的语法编译器了。

解决文法冲突

在第一次写复杂如S语言的文法,难免会出现移进/归约冲突、归约/归约冲突,还可能会定义了无用规则等错误,这些错误bison都会在我们编译yacc.y时指出来

如:

提示有1个无用的非终结符,1个无用规则,1个移进/归约错误和11个归约/归约错误

我们可以通过生成yacc.output文件来找到具体是那些文法出了错误

bison -v yacc.y

在yacc.output文件中

Useless nonterminals:

loop_stmt

Terminals which are not used:

WHILE
DO
CASE

Useless rules:

#18 loop_stmt : WHILE condition DO stmt;

Conflict in state 42 between rule 31 and token '+' resolved as shift.
Conflict in state 42 between rule 31 and token '*' resolved as shift.
Conflict in state 65 between rule 17 and token ELSE resolved as shift.
Conflict in state 70 between rule 29 and token '+' resolved as shift.
Conflict in state 70 between rule 29 and token '*' resolved as shift.
Conflict in state 71 between rule 30 and token '+' resolved as reduce.
Conflict in state 71 between rule 30 and token '*' resolved as shift.
State 27 contains 1 shift/reduce conflict.
State 43 contains 11 reduce/reduce conflicts.

先检查无用的非终结符和无用的规则是否忘了在文法中使用,如果不是则要删除。

状态27存在移进/归约错误

state 27

term ; factor . '*' term (rule 34)
term ; factor . '/' term (rule 35)
unary ; factor . (rule 38)

'*' shift, and go to state 54
'/' shift, and go to state 55

'*' [reduce using rule 38 (unary)]
$default reduce using rule 38 (unary)

可以看到识别到’*’时可以移进也可以归约,需要对文法进行更改。

状态43存在移进归约/归约错误,查看同移进/归约,找到相应规则后进行修改。

附录

S语言的BNF表示

(1) <程序>→[<常量说明>][<变量说明>]<语句>
(2) <常量说明>→Const <常量定义>{,<常量定义>};
(3) <常量定义>→<标识符>=<无符号整数>
(4) <无符号整数>→<数字>{<数字>}
(5) <字母>→a|b|c| … |z
(6) <数字>→0|1|2| … |9
(7) <标识符>→<字母>{<字母>|<数字>}
(8) <变量说明>→Var <标识符>{,<标识符>};
(9) <语句>→<赋值语句>|<条件语句>|<当循环语句>|<复合语句>|ε
(10) <赋值语句>→<标识符>=<表达式>;
(11) <表达式>→[+|-]<项>{<加法运算符><项>}
(12) <项>→<因子>{<乘法运算符><因子>}
(13) <因子>→<标识符>|<无符号整数>|‘(’<表达式>‘)’
(14) <加法运算符>→+|-
(15) <乘法运算符>→* |/
(16) <条件语句>→if <条件> then <语句>| if <条件> then <语句> else
<语句>
(17) <条件>→<表达式><关系运算符><表达式>
(18) <关系运算符>→==|<=|<|>|>=|<>
(19) <当循环语句>→while <条件> do <语句>
(20) <复合语句>→begin <语句>{;<语句>} end

注:产生式中<、>括起的部分表示一个非终结符号,[、]括起的部分表示可
选项,{、}括起的部分表示可重复,符号 | 表示“或”。

示例代码

一个简单文法的lex.l和yacc.y代码

文法:

E→E+T | T

T→T*F |F

F→( E ) | i

lex.l :

%option noyywrap
%{
#include
#include
#include
#include
#include "yacc.tab.h"
%}

delim [ \t\n]
ws {delim}+

%%
{ws} {}
"i" {printf("i ");return('i');}
"+" {printf("+ ");return('+');}
"*" {printf("* ");return('*');}
"(" {printf("( ");return('(');}
")" {printf(") ");return(')');}
%%

yacc.y :

%{
#include

%}

%token '(' ')' 'i' '+' '*'

%%
E: T ES {printf("E-&gt;T ES\n");}
;
ES: {printf("ES-&gt;#\n");}
| '+' T ES {printf("ES-&gt;+ T ES\n");}
;
T: F TS {printf("T-&gt;F TS\n");}
;
TS: {printf("TS-&gt;#\n");}
| '*' F TS {printf("TS-&gt;* F TS\n");}
;
F: '(' E ')' {printf("F-.( E )\n");}
|'i' {printf("F-&gt;i\n");}
;
%%
int flag;
int main()
{
flag=0;
extern FILE *yyin;
yyin = fopen("test.txt","r");
yyparse();
if(flag==1)
printf("error!");
else printf("accepcted!");
return 0;
}
int yyerror(char * msg)
{
printf("\nerror:%s\n",msg);
flag=1;
}

webpack入门

内容概述

尝试解释webpack及其依赖平台相关概念,仅仅讨论在管理前端代码使之工程化的场景下webpack的使用和常用方法。

梳理webpack使用方法,记录在参考教程 菜鸟教程-webpack学习webpack遇到的一些问题和踩过的坑(主要由于webpack和npm版本与网上教程不同造成,webpack不能向前兼容无比坑爹..)。

概念

node.js、npmwebpack

node.js是一个基于 Chrome V8 引擎的 JavaScript 运行环境,是运行在服务器端的JavaScript,可以摆脱浏览器宿主环境,解析和执行js代码,直接进行底层系统调用,并且内置提供了HTTP服务器相关的大量API。

npm随node.js一起安装,是一个包管理工具,用来解决node.js代码部署问题。

webpack是前端工程化打包工具,可以处理功能丰富的大型网站所拥有的复杂的js代码、css代码等,解析它们的依赖关系,转换和打包成模块使用,实现自动化管理前端代码。

功能

从功能上来说,node.js可以开启一个Web服务,给浏览器提供数据去展示,并且接收浏览器提交过来的用户产生的数据,存储到数据库中,方便后面使用。

我们在代码中使用node.js打包好的模块(模块指具有相同功能的代码的集合),然后需要通过npm工具为我们的工程导入模块以便代码在本地调用,npm工具被包装成一个类似命令行的模式提供给开发者使用。除了调用node.js已有的模块,我们还可以在npm上发布自己的模块和调用其他人所发布的模块。

webpack则是运行在npm上的一个任务执行者,可以看作npm为开发者提供的一个功能,和webpack实现类似功能的主流构建工具还有grunt,gulp,browerity等,其中webpack非常适用于管理前端开发代码,它将一切文件模块化,可以方便地帮助我们简化前端复杂繁多的js文件、css文件的调用,使我们的web应用工程化。

有用的资料:webpack官方网站

webpack使用

前提:本地环境支持node.js

全局安装webpack

npm install webpack -g //全局安装webpack

//--global为全局安装,可简写为-g

到了 webpack4,命令行相关的内容都移到 webpack-cli,所以还需要安装 webpack-cli

npm install webpack-cli -g

创建项目

mkdir app //项目文件夹

在项目路径下

npm init --yes//创建package.json文件

package.json 是包描述文件,存储着包的信息(包名、版本、项目的依赖项),最好每个项目都要有个 package.json 文件,就像产品说明书。此文件可自己普通文本改名的方式创建,但一般是 npm 命令创建。运行npm init命令会以向导的方式填写包的信息,不想填的话可回车略过。–yes是快速创建,可以跳过信息的填写直接创建,之后想改可以直接到package.json文件中修改。

局部安装webpack

npm install webpack --save-dev

为什么全局安装了还要局部安装:npm全局安装和局部文件安装区别

关于–save和-dev可参考:npm –save和–save-dev 傻傻分不清

接下来分别示例打包js文件和非js文件(css)两种使用场景来说明webpack使用的基本步骤

JS文件

在app目录下创建test.js文件并保存

document.write("it works!");

打包为bundle.js

webpack test.js bundle.js

注意,如果是高版本的npm,比如我的是5.6.0,需要加-o

webpack test.js -o bundle.js

试一下效果:

创建index.html文件

&nbsp;

&nbsp;

<script type="text/javascript" src="bundle.js" charset="utf-8"></script>

浏览器打开index.html

CSS文件

创建style.css文件

body {
background: pink;
}

修改test.js文件

require("!style-loader!css-loader!./style.css");//引用style.css文件
document.write(require("it works!");

Webpack 本身只能处理 JavaScript 模块,如果要处理其他类型的文件,就需要使用 loader 进行转换。

所以如果我们需要在应用中添加 css 文件,就需要使用到 css-loader 和 style-loader,他们做两件不同的事情,css-loader 会遍历 CSS 文件,然后找到 url() 表达式然后处理他们,style-loader 会把原来的 CSS 代码插入页面中的一个 style 标签中。

为了使用style-loadercss-loader,同样我们也需要全局安装style-loadercss-loader

npm install style-loader css-loader -g

再局部安装

npm install style-loader css-loader --save-dev

打包

webpack test.js -o bundle.js

浏览器打开index.html查看效果

配置 webpack.config.js

如果我们需要打包多个文件,那么在命令行下一个个输入文件名会比较麻烦,所以我们一般通过配置webpack.config.js文件,然后就可以直接使用webpack命令来打包所有文件。

创建webpack.config.js文件

module.exports = {
//指定入口文件
entry: {
entry: './test.js'
},
//指定出口文件
output: {
path: __dirname,
filename: 'test.js'
},
//模块,指定加载器,可配置各种加载器,test里指定加载文件的格式(.css),loader里指定加载器名称

module:{

rules:[{test:/\.css\$/}, loader:"style-loader!css-loader"]

}

注意,webpack2之后将loaders改为了rules,如果还是写成

loaders:[{test:/\.css\$/}, loader:"style-loader!css-loader"]

将报错

在指定出口文件中,

path:__dirname

path指生成的出口文件的统一路径,__dirname表示当前目录。

如果需要生成的文件在别的目录下,可以在文件开始引入模块path
const path=require('path');
然后就可以使用path.join()方法,这种方法将多个参数字符串合并成一个路径字符串
path: path.join(__dirname,'dist')</div>
<div>//出口文件会在/app/dist文件夹下,如果没有dist文件夹会自动创建
或者path.resolve()方法,这种方法以程序为根目录,作为起点,根据参数解析出一个绝对路径
path: path.resolve(__dirname,'./dist')
关于它们的区别:path.join()和path.resolve()
这篇文章仅仅用了最简单的代码来示例webpack的基本使用,事实上webpack还有许多其他高级特性和适用于复杂情况的使用方法。要准备开始真正地改造之前写的网站前端代码,然后再记录吧…
参考资料: